diff --git a/AIGrammar/AIGrammarApp.swift b/AIGrammar/AIGrammarApp.swift index 2388f8e..a5ce7f5 100644 --- a/AIGrammar/AIGrammarApp.swift +++ b/AIGrammar/AIGrammarApp.swift @@ -21,7 +21,8 @@ struct AIGrammarApp: App { setupLogging() _ = InitApp.shared - // firebase + // firebase 默认info级别,这里修改成线上级别。 + FirebaseConfiguration.shared.setLoggerLevel(.error) FirebaseApp.configure() Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(true) diff --git a/AIGrammar/Assets.xcassets/AppIcon.appiconset.zip b/AIGrammar/Assets.xcassets/AppIcon.appiconset.zip new file mode 100644 index 0000000..45f36bd Binary files /dev/null and b/AIGrammar/Assets.xcassets/AppIcon.appiconset.zip differ diff --git a/Pods/Firebase/CoreOnly/Sources/Firebase.h b/Pods/Firebase/CoreOnly/Sources/Firebase.h new file mode 100755 index 0000000..37d5f9e --- /dev/null +++ b/Pods/Firebase/CoreOnly/Sources/Firebase.h @@ -0,0 +1,88 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#if !defined(__has_include) + #error "Firebase.h won't import anything if your compiler doesn't support __has_include. Please \ + import the headers individually." +#else + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #if __has_include("FirebaseAuth-umbrella.h") + #if __has_include() + #import + #endif + #import + #import + #endif + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseFunctions-umbrella.h") + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include() + #import + #endif + + #if __has_include("FirebaseStorage-umbrella.h") + #import + #endif + +#endif // defined(__has_include) diff --git a/Pods/Firebase/CoreOnly/Sources/module.modulemap b/Pods/Firebase/CoreOnly/Sources/module.modulemap new file mode 100755 index 0000000..3685b54 --- /dev/null +++ b/Pods/Firebase/CoreOnly/Sources/module.modulemap @@ -0,0 +1,4 @@ +module Firebase { + export * + header "Firebase.h" +} \ No newline at end of file diff --git a/Pods/Firebase/LICENSE b/Pods/Firebase/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/Firebase/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/Firebase/README.md b/Pods/Firebase/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/Firebase/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h new file mode 100644 index 0000000..54e10b0 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h @@ -0,0 +1,79 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "FirebaseABTesting/Sources/Private/ABTExperimentPayload.h" + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRLifecycleEvents; + +/// This class dynamically calls Firebase Analytics API to collect or update experiments +/// information. +/// The experiment in Firebase Analytics is named as conditional user property (CUP) object defined +/// in FIRAConditionalUserProperty.h. +@interface ABTConditionalUserPropertyController : NSObject + +/// Returns the ABTConditionalUserPropertyController singleton. ++ (instancetype)sharedInstanceWithAnalytics:(id _Nullable)analytics; + +/// Returns the list of currently set experiments from Firebase Analytics for the provided origin. +- (NSArray *)experimentsWithOrigin:(NSString *)origin; + +/// Returns the experiment ID from Firebase Analytics given an experiment object. Returns empty +/// string if can't find Firebase Analytics service. +- (NSString *)experimentIDOfExperiment:(nullable id)experiment; + +/// Returns the variant ID from Firebase Analytics given an experiment object. Returns empty string +/// if can't find Firebase Analytics service. +- (NSString *)variantIDOfExperiment:(nullable id)experiment; + +/// Returns whether the experiment is the same as the one in the provided payload. +- (BOOL)isExperiment:(id)experiment theSameAsPayload:(ABTExperimentPayload *)payload; + +/// Clears the experiment in Firebase Analytics. +/// @param experimentID Experiment ID to clear. +/// @param variantID Variant ID to clear. +/// @param origin Impacted originating service, it is defined at Firebase Analytics +/// FIREventOrigins.h. +/// @param payload Payload to overwrite event name in events. DO NOT use payload's experiment +/// ID and variant ID as the experiment to clear. +/// @param events Events name for clearing the experiment. +- (void)clearExperiment:(NSString *)experimentID + variantID:(NSString *)variantID + withOrigin:(NSString *)origin + payload:(nullable ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events; + +/// Sets the experiment in Firebase Analytics. +/// @param origin Impacted originating service, it is defined at Firebase Analytics +/// FIREventOrigins.h. +/// @param payload Payload to overwrite event name in events. DO NOT use payload's experiment +/// ID and variant ID as the experiment to set. +/// @param events Events name for setting the experiment. +/// @param policy Overflow policy when the number of experiments is over the limit. +- (void)setExperimentWithOrigin:(NSString *)origin + payload:(ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events + policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy; + +/** + * Unavailable. Use sharedInstanceWithAnalytics: instead. + */ +- (instancetype)init __attribute__((unavailable("Use +sharedInstanceWithAnalytics: instead."))); +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.m b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.m new file mode 100644 index 0000000..e555826 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConditionalUserPropertyController.m @@ -0,0 +1,288 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h" + +#import "FirebaseABTesting/Sources/ABTConstants.h" +#import "FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +@implementation ABTConditionalUserPropertyController { + dispatch_queue_t _analyticOperationQueue; + id _Nullable _analytics; +} + +/// Returns the ABTConditionalUserPropertyController singleton. ++ (instancetype)sharedInstanceWithAnalytics:(id _Nullable)analytics { + static ABTConditionalUserPropertyController *sharedInstance = nil; + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + sharedInstance = [[ABTConditionalUserPropertyController alloc] initWithAnalytics:analytics]; + }); + return sharedInstance; +} + +- (instancetype)initWithAnalytics:(id _Nullable)analytics { + self = [super init]; + if (self) { + _analyticOperationQueue = + dispatch_queue_create("com.google.FirebaseABTesting.analytics", DISPATCH_QUEUE_SERIAL); + _analytics = analytics; + } + return self; +} + +#pragma mark - experiments proxy methods on Firebase Analytics + +- (NSArray *)experimentsWithOrigin:(NSString *)origin { + return [_analytics conditionalUserProperties:origin propertyNamePrefix:@""]; +} + +- (void)clearExperiment:(NSString *)experimentID + variantID:(NSString *)variantID + withOrigin:(NSString *)origin + payload:(ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events { + // Payload always overwrite event names. + NSString *clearExperimentEventName = events.clearExperimentEventName; + if (payload && payload.clearEventToLog && payload.clearEventToLog.length) { + clearExperimentEventName = payload.clearEventToLog; + } + + [_analytics clearConditionalUserProperty:experimentID + forOrigin:origin + clearEventName:clearExperimentEventName + clearEventParameters:@{experimentID : variantID}]; + + FIRLogDebug(kFIRLoggerABTesting, @"I-ABT000015", @"Clear Experiment ID %@, variant ID %@.", + experimentID, variantID); +} + +- (void)setExperimentWithOrigin:(NSString *)origin + payload:(ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events + policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy { + NSInteger maxNumOfExperiments = [self maxNumberOfExperimentsOfOrigin:origin]; + if (maxNumOfExperiments < 0) { + return; + } + + // Clear experiments if overflow + NSArray *experiments = [self experimentsWithOrigin:origin]; + if (!experiments) { + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000003", + @"Failed to get conditional user properties from Firebase Analytics."); + return; + } + + if (payload.experimentId == nil) { + // When doing experiment test on devices, the payload could be empty. Returning here to prevent + // app crash. + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000020", @"Experiment Id in payload is empty."); + return; + } + + if (maxNumOfExperiments <= experiments.count) { + ABTExperimentPayloadExperimentOverflowPolicy overflowPolicy = + [self overflowPolicyWithPayload:payload originalPolicy:policy]; + id experimentToClear = experiments.firstObject; + if (overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest && + experimentToClear) { + NSString *expID = [self experimentIDOfExperiment:experimentToClear]; + NSString *varID = [self variantIDOfExperiment:experimentToClear]; + + [self clearExperiment:expID variantID:varID withOrigin:origin payload:payload events:events]; + FIRLogDebug(kFIRLoggerABTesting, @"I-ABT000016", + @"Clear experiment ID %@ variant ID %@ due to " + @"overflow policy.", + expID, varID); + + } else { + FIRLogDebug(kFIRLoggerABTesting, @"I-ABT000017", + @"Experiment ID %@ variant ID %@ won't be set due to " + @"overflow policy.", + payload.experimentId, payload.variantId); + + return; + } + } + + // Clear experiment if other variant ID exists. + NSString *experimentID = payload.experimentId; + NSString *variantID = payload.variantId; + for (id experiment in experiments) { + NSString *expID = [self experimentIDOfExperiment:experiment]; + NSString *varID = [self variantIDOfExperiment:experiment]; + if ([expID isEqualToString:experimentID] && ![varID isEqualToString:variantID]) { + FIRLogDebug(kFIRLoggerABTesting, @"I-ABT000018", + @"Clear experiment ID %@ with variant ID %@ because " + @"only one variant ID can be existed " + @"at any time.", + expID, varID); + [self clearExperiment:expID variantID:varID withOrigin:origin payload:payload events:events]; + } + } + + // Set experiment + NSDictionary *experiment = [self createExperimentFromOrigin:origin + payload:payload + events:events]; + + [_analytics setConditionalUserProperty:experiment]; + + FIRLogDebug(kFIRLoggerABTesting, @"I-ABT000019", + @"Set conditional user property, experiment ID %@ with " + @"variant ID %@ triggered event %@.", + experimentID, variantID, payload.triggerEvent); + + // Log setEvent (experiment lifecycle event to be set when an experiment is set) + [self logEventWithOrigin:origin payload:payload events:events]; +} + +- (NSMutableDictionary *)createExperimentFromOrigin:(NSString *)origin + payload:(ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events { + NSMutableDictionary *experiment = [[NSMutableDictionary alloc] init]; + NSString *experimentID = payload.experimentId; + NSString *variantID = payload.variantId; + + NSDictionary *eventParams = @{experimentID : variantID}; + + [experiment setValue:origin forKey:kABTExperimentDictionaryOriginKey]; + + NSTimeInterval creationTimestamp = (double)(payload.experimentStartTimeMillis / ABT_MSEC_PER_SEC); + [experiment setValue:@(creationTimestamp) forKey:kABTExperimentDictionaryCreationTimestampKey]; + [experiment setValue:experimentID forKey:kABTExperimentDictionaryExperimentIDKey]; + [experiment setValue:variantID forKey:kABTExperimentDictionaryVariantIDKey]; + + // For the experiment to be immediately activated/triggered, its trigger event must be null. + // Double check if payload's trigger event is empty string, it must be set to null to trigger. + if (payload && payload.triggerEvent && payload.triggerEvent.length) { + [experiment setValue:payload.triggerEvent forKey:kABTExperimentDictionaryTriggeredEventNameKey]; + } else { + [experiment setValue:nil forKey:kABTExperimentDictionaryTriggeredEventNameKey]; + } + + // Set timeout event name and params. + NSString *timeoutEventName = events.timeoutExperimentEventName; + if (payload && payload.timeoutEventToLog && payload.timeoutEventToLog.length) { + timeoutEventName = payload.timeoutEventToLog; + } + NSDictionary *timeoutEvent = [self eventDictionaryWithOrigin:origin + eventName:timeoutEventName + params:eventParams]; + [experiment setValue:timeoutEvent forKey:kABTExperimentDictionaryTimedOutEventKey]; + + // Set trigger timeout information on how long to wait for trigger event. + NSTimeInterval triggerTimeout = (double)(payload.triggerTimeoutMillis / ABT_MSEC_PER_SEC); + [experiment setValue:@(triggerTimeout) forKey:kABTExperimentDictionaryTriggerTimeoutKey]; + + // Set activate event name and params. + NSString *activateEventName = events.activateExperimentEventName; + if (payload && payload.activateEventToLog && payload.activateEventToLog.length) { + activateEventName = payload.activateEventToLog; + } + NSDictionary *triggeredEvent = [self eventDictionaryWithOrigin:origin + eventName:activateEventName + params:eventParams]; + [experiment setValue:triggeredEvent forKey:kABTExperimentDictionaryTriggeredEventKey]; + + // Set time to live information for how long the experiment lasts. + NSTimeInterval timeToLive = (double)(payload.timeToLiveMillis / ABT_MSEC_PER_SEC); + [experiment setValue:@(timeToLive) forKey:kABTExperimentDictionaryTimeToLiveKey]; + + // Set expired event name and params. + NSString *expiredEventName = events.expireExperimentEventName; + if (payload && payload.ttlExpiryEventToLog && payload.ttlExpiryEventToLog.length) { + expiredEventName = payload.ttlExpiryEventToLog; + } + NSDictionary *expiredEvent = [self eventDictionaryWithOrigin:origin + eventName:expiredEventName + params:eventParams]; + [experiment setValue:expiredEvent forKey:kABTExperimentDictionaryExpiredEventKey]; + return experiment; +} + +- (NSDictionary *) + eventDictionaryWithOrigin:(nonnull NSString *)origin + eventName:(nonnull NSString *)eventName + params:(nonnull NSDictionary *)params { + return @{ + kABTEventDictionaryOriginKey : origin, + kABTEventDictionaryNameKey : eventName, + kABTEventDictionaryTimestampKey : @([NSDate date].timeIntervalSince1970), + kABTEventDictionaryParametersKey : params + }; +} + +#pragma mark - experiment properties +- (NSString *)experimentIDOfExperiment:(id)experiment { + if (!experiment) { + return @""; + } + return [experiment valueForKey:kABTExperimentDictionaryExperimentIDKey]; +} + +- (NSString *)variantIDOfExperiment:(id)experiment { + if (!experiment) { + return @""; + } + return [experiment valueForKey:kABTExperimentDictionaryVariantIDKey]; +} + +- (NSInteger)maxNumberOfExperimentsOfOrigin:(NSString *)origin { + if (!_analytics) { + return 0; + } + return [_analytics maxUserProperties:origin]; +} + +#pragma mark - analytics internal methods + +- (void)logEventWithOrigin:(NSString *)origin + payload:(ABTExperimentPayload *)payload + events:(FIRLifecycleEvents *)events { + NSString *setExperimentEventName = events.setExperimentEventName; + if (payload && payload.setEventToLog && payload.setEventToLog.length) { + setExperimentEventName = payload.setEventToLog; + } + NSDictionary *params; + params = payload.experimentId ? @{payload.experimentId : payload.variantId} : @{}; + [_analytics logEventWithOrigin:origin name:setExperimentEventName parameters:params]; +} + +#pragma mark - helper + +- (BOOL)isExperiment:(id)experiment theSameAsPayload:(ABTExperimentPayload *)payload { + NSString *experimentID = [self experimentIDOfExperiment:experiment]; + NSString *variantID = [self variantIDOfExperiment:experiment]; + return [experimentID isEqualToString:payload.experimentId] && + [variantID isEqualToString:payload.variantId]; +} + +- (ABTExperimentPayloadExperimentOverflowPolicy) + overflowPolicyWithPayload:(ABTExperimentPayload *)payload + originalPolicy:(ABTExperimentPayloadExperimentOverflowPolicy)originalPolicy { + if ([payload overflowPolicyIsValid]) { + return payload.overflowPolicy; + } + if (originalPolicy == ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest || + originalPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest) { + return originalPolicy; + } + return ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest; +} + +@end diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConstants.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConstants.h new file mode 100644 index 0000000..4edca5e --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTConstants.h @@ -0,0 +1,50 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "FirebaseCore/Extension/FIRLogger.h" + +#define ABT_MSEC_PER_SEC 1000ull + +#pragma mark - Keys for experiment dictionaries. + +static NSString *const kABTExperimentDictionaryCreationTimestampKey = @"creationTimestamp"; +static NSString *const kABTExperimentDictionaryExperimentIDKey = @"name"; +static NSString *const kABTExperimentDictionaryExpiredEventKey = @"expiredEvent"; +static NSString *const kABTExperimentDictionaryOriginKey = @"origin"; +static NSString *const kABTExperimentDictionaryTimedOutEventKey = @"timedOutEvent"; +static NSString *const kABTExperimentDictionaryTimeToLiveKey = @"timeToLive"; +static NSString *const kABTExperimentDictionaryTriggeredEventKey = @"triggeredEvent"; +static NSString *const kABTExperimentDictionaryTriggeredEventNameKey = @"triggerEventName"; +static NSString *const kABTExperimentDictionaryTriggerTimeoutKey = @"triggerTimeout"; +static NSString *const kABTExperimentDictionaryVariantIDKey = @"value"; + +#pragma mark - Keys for event dictionaries. + +static NSString *const kABTEventDictionaryNameKey = @"name"; +static NSString *const kABTEventDictionaryOriginKey = @"origin"; +static NSString *const kABTEventDictionaryParametersKey = @"parameters"; +static NSString *const kABTEventDictionaryTimestampKey = @"timestamp"; + +#pragma mark - Errors + +static NSString *const kABTErrorDomain = @"com.google.abtesting"; + +typedef NS_ENUM(NSUInteger, ABTInternalErrorCode) { + kABTInternalErrorFailedToFetchConditionalUserProperties = 1 +}; + +#pragma mark - Logger Service String + +extern FIRLoggerService kFIRLoggerABTesting; diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTExperimentPayload.m b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTExperimentPayload.m new file mode 100644 index 0000000..6bc2aaa --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/ABTExperimentPayload.m @@ -0,0 +1,151 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseABTesting/Sources/Private/ABTExperimentPayload.h" + +static NSString *const kExperimentPayloadKeyExperimentID = @"experimentId"; +static NSString *const kExperimentPayloadKeyVariantID = @"variantId"; + +// Start time can either be a date string or integer (milliseconds since 1970). +static NSString *const kExperimentPayloadKeyExperimentStartTime = @"experimentStartTime"; +static NSString *const kExperimentPayloadKeyExperimentStartTimeMillis = + @"experimentStartTimeMillis"; +static NSString *const kExperimentPayloadKeyTriggerEvent = @"triggerEvent"; +static NSString *const kExperimentPayloadKeyTriggerTimeoutMillis = @"triggerTimeoutMillis"; +static NSString *const kExperimentPayloadKeyTimeToLiveMillis = @"timeToLiveMillis"; +static NSString *const kExperimentPayloadKeySetEventToLog = @"setEventToLog"; +static NSString *const kExperimentPayloadKeyActivateEventToLog = @"activateEventToLog"; +static NSString *const kExperimentPayloadKeyClearEventToLog = @"clearEventToLog"; +static NSString *const kExperimentPayloadKeyTimeoutEventToLog = @"timeoutEventToLog"; +static NSString *const kExperimentPayloadKeyTTLExpiryEventToLog = @"ttlExpiryEventToLog"; + +static NSString *const kExperimentPayloadKeyOverflowPolicy = @"overflowPolicy"; +static NSString *const kExperimentPayloadValueDiscardOldestOverflowPolicy = @"DISCARD_OLDEST"; +static NSString *const kExperimentPayloadValueIgnoreNewestOverflowPolicy = @"IGNORE_NEWEST"; + +static NSString *const kExperimentPayloadKeyOngoingExperiments = @"ongoingExperiments"; + +@implementation ABTExperimentLite + +- (instancetype)initWithExperimentId:(NSString *)experimentId { + if (self = [super init]) { + _experimentId = experimentId; + } + return self; +} + +@end + +@implementation ABTExperimentPayload + ++ (NSDateFormatter *)experimentStartTimeFormatter { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; + [dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + // Locale needs to be hardcoded. See + // https://developer.apple.com/library/ios/#qa/qa1480/_index.html for more details. + [dateFormatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]]; + [dateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; + return dateFormatter; +} + ++ (nullable instancetype)parseFromData:(NSData *)data { + NSError *error; + NSDictionary *experimentDictionary = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingAllowFragments + error:&error]; + if (error != nil) { + return nil; + } else { + return [[ABTExperimentPayload alloc] initWithDictionary:experimentDictionary]; + } +} + +- (instancetype)initWithDictionary:(NSDictionary *)dictionary { + if (self = [super init]) { + _experimentId = dictionary[kExperimentPayloadKeyExperimentID]; + _variantId = dictionary[kExperimentPayloadKeyVariantID]; + _triggerEvent = dictionary[kExperimentPayloadKeyTriggerEvent]; + _setEventToLog = dictionary[kExperimentPayloadKeySetEventToLog]; + _activateEventToLog = dictionary[kExperimentPayloadKeyActivateEventToLog]; + _clearEventToLog = dictionary[kExperimentPayloadKeyClearEventToLog]; + _timeoutEventToLog = dictionary[kExperimentPayloadKeyTimeoutEventToLog]; + _ttlExpiryEventToLog = dictionary[kExperimentPayloadKeyTTLExpiryEventToLog]; + + // Experiment start time can either be in the form of a date string or milliseconds since 1970. + if (dictionary[kExperimentPayloadKeyExperimentStartTime]) { + // Convert from date string. + NSDate *experimentStartTime = [[[self class] experimentStartTimeFormatter] + dateFromString:dictionary[kExperimentPayloadKeyExperimentStartTime]]; + _experimentStartTimeMillis = + [@([experimentStartTime timeIntervalSince1970] * 1000) longLongValue]; + } else if (dictionary[kExperimentPayloadKeyExperimentStartTimeMillis]) { + // Simply store milliseconds. + _experimentStartTimeMillis = + [dictionary[kExperimentPayloadKeyExperimentStartTimeMillis] longLongValue]; + ; + } + + _triggerTimeoutMillis = [dictionary[kExperimentPayloadKeyTriggerTimeoutMillis] longLongValue]; + _timeToLiveMillis = [dictionary[kExperimentPayloadKeyTimeToLiveMillis] longLongValue]; + + // Overflow policy can be an integer, or string e.g. "DISCARD_OLDEST" or "IGNORE_NEWEST". + if ([dictionary[kExperimentPayloadKeyOverflowPolicy] isKindOfClass:[NSString class]]) { + // If it's a string, pick against the preset string values. + NSString *policy = dictionary[kExperimentPayloadKeyOverflowPolicy]; + if ([policy isEqualToString:kExperimentPayloadValueDiscardOldestOverflowPolicy]) { + _overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest; + } else if ([policy isEqualToString:kExperimentPayloadValueIgnoreNewestOverflowPolicy]) { + _overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest; + } else { + _overflowPolicy = ABTExperimentPayloadExperimentOverflowPolicyUnrecognizedValue; + } + } else { + _overflowPolicy = [dictionary[kExperimentPayloadKeyOverflowPolicy] intValue]; + } + + NSMutableArray *ongoingExperiments = [[NSMutableArray alloc] init]; + + NSArray *> *ongoingExperimentsArray = + dictionary[kExperimentPayloadKeyOngoingExperiments]; + + for (NSDictionary *experimentDictionary in ongoingExperimentsArray) { + NSString *experimentId = experimentDictionary[kExperimentPayloadKeyExperimentID]; + if (experimentId) { + ABTExperimentLite *liteExperiment = + [[ABTExperimentLite alloc] initWithExperimentId:experimentId]; + [ongoingExperiments addObject:liteExperiment]; + } + } + + _ongoingExperiments = [ongoingExperiments copy]; + } + return self; +} + +- (void)clearTriggerEvent { + _triggerEvent = nil; +} + +- (BOOL)overflowPolicyIsValid { + return self.overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest || + self.overflowPolicy == ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest; +} + +- (void)setOverflowPolicy:(ABTExperimentPayloadExperimentOverflowPolicy)overflowPolicy { + _overflowPolicy = overflowPolicy; +} + +@end diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRExperimentController.m b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRExperimentController.m new file mode 100644 index 0000000..4dd3432 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRExperimentController.m @@ -0,0 +1,310 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRExperimentController.h" + +#import "FirebaseABTesting/Sources/ABTConditionalUserPropertyController.h" +#import "FirebaseABTesting/Sources/ABTConstants.h" +#import "FirebaseABTesting/Sources/Private/ABTExperimentPayload.h" +#import "FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +/// Logger Service String. +FIRLoggerService kFIRLoggerABTesting = @"[FirebaseABTesting]"; + +/// Default experiment overflow policy. +const ABTExperimentPayloadExperimentOverflowPolicy FIRDefaultExperimentOverflowPolicy = + ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest; + +/// Deserialize the experiment payloads. +ABTExperimentPayload *ABTDeserializeExperimentPayload(NSData *payload) { + // Verify that we have a JSON object. + NSError *error; + id JSONObject = [NSJSONSerialization JSONObjectWithData:payload options:kNilOptions error:&error]; + if (JSONObject == nil) { + FIRLogError(kFIRLoggerABTesting, @"I-ABT000001", @"Failed to parse experiment payload: %@", + error.debugDescription); + } + return [ABTExperimentPayload parseFromData:payload]; +} + +/// Returns a list of experiments to be set given the payloads and current list of experiments from +/// Firebase Analytics. If an experiment is in payloads but not in experiments, it should be set to +/// Firebase Analytics. +NSArray *ABTExperimentsToSetFromPayloads( + NSArray *payloads, + NSArray *> *experiments, + id _Nullable analytics) { + NSArray *payloadsCopy = [payloads copy]; + NSArray *experimentsCopy = [experiments copy]; + NSMutableArray *experimentsToSet = [[NSMutableArray alloc] init]; + ABTConditionalUserPropertyController *controller = + [ABTConditionalUserPropertyController sharedInstanceWithAnalytics:analytics]; + + // Check if the experiment is in payloads but not in experiments. + for (NSData *payload in payloadsCopy) { + ABTExperimentPayload *experimentPayload = ABTDeserializeExperimentPayload(payload); + if (!experimentPayload) { + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000002", + @"Either payload is not set or it cannot be deserialized."); + continue; + } + + BOOL isExperimentSet = NO; + for (id experiment in experimentsCopy) { + if ([controller isExperiment:experiment theSameAsPayload:experimentPayload]) { + isExperimentSet = YES; + break; + } + } + + if (!isExperimentSet) { + [experimentsToSet addObject:experimentPayload]; + } + } + return [experimentsToSet copy]; +} + +/// Returns a list of experiments to be cleared given the payloads and current list of +/// experiments from Firebase Analytics. If an experiment is in experiments but not in payloads, it +/// should be cleared in Firebase Analytics. +NSArray *ABTExperimentsToClearFromPayloads( + NSArray *payloads, + NSArray *> *experiments, + id _Nullable analytics) { + NSMutableArray *experimentsToClear = [[NSMutableArray alloc] init]; + ABTConditionalUserPropertyController *controller = + [ABTConditionalUserPropertyController sharedInstanceWithAnalytics:analytics]; + + // Check if the experiment is in experiments but not payloads. + for (id experiment in [experiments copy]) { + BOOL doesExperimentNoLongerExist = YES; + for (NSData *payload in [payloads copy]) { + ABTExperimentPayload *experimentPayload = ABTDeserializeExperimentPayload(payload); + if (!experimentPayload) { + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000002", + @"Either payload is not set or it cannot be deserialized."); + continue; + } + + if ([controller isExperiment:experiment theSameAsPayload:experimentPayload]) { + doesExperimentNoLongerExist = NO; + } + } + if (doesExperimentNoLongerExist) { + [experimentsToClear addObject:experiment]; + } + } + return experimentsToClear; +} + +// ABT doesn't provide any functionality to other components, +// so it provides a private, empty protocol that it conforms to and use it for registration. + +@protocol FIRABTInstanceProvider +@end + +@interface FIRExperimentController () +@property(nonatomic, readwrite, strong) id _Nullable analytics; +@end + +@implementation FIRExperimentController + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-abt"]; +} + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + // Ensure it's cached so it returns the same instance every time ABTesting is called. + *isCacheable = YES; + id analytics = FIR_COMPONENT(FIRAnalyticsInterop, container); + return [[FIRExperimentController alloc] initWithAnalytics:analytics]; + }; + FIRComponent *abtProvider = [FIRComponent componentWithProtocol:@protocol(FIRABTInstanceProvider) + instantiationTiming:FIRInstantiationTimingLazy + creationBlock:creationBlock]; + + return @[ abtProvider ]; +} + +- (instancetype)initWithAnalytics:(nullable id)analytics { + self = [super init]; + if (self != nil) { + _analytics = analytics; + } + return self; +} + ++ (FIRExperimentController *)sharedInstance { + FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here. + id instance = FIR_COMPONENT(FIRABTInstanceProvider, defaultApp.container); + + // We know the instance coming from the container is a FIRExperimentController instance, cast it. + return (FIRExperimentController *)instance; +} + +- (void)updateExperimentsWithServiceOrigin:(NSString *)origin + events:(FIRLifecycleEvents *)events + policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy + lastStartTime:(NSTimeInterval)lastStartTime + payloads:(NSArray *)payloads + completionHandler: + (nullable void (^)(NSError *_Nullable error))completionHandler { + FIRExperimentController *__weak weakSelf = self; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + FIRExperimentController *strongSelf = weakSelf; + [strongSelf updateExperimentConditionalUserPropertiesWithServiceOrigin:origin + events:events + policy:policy + lastStartTime:lastStartTime + payloads:payloads + completionHandler:completionHandler]; + }); +} + +- (void) + updateExperimentConditionalUserPropertiesWithServiceOrigin:(NSString *)origin + events:(FIRLifecycleEvents *)events + policy: + (ABTExperimentPayloadExperimentOverflowPolicy) + policy + lastStartTime:(NSTimeInterval)lastStartTime + payloads:(NSArray *)payloads + completionHandler: + (nullable void (^)(NSError *_Nullable error)) + completionHandler { + ABTConditionalUserPropertyController *controller = + [ABTConditionalUserPropertyController sharedInstanceWithAnalytics:_analytics]; + + // Get the list of experiments from Firebase Analytics. + NSArray *experiments = [controller experimentsWithOrigin:origin]; + if (!experiments) { + NSString *errorDescription = + @"Failed to get conditional user properties from Firebase Analytics."; + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000003", @"%@", errorDescription); + + if (completionHandler) { + completionHandler([NSError + errorWithDomain:kABTErrorDomain + code:kABTInternalErrorFailedToFetchConditionalUserProperties + userInfo:@{NSLocalizedDescriptionKey : errorDescription}]); + } + + return; + } + NSArray *experimentsToSet = + ABTExperimentsToSetFromPayloads(payloads, experiments, _analytics); + NSArray *> *experimentsToClear = + ABTExperimentsToClearFromPayloads(payloads, experiments, _analytics); + + for (id experiment in experimentsToClear) { + NSString *experimentID = [controller experimentIDOfExperiment:experiment]; + NSString *variantID = [controller variantIDOfExperiment:experiment]; + [controller clearExperiment:experimentID + variantID:variantID + withOrigin:origin + payload:nil + events:events]; + } + + for (ABTExperimentPayload *experimentPayload in experimentsToSet) { + if (experimentPayload.experimentStartTimeMillis > lastStartTime * ABT_MSEC_PER_SEC) { + [controller setExperimentWithOrigin:origin + payload:experimentPayload + events:events + policy:policy]; + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000008", + @"Set Experiment ID %@, variant ID %@ to Firebase Analytics.", + experimentPayload.experimentId, experimentPayload.variantId); + + } else { + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000009", + @"Not setting experiment ID %@, variant ID %@ due to the last update time %lld.", + experimentPayload.experimentId, experimentPayload.variantId, + (long)lastStartTime * ABT_MSEC_PER_SEC); + } + } + + if (completionHandler) { + completionHandler(nil); + } +} + +- (NSTimeInterval)latestExperimentStartTimestampBetweenTimestamp:(NSTimeInterval)timestamp + andPayloads:(NSArray *)payloads { + for (NSData *payload in [payloads copy]) { + ABTExperimentPayload *experimentPayload = ABTDeserializeExperimentPayload(payload); + if (!experimentPayload) { + FIRLogInfo(kFIRLoggerABTesting, @"I-ABT000002", + @"Either payload is not set or it cannot be deserialized."); + continue; + } + if (experimentPayload.experimentStartTimeMillis > timestamp * ABT_MSEC_PER_SEC) { + timestamp = (double)(experimentPayload.experimentStartTimeMillis / ABT_MSEC_PER_SEC); + } + } + return timestamp; +} + +- (void)validateRunningExperimentsForServiceOrigin:(NSString *)origin + runningExperimentPayloads:(NSArray *)payloads { + ABTConditionalUserPropertyController *controller = + [ABTConditionalUserPropertyController sharedInstanceWithAnalytics:_analytics]; + + FIRLifecycleEvents *lifecycleEvents = [[FIRLifecycleEvents alloc] init]; + + // Get the list of experiments from Firebase Analytics. + NSArray *> *activeExperiments = + [controller experimentsWithOrigin:origin]; + + NSMutableSet *runningExperimentIDs = [NSMutableSet setWithCapacity:payloads.count]; + for (ABTExperimentPayload *payload in payloads) { + [runningExperimentIDs addObject:payload.experimentId]; + } + + for (NSDictionary *activeExperimentDictionary in activeExperiments) { + NSString *experimentID = activeExperimentDictionary[@"name"]; + if (![runningExperimentIDs containsObject:experimentID]) { + NSString *variantID = activeExperimentDictionary[@"value"]; + + [controller clearExperiment:experimentID + variantID:variantID + withOrigin:origin + payload:nil + events:lifecycleEvents]; + } + } +} + +- (void)activateExperiment:(ABTExperimentPayload *)experimentPayload + forServiceOrigin:(NSString *)origin { + ABTConditionalUserPropertyController *controller = + [ABTConditionalUserPropertyController sharedInstanceWithAnalytics:_analytics]; + + FIRLifecycleEvents *lifecycleEvents = [[FIRLifecycleEvents alloc] init]; + + // Ensure that trigger event is nil, which will immediately set the experiment to active. + [experimentPayload clearTriggerEvent]; + + [controller setExperimentWithOrigin:origin + payload:experimentPayload + events:lifecycleEvents + policy:experimentPayload.overflowPolicy]; +} + +@end diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRLifecycleEvents.m b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRLifecycleEvents.m new file mode 100644 index 0000000..95b25ae --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/FIRLifecycleEvents.m @@ -0,0 +1,88 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h" + +#import "FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRExperimentController.h" + +/// Default name of the analytics event to be logged when an experiment is set. +NSString *const FIRSetExperimentEventName = @"_exp_set"; +/// Default name of the analytics event to be logged when an experiment is activated. +NSString *const FIRActivateExperimentEventName = @"_exp_activate"; +/// Default name of the analytics event to be logged when an experiment is cleared. +NSString *const FIRClearExperimentEventName = @"_exp_clear"; +/// Default name of the analytics event to be logged when an experiment times out for being +/// activated. +NSString *const FIRTimeoutExperimentEventName = @"_exp_timeout"; +/// Default name of the analytics event to be logged when an experiment is expired as it reaches the +/// end of TTL. +NSString *const FIRExpireExperimentEventName = @"_exp_expire"; +/// Prefix for lifecycle event names. +static NSString *const kLifecycleEventPrefix = @"_"; + +@implementation FIRLifecycleEvents +- (instancetype)init { + self = [super init]; + if (self) { + _setExperimentEventName = FIRSetExperimentEventName; + _activateExperimentEventName = FIRActivateExperimentEventName; + _clearExperimentEventName = FIRClearExperimentEventName; + _timeoutExperimentEventName = FIRTimeoutExperimentEventName; + _expireExperimentEventName = FIRExpireExperimentEventName; + } + return self; +} + +- (void)setSetExperimentEventName:(NSString *)setExperimentEventName { + if (setExperimentEventName && [setExperimentEventName hasPrefix:kLifecycleEventPrefix]) { + _setExperimentEventName = setExperimentEventName; + } else { + _setExperimentEventName = FIRSetExperimentEventName; + } +} + +- (void)setActivateExperimentEventName:(NSString *)activateExperimentEventName { + if (activateExperimentEventName && + [activateExperimentEventName hasPrefix:kLifecycleEventPrefix]) { + _activateExperimentEventName = activateExperimentEventName; + } else { + _activateExperimentEventName = FIRActivateExperimentEventName; + } +} + +- (void)setClearExperimentEventName:(NSString *)clearExperimentEventName { + if (clearExperimentEventName && [clearExperimentEventName hasPrefix:kLifecycleEventPrefix]) { + _clearExperimentEventName = clearExperimentEventName; + } else { + _clearExperimentEventName = FIRClearExperimentEventName; + } +} + +- (void)setTimeoutExperimentEventName:(NSString *)timeoutExperimentEventName { + if (timeoutExperimentEventName && [timeoutExperimentEventName hasPrefix:kLifecycleEventPrefix]) { + _timeoutExperimentEventName = timeoutExperimentEventName; + } else { + _timeoutExperimentEventName = FIRTimeoutExperimentEventName; + } +} + +- (void)setExpireExperimentEventName:(NSString *)expireExperimentEventName { + if (expireExperimentEventName && [_timeoutExperimentEventName hasPrefix:kLifecycleEventPrefix]) { + _expireExperimentEventName = expireExperimentEventName; + } else { + _expireExperimentEventName = FIRExpireExperimentEventName; + } +} + +@end diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h new file mode 100644 index 0000000..b2f2da0 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h @@ -0,0 +1,96 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Policy for handling the case where there's an overflow of experiments for an installation +/// instance. +typedef NS_ENUM(int32_t, ABTExperimentPayloadExperimentOverflowPolicy) { + ABTExperimentPayloadExperimentOverflowPolicyUnrecognizedValue = 999, + ABTExperimentPayloadExperimentOverflowPolicyUnspecified = 0, + ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest = 1, + ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest = 2, +}; + +@interface ABTExperimentLite : NSObject +@property(nonatomic, readonly, copy) NSString *experimentId; + +- (instancetype)initWithExperimentId:(NSString *)experimentId NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +@interface ABTExperimentPayload : NSObject + +/// Unique identifier for this experiment. +@property(nonatomic, readonly, copy) NSString *experimentId; + +/// Unique identifier for the variant to which an installation instance has been assigned. +@property(nonatomic, readonly, copy) NSString *variantId; + +/// Epoch time that represents when the experiment was started. +@property(nonatomic, readonly) int64_t experimentStartTimeMillis; + +/// The event that triggers this experiment into ON state. +@property(nonatomic, nullable, readonly, copy) NSString *triggerEvent; + +/// Duration in milliseconds for which the experiment can stay in STANDBY state (un-triggered). +@property(nonatomic, readonly) int64_t triggerTimeoutMillis; + +/// Duration in milliseconds for which the experiment can stay in ON state (triggered). +@property(nonatomic, readonly) int64_t timeToLiveMillis; + +/// The event logged when impact service sets the experiment. +@property(nonatomic, readonly, copy) NSString *setEventToLog; + +/// The event logged when an experiment goes to the ON state. +@property(nonatomic, readonly, copy) NSString *activateEventToLog; + +/// The event logged when an experiment is cleared. +@property(nonatomic, readonly, copy) NSString *clearEventToLog; + +/// The event logged when an experiment times out after `triggerTimeoutMillis` milliseconds. +@property(nonatomic, readonly, copy) NSString *timeoutEventToLog; + +/// The event logged when an experiment times out after `timeToLiveMillis` milliseconds. +@property(nonatomic, readonly, copy) NSString *ttlExpiryEventToLog; + +@property(nonatomic, readonly) ABTExperimentPayloadExperimentOverflowPolicy overflowPolicy; + +/// A list of all other ongoing (started, and not yet stopped) experiments at the time this +/// experiment was started. Does not include this experiment; only the others. +@property(nonatomic, readonly) NSArray *ongoingExperiments; + +/// Parses an ABTExperimentPayload directly from JSON data. +/// @param data JSON object as NSData. Must be reconstructible as an NSDictionary. ++ (nullable instancetype)parseFromData:(NSData *)data; + +/// Initializes an ABTExperimentPayload from a dictionary with experiment metadata. +- (instancetype)initWithDictionary:(NSDictionary *)dictionary + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Clears the trigger event associated with this payload. +- (void)clearTriggerEvent; + +/// Checks if the overflow policy is a valid enum object. +- (BOOL)overflowPolicyIsValid; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h new file mode 100644 index 0000000..7259e08 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h @@ -0,0 +1,20 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase Public and Private +// headers. Any package manager complexity should be handled here. + +#import + +#import "FirebaseABTesting/Sources/Private/ABTExperimentPayload.h" diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRExperimentController.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRExperimentController.h new file mode 100644 index 0000000..3bd757d --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRExperimentController.h @@ -0,0 +1,83 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class ABTExperimentPayload; + +// Forward declaration to avoid importing into the module header +typedef NS_ENUM(int32_t, ABTExperimentPayloadExperimentOverflowPolicy); + +NS_ASSUME_NONNULL_BEGIN + +@class FIRLifecycleEvents; + +/// The default experiment overflow policy, that is to discard the experiment with the oldest start +/// time when users start the experiment on the web console. +extern const ABTExperimentPayloadExperimentOverflowPolicy FIRDefaultExperimentOverflowPolicy; + +/// This class is for Firebase services to handle experiments updates to Firebase Analytics. +/// Experiments can be set, cleared and updated through this controller. +NS_SWIFT_NAME(ExperimentController) +@interface FIRExperimentController : NSObject + +/// Returns the FIRExperimentController singleton. ++ (FIRExperimentController *)sharedInstance; + +/// Updates the list of experiments with an optional completion handler. Experiments already +/// existing in payloads are not affected, whose state and payload is preserved. This method +/// compares whether the experiments have changed or not by their variant ID. This runs in a +/// background queue and calls the completion handler when finished executing. +/// @param origin The originating service affected by the experiment. +/// @param events A list of event names to be used for logging experiment lifecycle events, +/// if they are not defined in the payload. +/// @param policy The policy to handle new experiments when slots are full. +/// @param lastStartTime The last known experiment start timestamp for this affected service. +/// (Timestamps are specified by the number of seconds from 00:00:00 UTC on 1 +/// January 1970.). +/// @param payloads List of experiment metadata. +/// @param completionHandler Code to be executed after experiments are updated in the background +/// thread. +- (void)updateExperimentsWithServiceOrigin:(NSString *)origin + events:(FIRLifecycleEvents *)events + policy:(ABTExperimentPayloadExperimentOverflowPolicy)policy + lastStartTime:(NSTimeInterval)lastStartTime + payloads:(NSArray *)payloads + completionHandler: + (nullable void (^)(NSError *_Nullable error))completionHandler; + +/// Returns the latest experiment start timestamp given a current latest timestamp and a list of +/// experiment payloads. Timestamps are specified by the number of seconds from 00:00:00 UTC on 1 +/// January 1970. +/// @param timestamp Current latest experiment start timestamp. If not known, affected service +/// should specify -1; +/// @param payloads List of experiment metadata. +- (NSTimeInterval)latestExperimentStartTimestampBetweenTimestamp:(NSTimeInterval)timestamp + andPayloads:(NSArray *)payloads; + +/// Expires experiments that aren't in the list of running experiment payloads. +/// @param origin The originating service affected by the experiment. +/// @param payloads The list of valid, running experiments. +- (void)validateRunningExperimentsForServiceOrigin:(NSString *)origin + runningExperimentPayloads:(NSArray *)payloads; + +/// Directly sets a given experiment to be active. +/// @param experimentPayload The payload for the experiment that should be activated. +/// @param origin The originating service affected by the experiment. +- (void)activateExperiment:(ABTExperimentPayload *)experimentPayload + forServiceOrigin:(NSString *)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h new file mode 100644 index 0000000..e20f9a3 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FIRLifecycleEvents.h @@ -0,0 +1,66 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Default event name for when an experiment is set. +extern NSString *const FIRSetExperimentEventName NS_SWIFT_NAME(DefaultSetExperimentEventName); +/// Default event name for when an experiment is activated. +// clang-format off +// clang-format12 will merge lines and exceed 100 character limit. +extern NSString *const FIRActivateExperimentEventName + NS_SWIFT_NAME(DefaultActivateExperimentEventName); +/// Default event name for when an experiment is cleared. +extern NSString *const FIRClearExperimentEventName NS_SWIFT_NAME(DefaultClearExperimentEventName); +/// Default event name for when an experiment times out for being activated. +extern NSString *const FIRTimeoutExperimentEventName + NS_SWIFT_NAME(DefaultTimeoutExperimentEventName); +// clang-format on +/// Default event name for when an experiment is expired as it reaches the end of TTL. +extern NSString *const FIRExpireExperimentEventName NS_SWIFT_NAME(DefaultExpireExperimentEventName); + +/// An Experiment Lifecycle Event Object that specifies the name of the experiment event to be +/// logged by Firebase Analytics. +NS_SWIFT_NAME(LifecycleEvents) +@interface FIRLifecycleEvents : NSObject + +/// Event name for when an experiment is set. It defaults to `SetExperimentEventName` and can be +/// overridden. If experiment payload has a valid string of this field, always use +/// experiment payload. +@property(nonatomic, copy) NSString *setExperimentEventName; + +/// Event name for when an experiment is activated. It defaults to `ActivateExperimentEventName` +/// and can be overridden. If experiment payload has a valid string of this field, always use +/// experiment payload. +@property(nonatomic, copy) NSString *activateExperimentEventName; + +/// Event name for when an experiment is cleared. It is default to `ClearExperimentEventName` and +/// can be overridden. If experiment payload has a valid string of this field, always use experiment +/// payload. +@property(nonatomic, copy) NSString *clearExperimentEventName; +/// Event name for when an experiment is timeout from being STANDBY. It is default to +/// `TimeoutExperimentEventName` and can be overridden. If experiment payload has a valid string +/// of this field, always use experiment payload. +@property(nonatomic, copy) NSString *timeoutExperimentEventName; + +/// Event name when an experiment is expired when it reaches the end of its TTL. +/// It is default to `ExpireExperimentEventName` and can be overridden. If experiment payload has a +/// valid string of this field, always use experiment payload. +@property(nonatomic, copy) NSString *expireExperimentEventName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FirebaseABTesting.h b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FirebaseABTesting.h new file mode 100755 index 0000000..cfa99b4 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Public/FirebaseABTesting/FirebaseABTesting.h @@ -0,0 +1,16 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRExperimentController.h" +#import "FIRLifecycleEvents.h" diff --git a/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..c89c88f --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseABTesting/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,18 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseABTesting/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseABTesting/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseABTesting/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInterop.h b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInterop.h new file mode 100644 index 0000000..3b49733 --- /dev/null +++ b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInterop.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol FIRAnalyticsInteropListener; + +NS_ASSUME_NONNULL_BEGIN + +/// Block typedef callback parameter to `getUserProperties(with:)`. +typedef void (^FIRAInteropUserPropertiesCallback)(NSDictionary *userProperties) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Connector for bridging communication between Firebase SDKs and FirebaseAnalytics APIs. +@protocol FIRAnalyticsInterop + +/// Sets user property when trigger event is logged. This API is only available in the SDK. +- (void)setConditionalUserProperty:(NSDictionary *)conditionalUserProperty; + +/// Clears user property if set. +- (void)clearConditionalUserProperty:(NSString *)userPropertyName + forOrigin:(NSString *)origin + clearEventName:(NSString *)clearEventName + clearEventParameters:(NSDictionary *)clearEventParameters; + +/// Returns currently set user properties. +- (NSArray *> *)conditionalUserProperties:(NSString *)origin + propertyNamePrefix: + (NSString *)propertyNamePrefix; + +/// Returns the maximum number of user properties. +- (NSInteger)maxUserProperties:(NSString *)origin; + +/// Returns the user properties to a callback function. +- (void)getUserPropertiesWithCallback: + (void (^)(NSDictionary *userProperties))callback; + +/// Logs events. +- (void)logEventWithOrigin:(NSString *)origin + name:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets user property. +- (void)setUserPropertyWithOrigin:(NSString *)origin name:(NSString *)name value:(id)value; + +/// Registers an Analytics listener for the given origin. +- (void)registerAnalyticsListener:(id)listener + withOrigin:(NSString *)origin; + +/// Unregisters an Analytics listener for the given origin. +- (void)unregisterAnalyticsListenerWithOrigin:(NSString *)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInteropListener.h b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInteropListener.h new file mode 100644 index 0000000..327aefd --- /dev/null +++ b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRAnalyticsInteropListener.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Handles events and messages from Analytics. +@protocol FIRAnalyticsInteropListener + +/// Triggers when an Analytics event happens for the registered origin with +/// FirebaseAnalyticsInterop`s `registerAnalyticsListener(_:withOrigin:)`. +- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters; + +@end diff --git a/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropEventNames.h b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropEventNames.h new file mode 100644 index 0000000..efc54ab --- /dev/null +++ b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropEventNames.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// @file FIRInteropEventNames.h + +#import + +/// Notification open event name. +static NSString *const kFIRIEventNotificationOpen = @"_no"; + +/// Notification foreground event name. +static NSString *const kFIRIEventNotificationForeground = @"_nf"; + +/// Campaign event name. +static NSString *const kFIRIEventFirebaseCampaign = @"_cmp"; diff --git a/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropParameterNames.h b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropParameterNames.h new file mode 100644 index 0000000..f640702 --- /dev/null +++ b/Pods/FirebaseABTesting/Interop/Analytics/Public/FIRInteropParameterNames.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// @file FIRInteropParameterNames.h +/// +/// Predefined event parameter names used by Firebase. This file is a subset of the +/// FirebaseAnalytics FIRParameterNames.h public header. +/// +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       kFIRParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Message identifier. +static NSString *const kFIRIParameterMessageIdentifier = @"_nmid"; + +/// Message name. +static NSString *const kFIRIParameterMessageName = @"_nmn"; + +/// Message send time. +static NSString *const kFIRIParameterMessageTime = @"_nmt"; + +/// Message device time. +static NSString *const kFIRIParameterMessageDeviceTime = @"_ndt"; + +/// Topic message. +static NSString *const kFIRIParameterTopic = @"_nt"; + +/// Stores the message_id of the last notification opened by the app. +static NSString *const kFIRIUserPropertyLastNotification = @"_ln"; diff --git a/Pods/FirebaseABTesting/LICENSE b/Pods/FirebaseABTesting/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseABTesting/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseABTesting/README.md b/Pods/FirebaseABTesting/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseABTesting/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist new file mode 100644 index 0000000..4640d50 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/Info.plist @@ -0,0 +1,107 @@ + + + + + AvailableLibraries + + + BinaryPath + FirebaseAnalytics.framework/FirebaseAnalytics + LibraryIdentifier + ios-arm64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + BinaryPath + FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + BinaryPath + FirebaseAnalytics.framework/FirebaseAnalytics + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + BinaryPath + FirebaseAnalytics.framework/FirebaseAnalytics + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + BinaryPath + FirebaseAnalytics.framework/FirebaseAnalytics + LibraryIdentifier + tvos-arm64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + BinaryPath + FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + FirebaseAnalytics.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeDirectory b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeDirectory new file mode 100644 index 0000000..bcd557a Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeDirectory differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements new file mode 100644 index 0000000..665b37e Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements-1 b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements-1 new file mode 100644 index 0000000..6c10b79 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeRequirements-1 differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeResources b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeResources new file mode 100644 index 0000000..36555ee --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeResources @@ -0,0 +1,2068 @@ + + + + + files + + ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics + + 4TWkcATxuIU+5C+hG4fT+ROVRUs= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + 0nWXABx/HRqcUMkqMxRdJuHxqQU= + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + ios-arm64/FirebaseAnalytics.framework/Info.plist + + WX6aoBMqQwQzsDvLeyE0OgFVPrw= + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo + + 3M+pYToQyErPKuPVG6i1Cq45UGg= + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.private.swiftinterface + + NAvpCrv1M1YGI6Vin6eL42cx/3s= + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftdoc + + BHIT/FyHupjfAkf+upImM8fRLqU= + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftinterface + + NAvpCrv1M1YGI6Vin6eL42cx/3s= + + ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + + hLMA9SEHbpnzoKCc9HUHc1uhKak= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-macabi.swiftsourceinfo + + EhtqX7DzKoQW0iSi3IUTGK5b37Q= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-macabi.swiftsourceinfo + + JLsXBdIWPoRNn3Kb2eMFEdHVdRA= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.private.swiftinterface + + 4gR6vGh9NGCOc8NqbJitBi4PYMc= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftdoc + + qhoelsD3haNmZEE9NM8xvtK9mEY= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftinterface + + 4gR6vGh9NGCOc8NqbJitBi4PYMc= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface + + R1LVVji18GwfW9nhhjO5aFGB1+k= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftdoc + + /8RdTbctZKCA1/OIwmZLl2oWnCk= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftinterface + + R1LVVji18GwfW9nhhjO5aFGB1+k= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist + + svXxv0/OGVjQmF1D+z3z0w5TRm0= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics + + 5lkjmj4xdvZvK3gmirF/U6+EOHk= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist + + etmbf5xWw3wEKGL3IWC/ow/wF+M= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo + + FhnJN0FjXUhPYpTZbg7lfTzY4iM= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo + + G1rPKi+yEapomahwUr5E85athPA= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface + + hZUm+6Yon0B4K7L8GD1ScdCY3t0= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftdoc + + JeXYTVdQMygRSZdbbP8kc/pgjAI= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftinterface + + hZUm+6Yon0B4K7L8GD1ScdCY3t0= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface + + eO9rriExhXQgyXhchyORV3h91L4= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftdoc + + mjATLkNPULjHjLv3ARUXQ7doOSY= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftinterface + + eO9rriExhXQgyXhchyORV3h91L4= + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + + k2YgKDybd3CbLlkKKDkufS9bf5M= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h + + sXk7jWhcfsvb8eJb7/NDl2Dy2RQ= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo + + tDXAvUd1DT/hf+gGhRWBN9f6++k= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo + + yO6TP0ibVAPGnKhw/PP4xRl7xRU= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.private.swiftinterface + + ZAKuYvVr4sfCX7usXZP7Kk9oW7k= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftdoc + + 1zu68JlIn8zDFnfRoKMDRMs6j5I= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftinterface + + ZAKuYvVr4sfCX7usXZP7Kk9oW7k= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.private.swiftinterface + + TztLGK3InUf3F4NjuC+lzdaWf50= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftdoc + + ByKNCJ6aB6LHj+qNk+ZX3YQ3LWM= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftinterface + + TztLGK3InUf3F4NjuC+lzdaWf50= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap + + jWZ+azdgXQdH9z56z25NptmWlq4= + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist + + oYHe0jq2/d647hnie1kXM5yTzG0= + + tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics + + 6KKSHK++Blij52zq9pAdBDlRLbQ= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + 0nWXABx/HRqcUMkqMxRdJuHxqQU= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + tvos-arm64/FirebaseAnalytics.framework/Info.plist + + QpGj6BfYgPdzaxBNh2oz0+kEaqg= + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos.swiftsourceinfo + + b0d6xVfiF71u0Dj4E4tbrPn+9wc= + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.private.swiftinterface + + Yg0lxt4eDVJ4zEDgxRvyl2hwR5Q= + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftdoc + + ICm3QgbA9GCrU8RrR6izKGRnrLA= + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftinterface + + Yg0lxt4eDVJ4zEDgxRvyl2hwR5Q= + + tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics + + ScPpK9PZ1K2h4MEIEhGdimAqFGg= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist + + q9RykUmARxGpwWkmA+HY/h9DPA0= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos-simulator.swiftsourceinfo + + WC+E5oT39/Vu6ecgffiaR00kGys= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-tvos-simulator.swiftsourceinfo + + xw34VmRefYpxywjZs0NQB+4xvz8= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.private.swiftinterface + + +EoKjIoaiJH4HuBxFOAR+N6qm/A= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftdoc + + kEpmMJ+EwdoypGxC9M4fHrfAYic= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftinterface + + +EoKjIoaiJH4HuBxFOAR+N6qm/A= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.abi.json + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.private.swiftinterface + + KthVIak11hjuXvIlm095GJUwL1M= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc + + 65HbWdHXydClg5RHbdZeeWhc8us= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftinterface + + KthVIak11hjuXvIlm095GJUwL1M= + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + + files2 + + ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics + + hash + + 4TWkcATxuIU+5C+hG4fT+ROVRUs= + + hash2 + + 8/9oZKg7xVvmNpY5bHq1YNlySb2+UfgrbO0rakY0aKw= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + hash + + 0nWXABx/HRqcUMkqMxRdJuHxqQU= + + hash2 + + DmmG7v+JGyWpcKQl1BeGd8rqz4HV3b+PToUt+aM45bY= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + hash + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + hash2 + + LOiywMHEh60MswGEzs9lM8P6m3oohYp+IWaiZtbwVVM= + + + ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + ios-arm64/FirebaseAnalytics.framework/Info.plist + + hash + + WX6aoBMqQwQzsDvLeyE0OgFVPrw= + + hash2 + + 6HZwAdwIcLgdAYbXj2Rdo8hxuIk/yBzbvcA/jwYk7VE= + + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo + + hash + + 3M+pYToQyErPKuPVG6i1Cq45UGg= + + hash2 + + gDXpDQ46UaffVyDDJojjT9cq4VI6EG0nsDQq7vP4Osg= + + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.private.swiftinterface + + hash + + NAvpCrv1M1YGI6Vin6eL42cx/3s= + + hash2 + + w4kvFgyfxWYtCjCy0BYHS05P0r5XAws8V9Mc4rKyOaQ= + + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftdoc + + hash + + BHIT/FyHupjfAkf+upImM8fRLqU= + + hash2 + + VD+vnhQT/tzGLf1nYQU+/onj2SvCzxwQtgst449XRlc= + + + ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftinterface + + hash + + NAvpCrv1M1YGI6Vin6eL42cx/3s= + + hash2 + + w4kvFgyfxWYtCjCy0BYHS05P0r5XAws8V9Mc4rKyOaQ= + + + ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap + + hash + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + hash2 + + vxNgOuI61t45Sed09vILAKePFm9riTp4aZ48hjDRPIQ= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics + + symlink + Versions/Current/FirebaseAnalytics + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers + + symlink + Versions/Current/Headers + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules + + symlink + Versions/Current/Modules + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Resources + + symlink + Versions/Current/Resources + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + + hash + + hLMA9SEHbpnzoKCc9HUHc1uhKak= + + hash2 + + 5NXk7T4Y6W/XNKWU0Djgq2+7hF3KSBus3PucXubv7bM= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h + + hash + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + hash2 + + 4mnxjtoRMyo5TIjTieqzJLBQ4m0noIZqWhmI5a2a3QE= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h + + hash + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + hash2 + + LOiywMHEh60MswGEzs9lM8P6m3oohYp+IWaiZtbwVVM= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-macabi.swiftsourceinfo + + hash + + EhtqX7DzKoQW0iSi3IUTGK5b37Q= + + hash2 + + EB/Dw4T1UMGv1jgPZ1eCWm7fdXPIo8yT0CkHETyq3mU= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-macabi.swiftsourceinfo + + hash + + JLsXBdIWPoRNn3Kb2eMFEdHVdRA= + + hash2 + + jXBXaBJl9zxQZXHt4XmxiSmutlJNIM/Y2nF+nFirDLQ= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.private.swiftinterface + + hash + + 4gR6vGh9NGCOc8NqbJitBi4PYMc= + + hash2 + + sBsGCsKt/qVMlUX2JkA5hB1ko0klhw7cNGdqgUlwGW4= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftdoc + + hash + + qhoelsD3haNmZEE9NM8xvtK9mEY= + + hash2 + + ORG2lGLtqMk9O/g5fSRsgM0vkRuCeApJ2rKBJUOAyQY= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftinterface + + hash + + 4gR6vGh9NGCOc8NqbJitBi4PYMc= + + hash2 + + sBsGCsKt/qVMlUX2JkA5hB1ko0klhw7cNGdqgUlwGW4= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface + + hash + + R1LVVji18GwfW9nhhjO5aFGB1+k= + + hash2 + + 8sleA8PWyFsmq4UfIdcmC5GkHeUcPvp/kAytxpjR9N0= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftdoc + + hash + + /8RdTbctZKCA1/OIwmZLl2oWnCk= + + hash2 + + zgcFlEjAeUx/3gKqZtb0j32k5wK3ScunLgYWrpCZ8YY= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftinterface + + hash + + R1LVVji18GwfW9nhhjO5aFGB1+k= + + hash2 + + 8sleA8PWyFsmq4UfIdcmC5GkHeUcPvp/kAytxpjR9N0= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap + + hash + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + hash2 + + vxNgOuI61t45Sed09vILAKePFm9riTp4aZ48hjDRPIQ= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist + + hash + + svXxv0/OGVjQmF1D+z3z0w5TRm0= + + hash2 + + Q9LZdmVWVRUP3q3lLdhUHRJR4KHk7xMtSOrKMCdIp+o= + + + ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/Current + + symlink + A + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics + + hash + + 5lkjmj4xdvZvK3gmirF/U6+EOHk= + + hash2 + + ov7GDmKsTwBrxyGJDDKZsskGgKQ/iTjYMmwtXYiLLhg= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + hash + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + hash2 + + 4mnxjtoRMyo5TIjTieqzJLBQ4m0noIZqWhmI5a2a3QE= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + hash + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + hash2 + + LOiywMHEh60MswGEzs9lM8P6m3oohYp+IWaiZtbwVVM= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist + + hash + + etmbf5xWw3wEKGL3IWC/ow/wF+M= + + hash2 + + kH3fU+ZuMtEki514m7Cc6ofP/bWS1iaUZyQ+karEG6c= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo + + hash + + FhnJN0FjXUhPYpTZbg7lfTzY4iM= + + hash2 + + 9XmCR5irL/8jhiloXGrknFOIXREzqF5D7zOusygjD+M= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo + + hash + + G1rPKi+yEapomahwUr5E85athPA= + + hash2 + + O/FxrYsc5ddEnVxgrppEhKMlUD5uDlwSVru+JzigV/Y= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface + + hash + + hZUm+6Yon0B4K7L8GD1ScdCY3t0= + + hash2 + + QzIaVFFMO8tYIzl4o3nbVBhW2fuNtgOmkSNeDMOfOfA= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftdoc + + hash + + JeXYTVdQMygRSZdbbP8kc/pgjAI= + + hash2 + + R2Pt3A/l7SQ4n2I93xw+Ffz7yGbF0Q7HJd4fqxMgV10= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftinterface + + hash + + hZUm+6Yon0B4K7L8GD1ScdCY3t0= + + hash2 + + QzIaVFFMO8tYIzl4o3nbVBhW2fuNtgOmkSNeDMOfOfA= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface + + hash + + eO9rriExhXQgyXhchyORV3h91L4= + + hash2 + + lt9Vh+N0wzNo3JZuavlytTxaN9X/rwKiQlcn7Xt6DU4= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftdoc + + hash + + mjATLkNPULjHjLv3ARUXQ7doOSY= + + hash2 + + gcmxRgiXlWBZMSGlxd3/aPJfzJWomCwGizfkHXKvofA= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftinterface + + hash + + eO9rriExhXQgyXhchyORV3h91L4= + + hash2 + + lt9Vh+N0wzNo3JZuavlytTxaN9X/rwKiQlcn7Xt6DU4= + + + ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap + + hash + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + hash2 + + vxNgOuI61t45Sed09vILAKePFm9riTp4aZ48hjDRPIQ= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics + + symlink + Versions/Current/FirebaseAnalytics + + macos-arm64_x86_64/FirebaseAnalytics.framework/Headers + + symlink + Versions/Current/Headers + + macos-arm64_x86_64/FirebaseAnalytics.framework/Modules + + symlink + Versions/Current/Modules + + macos-arm64_x86_64/FirebaseAnalytics.framework/Resources + + symlink + Versions/Current/Resources + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics + + hash + + k2YgKDybd3CbLlkKKDkufS9bf5M= + + hash2 + + bvTqmJfY3GA8URECdr8W5Etny9hghCS8GDdFeB7B0/s= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h + + hash + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + hash2 + + 4mnxjtoRMyo5TIjTieqzJLBQ4m0noIZqWhmI5a2a3QE= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h + + hash + + sXk7jWhcfsvb8eJb7/NDl2Dy2RQ= + + hash2 + + E6EdPyZp5cQbOObE0CPO9/R+QvTIYlDIOHvuzam/9H8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo + + hash + + tDXAvUd1DT/hf+gGhRWBN9f6++k= + + hash2 + + QzCJQ72/JCPFZASJhWt7lF4KSL9gQCJAHOBGZixXkws= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo + + hash + + yO6TP0ibVAPGnKhw/PP4xRl7xRU= + + hash2 + + 5IoLEq5Ozo113OVhVe9+W2gjx/eVozbIGXB2vjZ+Vw8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.private.swiftinterface + + hash + + ZAKuYvVr4sfCX7usXZP7Kk9oW7k= + + hash2 + + 65tpMWBKS1d0GpEhBByvoQ0+KStlRWp8GF8K7dzViE8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftdoc + + hash + + 1zu68JlIn8zDFnfRoKMDRMs6j5I= + + hash2 + + 5q8dF0bgCDYfD0KnwHIw+wuj/GogPeqMVp2cx9uulKg= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftinterface + + hash + + ZAKuYvVr4sfCX7usXZP7Kk9oW7k= + + hash2 + + 65tpMWBKS1d0GpEhBByvoQ0+KStlRWp8GF8K7dzViE8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.private.swiftinterface + + hash + + TztLGK3InUf3F4NjuC+lzdaWf50= + + hash2 + + nSnXCeosOPuMgd2b41zKfQBUM22ZloRdAj9hyRYK8wk= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftdoc + + hash + + ByKNCJ6aB6LHj+qNk+ZX3YQ3LWM= + + hash2 + + 7L1iy8hHgpzEAPYgxmkdsz/w6JO8FzKST9eY6Hz9nQU= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftinterface + + hash + + TztLGK3InUf3F4NjuC+lzdaWf50= + + hash2 + + nSnXCeosOPuMgd2b41zKfQBUM22ZloRdAj9hyRYK8wk= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap + + hash + + jWZ+azdgXQdH9z56z25NptmWlq4= + + hash2 + + e4a41Axjw7BAywMms/GuOcqrdwPIVYuMRsPznqQS0X8= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist + + hash + + oYHe0jq2/d647hnie1kXM5yTzG0= + + hash2 + + GumuYQPnyvV63aI4FIGdxXwspWQEKX6j6bgTpwkINkY= + + + macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/Current + + symlink + A + + tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics + + hash + + 6KKSHK++Blij52zq9pAdBDlRLbQ= + + hash2 + + 8WL/5BNllU4afHaeflRtaPrbFHtVzSRBRgv1EoW2us8= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + hash + + 0nWXABx/HRqcUMkqMxRdJuHxqQU= + + hash2 + + DmmG7v+JGyWpcKQl1BeGd8rqz4HV3b+PToUt+aM45bY= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + hash + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + hash2 + + LOiywMHEh60MswGEzs9lM8P6m3oohYp+IWaiZtbwVVM= + + + tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + tvos-arm64/FirebaseAnalytics.framework/Info.plist + + hash + + QpGj6BfYgPdzaxBNh2oz0+kEaqg= + + hash2 + + owmnZRQqsuSDRrqYBYESImL/Zib1MN9AhCETv8GjbXQ= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos.swiftsourceinfo + + hash + + b0d6xVfiF71u0Dj4E4tbrPn+9wc= + + hash2 + + QyXu9XGPHG0qkF86498YTbqqlYBOG924tN0z82f2Ghk= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.private.swiftinterface + + hash + + Yg0lxt4eDVJ4zEDgxRvyl2hwR5Q= + + hash2 + + EsiBmwD4KG8UOQJ9SEWfB/O1mnTXHmVIEyAeH2JVApE= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftdoc + + hash + + ICm3QgbA9GCrU8RrR6izKGRnrLA= + + hash2 + + Wd9mR8J/cQBEqDuyZ1x32/TWxOvg35osz6P9hEE4nck= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftinterface + + hash + + Yg0lxt4eDVJ4zEDgxRvyl2hwR5Q= + + hash2 + + EsiBmwD4KG8UOQJ9SEWfB/O1mnTXHmVIEyAeH2JVApE= + + + tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap + + hash + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + hash2 + + vxNgOuI61t45Sed09vILAKePFm9riTp4aZ48hjDRPIQ= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics + + hash + + ScPpK9PZ1K2h4MEIEhGdimAqFGg= + + hash2 + + e/mMv3A45/g5+5Vo4fkyav4kg//pyK1lQkcRmEuS5Io= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h + + hash + + JxSy4BVIpZB3s+tbI3EgcIVsvN0= + + hash2 + + HSPmaeLSu5PqNTtlwUWfRT4cyVX65JmeB/oed8f0pdU= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h + + hash + + IN4riVkldIj3MlPpvlUuU1i+I8w= + + hash2 + + ebGwpP2JZ0Rp6BdXhKiLUYOq6nJG7la5O0y/wEKfyak= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h + + hash + + 58LqQ/Y9jqPGz3JttzK0z7jPLLc= + + hash2 + + 67S/czxwflT8GxF7bVp32FLgu2W97zH06W6zv8/VILU= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h + + hash + + B+YLaEHhiOu6tTPZaB5wWy4n95U= + + hash2 + + wmpxZuP80odiQUX5Ts7GaPkhE7UeuzmDMrvTcOS0vLQ= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h + + hash + + HrzLufMtB3E5zAfPXZTkYQdGyHI= + + hash2 + + mNgPvQJ0O5ZQ/EINmxz+zoQHoxj/O70iH5crkbhGU3g= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h + + hash + + SztBbCRZ5QE523pdMx4HZt0AYKE= + + hash2 + + hwLb6dR4Q5L+j2vYcsXcc8sr2yoS1X9vyl7T/PjcHow= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h + + hash + + 33ogzLW88kbc3XVXJp9Opq9Znmc= + + hash2 + + z0lD0Agt0NzOZdG+xd6QpXvGS+06dK4A3RYK0Wu1OKw= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h + + hash + + cu0mXcU7RrT9nKAMSamYxQcZ8MA= + + hash2 + + 4mnxjtoRMyo5TIjTieqzJLBQ4m0noIZqWhmI5a2a3QE= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h + + hash + + wE8Bjq1o5wGq1TFJb0gCJUmRelQ= + + hash2 + + LOiywMHEh60MswGEzs9lM8P6m3oohYp+IWaiZtbwVVM= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h + + hash + + 6tM+QmAiCFyFHMaFXgWsH/uYosM= + + hash2 + + VS1dxfDwCZeRcJYgkkEUhmdXx6ch9X/E8YjKBX367WY= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist + + hash + + q9RykUmARxGpwWkmA+HY/h9DPA0= + + hash2 + + aql5HABSrVkuBeSRm5uQO6NG2o+sxbJr7jcw1WpUlEU= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos-simulator.swiftsourceinfo + + hash + + WC+E5oT39/Vu6ecgffiaR00kGys= + + hash2 + + w7B16PsLn7E+3+D/saa8rPXSOTv0IINGbNPPHPgRZ+0= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-tvos-simulator.swiftsourceinfo + + hash + + xw34VmRefYpxywjZs0NQB+4xvz8= + + hash2 + + OYRUNqHkG5UkTTHQx4K7PO4J+oeeC5X61EMppp0tTow= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.private.swiftinterface + + hash + + +EoKjIoaiJH4HuBxFOAR+N6qm/A= + + hash2 + + DoD1OSJHno0bNy0osPn/laVPoBAxHGWB789dQSNEMkI= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftdoc + + hash + + kEpmMJ+EwdoypGxC9M4fHrfAYic= + + hash2 + + kgbprKMKWtu9nlXnOTVjHVY0TAgVDbK5pK/G+QpaymE= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftinterface + + hash + + +EoKjIoaiJH4HuBxFOAR+N6qm/A= + + hash2 + + DoD1OSJHno0bNy0osPn/laVPoBAxHGWB789dQSNEMkI= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.abi.json + + hash + + 66KHnyUOUpeHtfGUA412UpsRmhw= + + hash2 + + C4diFGoEyBmGjFO8mP/P4nf/3oZuROOsFMcNqQ/DHE8= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.private.swiftinterface + + hash + + KthVIak11hjuXvIlm095GJUwL1M= + + hash2 + + MwVZoM3SRxYLhYEsI316k3d6aaaJ31Xne1MXyoX0sFs= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc + + hash + + 65HbWdHXydClg5RHbdZeeWhc8us= + + hash2 + + HXWYfxPhG1Lkni6+8MhUCQGNPmfg72yH2N6CVQbWuuI= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftinterface + + hash + + KthVIak11hjuXvIlm095GJUwL1M= + + hash2 + + MwVZoM3SRxYLhYEsI316k3d6aaaJ31Xne1MXyoX0sFs= + + + tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap + + hash + + uLysK0T5K1GSoqJmcXx9AnZ9lqY= + + hash2 + + vxNgOuI61t45Sed09vILAKePFm9riTp4aZ48hjDRPIQ= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeSignature b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeSignature new file mode 100644 index 0000000..e52a03c Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/_CodeSignature/CodeSignature differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..beb9190 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..127576f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,312 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..a1c770a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,57 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphoneos + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphoneos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo new file mode 100644 index 0000000..06d5c41 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.private.swiftinterface new file mode 100644 index 0000000..efac098 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios12.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftdoc new file mode 100644 index 0000000..b1d514b Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftinterface new file mode 100644 index 0000000..efac098 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios12.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..fa10817 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 120000 index 0000000..82502e9 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/FirebaseAnalytics @@ -0,0 +1 @@ +Versions/Current/FirebaseAnalytics \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Resources b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics new file mode 100644 index 0000000..d69aa06 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..3dbf01a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,620 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-macabi.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-macabi.swiftsourceinfo new file mode 100644 index 0000000..5c77353 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-macabi.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-macabi.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-macabi.swiftsourceinfo new file mode 100644 index 0000000..96af6ab Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-macabi.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.private.swiftinterface new file mode 100644 index 0000000..167a18c --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios13.1-macabi -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftdoc new file mode 100644 index 0000000..8591fff Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftinterface new file mode 100644 index 0000000..167a18c --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-macabi.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios13.1-macabi -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface new file mode 100644 index 0000000..6dbbf72 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios13.1-macabi -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftdoc new file mode 100644 index 0000000..7cfa677 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftinterface new file mode 100644 index 0000000..6dbbf72 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-macabi.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios13.1-macabi -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..fa10817 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..3a611f6 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,54 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + UIDeviceFamily + + 2 + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/Current b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst/FirebaseAnalytics.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..29be556 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..3dbf01a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,620 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..50bd672 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,53 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphonesimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphonesimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 0000000..d594226 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-ios-simulator.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo new file mode 100644 index 0000000..cef01c7 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-ios-simulator.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 0000000..ba530d4 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios12.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000..8c3d9e5 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftinterface new file mode 100644 index 0000000..ba530d4 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-ios-simulator.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-ios12.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface new file mode 100644 index 0000000..2532ee9 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios12.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftdoc new file mode 100644 index 0000000..09db1b8 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftinterface new file mode 100644 index 0000000..2532ee9 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-ios-simulator.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-ios12.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..fa10817 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 120000 index 0000000..82502e9 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/FirebaseAnalytics @@ -0,0 +1 @@ +Versions/Current/FirebaseAnalytics \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Resources b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics new file mode 100644 index 0000000..9dbc72e Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..3dbf01a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,620 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..58342c6 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo new file mode 100644 index 0000000..45a174d Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-macos.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo new file mode 100644 index 0000000..b30d50b Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-macos.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.private.swiftinterface new file mode 100644 index 0000000..6cc58c4 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-macos10.15 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftdoc new file mode 100644 index 0000000..3846b1f Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftinterface new file mode 100644 index 0000000..6cc58c4 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-macos.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-macos10.15 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.private.swiftinterface new file mode 100644 index 0000000..ed5a9f3 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-macos10.15 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftdoc new file mode 100644 index 0000000..88b706d Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftinterface new file mode 100644 index 0000000..ed5a9f3 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-macos.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-macos10.15 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..927d5c0 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "AppKit" + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..c4a1804 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,50 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/Current b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/macos-arm64_x86_64/FirebaseAnalytics.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..7131125 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..127576f --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,312 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..7766126 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvos + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos.swiftsourceinfo new file mode 100644 index 0000000..4dd70cf Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.private.swiftinterface new file mode 100644 index 0000000..ddb8384 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-tvos13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftdoc new file mode 100644 index 0000000..c852ce8 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftinterface new file mode 100644 index 0000000..ddb8384 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-tvos13.0 -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..fa10817 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics new file mode 100644 index 0000000..583ff87 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/FirebaseAnalytics differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h new file mode 100644 index 0000000..cb1e407 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+AppDelegate.h @@ -0,0 +1,80 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Provides App Delegate handlers to be used in your App Delegate. +/// +/// To save time integrating Firebase Analytics in an application, Firebase Analytics does not +/// require delegation implementation from the AppDelegate if neither SwiftUI nor UIScene lifecycle +/// is adopted. Instead this is automatically done by Firebase Analytics. Should you choose instead +/// to delegate manually, you can turn off the App Delegate Proxy by adding +/// FirebaseAppDelegateProxyEnabled into your app's Info.plist and setting it to boolean `NO`, and +/// adding the methods in this category to corresponding delegation handlers. +/// +/// To handle Universal Links, you must return `true` in +/// `UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:)`. +@interface FIRAnalytics (AppDelegate) + +/// Handles events related to a URL session that are waiting to be processed. +/// +/// 1. If SwiftUI lifecycle is adopted, call this method from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// 2. If SwiftUI lifecycle is not adopted, Firebase Analytics does not require delegation +/// implementation from the AppDelegate. If you choose instead to delegate manually, you can set +/// FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this method +/// from +/// `UIApplicationDelegate.application(_:handleEventsForBackgroundURLSession:completionHandler:)` +/// in your app delegate. +/// +/// @param identifier The identifier of the URL session requiring attention. +/// @param completionHandler The completion handler to call when you finish processing the events. +/// Calling this completion handler lets the system know that your app's user interface is +/// updated and a new snapshot can be taken. ++ (void)handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(nullable void (^)(void))completionHandler; + +/// Handles the event when the app is launched by a URL (custom URL scheme or universal link). +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// this method in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and +/// `UISceneDelegate.scene(_:openURLContexts:)` when the URL contexts are available. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplicationDelegate.application(_:open:options:)` in your app delegate. +/// +/// @param url The URL resource to open. This resource can be a network resource or a file. ++ (void)handleOpenURL:(NSURL *)url; + +/// Handles the event when the app receives data associated with user activity that includes a +/// Universal Link. +/// +/// 1. If SwiftUI lifecycle is adopted, use `onOpenURL(perform:)` to register a handler and call +/// `Analytics.handleOpen(_:)` instead in the handler. +/// +/// 2. If UIScene lifecycle is adopted, call this method from +/// `UISceneDelegate.scene(_:willConnectTo:options:)` and `UISceneDelegate.scene(_:continue:)` when +/// NSUserActivity is available. See the [Apple +/// doc](https://developer.apple.com/documentation/xcode/supporting-universal-links-in-your-app) for +/// more details. +/// +/// 3. If neither SwiftUI nor UIScene lifecycle is adopted, Firebase Analytics does not require +/// delegation implementation from the AppDelegate. If you choose instead to delegate manually, you +/// can set FirebaseAppDelegateProxyEnabled to boolean `NO` in your app's Info.plist and call this +/// method from `UIApplication.application(_:continue:restorationHandler:)` in your app delegate. +/// +/// @param userActivity The activity object containing the data associated with the task the user +/// was performing. ++ (void)handleUserActivity:(id)userActivity; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h new file mode 100644 index 0000000..7758390 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+Consent.h @@ -0,0 +1,51 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The type of consent to set. Supported consent types are `ConsentType.adStorage`, +/// `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and `ConsentType.adPersonalization`. +/// Omitting a type retains its previous status. +typedef NSString *FIRConsentType NS_TYPED_ENUM NS_SWIFT_NAME(ConsentType); + +/// Enables storage (such as device identifiers) related to advertising. +extern FIRConsentType const FIRConsentTypeAdStorage; + +/// Enables storage (such as app identifiers) related to analytics, e.g. visit duration. +extern FIRConsentType const FIRConsentTypeAnalyticsStorage; + +/// Sets consent for sending user data to Google for advertising purposes. +extern FIRConsentType const FIRConsentTypeAdUserData; + +/// Sets consent for personalized advertising. +extern FIRConsentType const FIRConsentTypeAdPersonalization; + +/// The status value of the consent type. Supported statuses are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. +typedef NSString *FIRConsentStatus NS_TYPED_ENUM NS_SWIFT_NAME(ConsentStatus); + +/// Consent status indicating consent is denied. For an overview of which data is sent when consent +/// is denied, see [SDK behavior with consent +/// mode](https://developers.google.com/tag-platform/security/concepts/consent-mode#tag-behavior). +extern FIRConsentStatus const FIRConsentStatusDenied; + +/// Consent status indicating consent is granted. +extern FIRConsentStatus const FIRConsentStatusGranted; + +/// Sets the applicable end user consent state. +@interface FIRAnalytics (Consent) + +/// Sets the applicable end user consent state (e.g. for device identifiers) for this app on this +/// device. Use the consent settings to specify individual consent type values. Settings are +/// persisted across app sessions. By default consent types are set to `ConsentStatus.granted`. +/// +/// @param consentSettings A Dictionary of consent types. Supported consent type keys are +/// `ConsentType.adStorage`, `ConsentType.analyticsStorage`, `ConsentType.adUserData`, and +/// `ConsentType.adPersonalization`. Valid values are `ConsentStatus.granted` and +/// `ConsentStatus.denied`. ++ (void)setConsent:(NSDictionary *)consentSettings; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h new file mode 100644 index 0000000..0bfec88 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics+OnDevice.h @@ -0,0 +1,44 @@ +#import + +#import "FIRAnalytics.h" + +NS_ASSUME_NONNULL_BEGIN + +API_UNAVAILABLE(macCatalyst, macos, tvos, watchos) +@interface FIRAnalytics (OnDevice) + +/// Initiates on-device conversion measurement given a user email address. Requires dependency +/// GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param emailAddress User email address. Include a domain name for all email addresses +/// (e.g. gmail.com or hotmail.co.jp). ++ (void)initiateOnDeviceConversionMeasurementWithEmailAddress:(NSString *)emailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(emailAddress:)); + +/// Initiates on-device conversion measurement given a phone number in E.164 format. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param phoneNumber User phone number. Must be in E.164 format, which means it must be +/// limited to a maximum of 15 digits and must include a plus sign (+) prefix and country code +/// with no dashes, parentheses, or spaces. ++ (void)initiateOnDeviceConversionMeasurementWithPhoneNumber:(NSString *)phoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(phoneNumber:)); + +/// Initiates on-device conversion measurement given a sha256-hashed user email address. Requires +/// dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a no-op. +/// @param hashedEmailAddress User email address as a UTF8-encoded string normalized and hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedEmailAddress:(NSData *)hashedEmailAddress + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedEmailAddress:)); + +/// Initiates on-device conversion measurement given a sha256-hashed phone number in E.164 format. +/// Requires dependency GoogleAppMeasurementOnDeviceConversion to be linked in, otherwise it is a +/// no-op. +/// @param hashedPhoneNumber UTF8-encoded user phone number in E.164 format and then hashed +/// according to the instructions at +/// https://firebase.google.com/docs/tutorials/ads-ios-on-device-measurement/step-3. ++ (void)initiateOnDeviceConversionMeasurementWithHashedPhoneNumber:(NSData *)hashedPhoneNumber + NS_SWIFT_NAME(initiateOnDeviceConversionMeasurement(hashedPhoneNumber:)); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h new file mode 100644 index 0000000..e58d7dd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRAnalytics.h @@ -0,0 +1,155 @@ +#import + +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The top level Firebase Analytics singleton that provides methods for logging events and setting +/// user properties. See the developer guides for general +/// information on using Firebase Analytics in your apps. +/// +/// @note The Analytics SDK uses SQLite to persist events and other app-specific data. Calling +/// certain thread-unsafe global SQLite methods like `sqlite3_shutdown()` can result in +/// unexpected crashes at runtime. +NS_SWIFT_NAME(Analytics) +@interface FIRAnalytics : NSObject + +/// Logs an app event. The event can have up to 25 parameters. Events with the same name must have +/// the same parameters. Up to 500 event names are supported. Using predefined events and/or +/// parameters is recommended for optimal reporting. +/// +/// The following event names are reserved and cannot be used: +///
    +///
  • ad_activeview
  • +///
  • ad_click
  • +///
  • ad_exposure
  • +///
  • ad_query
  • +///
  • ad_reward
  • +///
  • adunit_exposure
  • +///
  • app_clear_data
  • +///
  • app_exception
  • +///
  • app_remove
  • +///
  • app_store_refund
  • +///
  • app_store_subscription_cancel
  • +///
  • app_store_subscription_convert
  • +///
  • app_store_subscription_renew
  • +///
  • app_update
  • +///
  • app_upgrade
  • +///
  • dynamic_link_app_open
  • +///
  • dynamic_link_app_update
  • +///
  • dynamic_link_first_open
  • +///
  • error
  • +///
  • firebase_campaign
  • +///
  • first_open
  • +///
  • first_visit
  • +///
  • in_app_purchase
  • +///
  • notification_dismiss
  • +///
  • notification_foreground
  • +///
  • notification_open
  • +///
  • notification_receive
  • +///
  • os_update
  • +///
  • session_start
  • +///
  • session_start_with_rollout
  • +///
  • user_engagement
  • +///
+/// +/// @param name The name of the event. Should contain 1 to 40 alphanumeric characters or +/// underscores. The name must start with an alphabetic character. Some event names are +/// reserved. See FIREventNames.h for the list of reserved event names. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. Note that event names are +/// case-sensitive and that logging two events whose names differ only in case will result in +/// two distinct events. To manually log screen view events, use the `screen_view` event name. +/// @param parameters The dictionary of event parameters. Passing `nil` indicates that the event has +/// no parameters. Parameter names can be up to 40 characters long and must start with an +/// alphabetic character and contain only alphanumeric characters and underscores. Only String, +/// Int, and Double parameter types are supported. String parameter values can be up to 100 +/// characters long for standard Google Analytics properties, and up to 500 characters long for +/// Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are reserved +/// and should not be used for parameter names. ++ (void)logEventWithName:(NSString *)name + parameters:(nullable NSDictionary *)parameters + NS_SWIFT_NAME(logEvent(_:parameters:)); + +/// Sets a user property to a given value. Up to 25 user property names are supported. Once set, +/// user property values persist throughout the app lifecycle and across sessions. +/// +/// The following user property names are reserved and cannot be used: +///
    +///
  • first_open_time
  • +///
  • last_deep_link_referrer
  • +///
  • user_id
  • +///
+/// +/// @param value The value of the user property. Values can be up to 36 characters long. Setting the +/// value to `nil` removes the user property. +/// @param name The name of the user property to set. Should contain 1 to 24 alphanumeric characters +/// or underscores and must start with an alphabetic character. The "firebase_", "google_", and +/// "ga_" prefixes are reserved and should not be used for user property names. ++ (void)setUserPropertyString:(nullable NSString *)value forName:(NSString *)name + NS_SWIFT_NAME(setUserProperty(_:forName:)); + +/// Sets the user ID property. This feature must be used in accordance with +/// Google's Privacy Policy +/// +/// @param userID The user ID to ascribe to the user of this app on this device, which must be +/// non-empty and no more than 256 characters long. Setting userID to `nil` removes the user ID. ++ (void)setUserID:(nullable NSString *)userID; + +/// Sets whether analytics collection is enabled for this app on this device. This setting is +/// persisted across app sessions. By default it is enabled. +/// +/// @param analyticsCollectionEnabled A flag that enables or disables Analytics collection. ++ (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets the interval of inactivity in seconds that terminates the current session. The default +/// value is 1800 seconds (30 minutes). +/// +/// @param sessionTimeoutInterval The custom time of inactivity in seconds before the current +/// session terminates. ++ (void)setSessionTimeoutInterval:(NSTimeInterval)sessionTimeoutInterval; + +/// Asynchronously retrieves the identifier of the current app session. +/// +/// The session ID retrieval could fail due to Analytics collection disabled, app session expired, +/// etc. +/// +/// @param completion The completion handler to call when the session ID retrieval is complete. This +/// handler is executed on a system-defined global concurrent queue. +/// This completion handler takes the following parameters: +/// sessionID The identifier of the current app session. The value is undefined if the +/// request failed. +/// error An error object that indicates why the request failed, or `nil` if the request +/// was successful. ++ (void)sessionIDWithCompletion:(void (^)(int64_t sessionID, NSError *_Nullable error))completion; + +/// Returns the unique ID for this instance of the application or `nil` if +/// `ConsentType.analyticsStorage` has been set to `ConsentStatus.denied`. +/// +/// @see `FIRAnalytics+Consent.h` ++ (nullable NSString *)appInstanceID; + +/// Clears all analytics data for this instance from the device and resets the app instance ID. ++ (void)resetAnalyticsData; + +/// Adds parameters that will be set on every event logged from the SDK, including automatic ones. +/// The values passed in the parameters dictionary will be added to the dictionary of default event +/// parameters. These parameters persist across app runs. They are of lower precedence than event +/// parameters, so if an event parameter and a parameter set using this API have the same name, the +/// value of the event parameter will be used. The same limitations on event parameters apply to +/// default event parameters. +/// +/// @param parameters Parameters to be added to the dictionary of parameters added to every event. +/// They will be added to the dictionary of default event parameters, replacing any existing +/// parameter with the same name. Valid parameters are String, Int, and Double. Setting a key's +/// value to `NSNull()` will clear that parameter. Passing in a `nil` dictionary will clear all +/// parameters. ++ (void)setDefaultEventParameters:(nullable NSDictionary *)parameters; + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h new file mode 100644 index 0000000..1e69a44 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIREventNames.h @@ -0,0 +1,418 @@ +/// @file FIREventNames.h +/// +/// Predefined event names. +/// +/// An Event is an important occurrence in your app that you want to measure. You can report up to +/// 500 different types of Events per app and you can associate up to 25 unique parameters with each +/// Event type. Some common events are suggested below, but you may also choose to specify custom +/// Event types that are associated with your specific app. Each event type is identified by a +/// unique name. Event names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. The "firebase_", +/// "google_", and "ga_" prefixes are reserved and should not be used. + +#import + +/// Ad Impression event. This event signifies when a user sees an ad impression. Note: If you supply +/// the @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAdPlatform (String) (optional)
  • +///
  • @c AnalyticsParameterAdFormat (String) (optional)
  • +///
  • @c AnalyticsParameterAdSource (String) (optional)
  • +///
  • @c AnalyticsParameterAdUnitName (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAdImpression NS_SWIFT_NAME(AnalyticsEventAdImpression) = + @"ad_impression"; + +/// Add Payment Info event. This event signifies that a user has submitted their payment +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterPaymentType (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddPaymentInfo NS_SWIFT_NAME(AnalyticsEventAddPaymentInfo) = + @"add_payment_info"; + +/// Add Shipping Info event. This event signifies that a user has submitted their shipping +/// information. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShippingTier (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddShippingInfo NS_SWIFT_NAME(AnalyticsEventAddShippingInfo) = + @"add_shipping_info"; + +/// E-Commerce Add To Cart event. This event signifies that an item(s) was added to a cart for +/// purchase. Add this event to a funnel with @c AnalyticsEventPurchase to gauge the effectiveness +/// of your checkout process. Note: If you supply the @c AnalyticsParameterValue parameter, you must +/// also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToCart NS_SWIFT_NAME(AnalyticsEventAddToCart) = @"add_to_cart"; + +/// E-Commerce Add To Wishlist event. This event signifies that an item was added to a wishlist. Use +/// this event to identify popular gift items. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventAddToWishlist NS_SWIFT_NAME(AnalyticsEventAddToWishlist) = + @"add_to_wishlist"; + +/// App Open event. By logging this event when an App becomes active, developers can understand how +/// often users leave and return during the course of a Session. Although Sessions are automatically +/// reported, this event can provide further clarification around the continuous engagement of +/// app-users. +static NSString *const kFIREventAppOpen NS_SWIFT_NAME(AnalyticsEventAppOpen) = @"app_open"; + +/// E-Commerce Begin Checkout event. This event signifies that a user has begun the process of +/// checking out. Add this event to a funnel with your @c AnalyticsEventPurchase event to gauge the +/// effectiveness of your checkout process. Note: If you supply the @c AnalyticsParameterValue +/// parameter, you must also supply the @c AnalyticsParameterCurrency parameter so that revenue +/// metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventBeginCheckout NS_SWIFT_NAME(AnalyticsEventBeginCheckout) = + @"begin_checkout"; + +/// Campaign Detail event. Log this event to supply the referral details of a re-engagement +/// campaign. Note: you must supply at least one of the required parameters +/// AnalyticsParameterSource, AnalyticsParameterMedium or AnalyticsParameterCampaign. Params: +/// +///
    +///
  • @c AnalyticsParameterSource (String)
  • +///
  • @c AnalyticsParameterMedium (String)
  • +///
  • @c AnalyticsParameterCampaign (String)
  • +///
  • @c AnalyticsParameterTerm (String) (optional)
  • +///
  • @c AnalyticsParameterContent (String) (optional)
  • +///
  • @c AnalyticsParameterAdNetworkClickID (String) (optional)
  • +///
  • @c AnalyticsParameterCP1 (String) (optional)
  • +///
  • @c AnalyticsParameterCampaignID (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeFormat (String) (optional)
  • +///
  • @c AnalyticsParameterMarketingTactic (String) (optional)
  • +///
  • @c AnalyticsParameterSourcePlatform (String) (optional)
  • +///
+static NSString *const kFIREventCampaignDetails NS_SWIFT_NAME(AnalyticsEventCampaignDetails) = + @"campaign_details"; + +/// Earn Virtual Currency event. This event tracks the awarding of virtual currency in your app. Log +/// this along with @c AnalyticsEventSpendVirtualCurrency to better understand your virtual economy. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventEarnVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventEarnVirtualCurrency) = @"earn_virtual_currency"; + +/// Generate Lead event. Log this event when a lead has been generated in the app to understand the +/// efficacy of your install and re-engagement campaigns. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventGenerateLead NS_SWIFT_NAME(AnalyticsEventGenerateLead) = + @"generate_lead"; + +/// Join Group event. Log this event when a user joins a group such as a guild, team or family. Use +/// this event to analyze how popular certain groups or social features are in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterGroupID (String)
  • +///
+static NSString *const kFIREventJoinGroup NS_SWIFT_NAME(AnalyticsEventJoinGroup) = @"join_group"; + +/// Level End event. Log this event when the user finishes a level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
  • @c AnalyticsParameterSuccess (String)
  • +///
+static NSString *const kFIREventLevelEnd NS_SWIFT_NAME(AnalyticsEventLevelEnd) = @"level_end"; + +/// Level Start event. Log this event when the user starts a new level. Params: +/// +///
    +///
  • @c AnalyticsParameterLevelName (String)
  • +///
+static NSString *const kFIREventLevelStart NS_SWIFT_NAME(AnalyticsEventLevelStart) = @"level_start"; + +/// Level Up event. This event signifies that a player has leveled up in your gaming app. It can +/// help you gauge the level distribution of your userbase and help you identify certain levels that +/// are difficult to pass. Params: +/// +///
    +///
  • @c AnalyticsParameterLevel (Int)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventLevelUp NS_SWIFT_NAME(AnalyticsEventLevelUp) = @"level_up"; + +/// Login event. Apps with a login feature can report this event to signify that a user has logged +/// in. +static NSString *const kFIREventLogin NS_SWIFT_NAME(AnalyticsEventLogin) = @"login"; + +/// Post Score event. Log this event when the user posts a score in your gaming app. This event can +/// help you understand how users are actually performing in your game and it can help you correlate +/// high scores with certain audiences or behaviors. Params: +/// +///
    +///
  • @c AnalyticsParameterScore (Int)
  • +///
  • @c AnalyticsParameterLevel (Int) (optional)
  • +///
  • @c AnalyticsParameterCharacter (String) (optional)
  • +///
+static NSString *const kFIREventPostScore NS_SWIFT_NAME(AnalyticsEventPostScore) = @"post_score"; + +/// E-Commerce Purchase event. This event signifies that an item(s) was purchased by a user. Note: +/// This is different from the in-app purchase event, which is reported automatically for App +/// Store-based apps. Note: If you supply the @c AnalyticsParameterValue parameter, you must also +/// supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed +/// accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterItemID (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventPurchase NS_SWIFT_NAME(AnalyticsEventPurchase) = @"purchase"; + +/// E-Commerce Refund event. This event signifies that a refund was issued. Note: If you supply the +/// @c AnalyticsParameterValue parameter, you must also supply the @c AnalyticsParameterCurrency +/// parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterAffiliation (String) (optional)
  • +///
  • @c AnalyticsParameterCoupon (String) (optional)
  • +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterShipping (Double) (optional)
  • +///
  • @c AnalyticsParameterTax (Double) (optional)
  • +///
  • @c AnalyticsParameterTransactionID (String) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRefund NS_SWIFT_NAME(AnalyticsEventRefund) = @"refund"; + +/// E-Commerce Remove from Cart event. This event signifies that an item(s) was removed from a cart. +/// Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply the @c +/// AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventRemoveFromCart NS_SWIFT_NAME(AnalyticsEventRemoveFromCart) = + @"remove_from_cart"; + +/// Screen View event. This event signifies a screen view. Use this when a screen transition occurs. +/// This event can be logged irrespective of whether automatic screen tracking is enabled. Params: +/// +///
    +///
  • @c AnalyticsParameterScreenClass (String) (optional)
  • +///
  • @c AnalyticsParameterScreenName (String) (optional)
  • +///
+static NSString *const kFIREventScreenView NS_SWIFT_NAME(AnalyticsEventScreenView) = @"screen_view"; + +/// Search event. Apps that support search features can use this event to contextualize search +/// operations by supplying the appropriate, corresponding parameters. This event can help you +/// identify the most popular content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
  • @c AnalyticsParameterStartDate (String) (optional)
  • +///
  • @c AnalyticsParameterEndDate (String) (optional)
  • +///
  • @c AnalyticsParameterNumberOfNights (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfRooms (Int) (optional) for hotel bookings
  • +///
  • @c AnalyticsParameterNumberOfPassengers (Int) (optional) for travel bookings
  • +///
  • @c AnalyticsParameterOrigin (String) (optional)
  • +///
  • @c AnalyticsParameterDestination (String) (optional)
  • +///
  • @c AnalyticsParameterTravelClass (String) (optional) for travel bookings
  • +///
+static NSString *const kFIREventSearch NS_SWIFT_NAME(AnalyticsEventSearch) = @"search"; + +/// Select Content event. This general purpose event signifies that a user has selected some content +/// of a certain type in an app. The content can be any object in your app. This event can help you +/// identify popular content and categories of content in your app. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventSelectContent NS_SWIFT_NAME(AnalyticsEventSelectContent) = + @"select_content"; + +/// Select Item event. This event signifies that an item was selected by a user from a list. Use the +/// appropriate parameters to contextualize the event. Use this event to discover the most popular +/// items selected. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventSelectItem NS_SWIFT_NAME(AnalyticsEventSelectItem) = @"select_item"; + +/// Select promotion event. This event signifies that a user has selected a promotion offer. Use the +/// appropriate parameters to contextualize the event, such as the item(s) for which the promotion +/// applies. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventSelectPromotion NS_SWIFT_NAME(AnalyticsEventSelectPromotion) = + @"select_promotion"; + +/// Share event. Apps with social features can log the Share event to identify the most viral +/// content. Params: +/// +///
    +///
  • @c AnalyticsParameterContentType (String)
  • +///
  • @c AnalyticsParameterItemID (String)
  • +///
+static NSString *const kFIREventShare NS_SWIFT_NAME(AnalyticsEventShare) = @"share"; + +/// Sign Up event. This event indicates that a user has signed up for an account in your app. The +/// parameter signifies the method by which the user signed up. Use this event to understand the +/// different behaviors between logged in and logged out users. Params: +/// +///
    +///
  • @c AnalyticsParameterMethod (String)
  • +///
+static NSString *const kFIREventSignUp NS_SWIFT_NAME(AnalyticsEventSignUp) = @"sign_up"; + +/// Spend Virtual Currency event. This event tracks the sale of virtual goods in your app and can +/// help you identify which virtual goods are the most popular objects of purchase. Params: +/// +///
    +///
  • @c AnalyticsParameterItemName (String)
  • +///
  • @c AnalyticsParameterVirtualCurrencyName (String)
  • +///
  • @c AnalyticsParameterValue (Int or Double)
  • +///
+static NSString *const kFIREventSpendVirtualCurrency + NS_SWIFT_NAME(AnalyticsEventSpendVirtualCurrency) = @"spend_virtual_currency"; + +/// Tutorial Begin event. This event signifies the start of the on-boarding process in your app. Use +/// this in a funnel with @c AnalyticsEventTutorialComplete to understand how many users complete +/// this process and move on to the full app experience. +static NSString *const kFIREventTutorialBegin NS_SWIFT_NAME(AnalyticsEventTutorialBegin) = + @"tutorial_begin"; + +/// Tutorial End event. Use this event to signify the user's completion of your app's on-boarding +/// process. Add this to a funnel with @c AnalyticsEventTutorialBegin to gauge the completion rate +/// of your on-boarding process. +static NSString *const kFIREventTutorialComplete NS_SWIFT_NAME(AnalyticsEventTutorialComplete) = + @"tutorial_complete"; + +/// Unlock Achievement event. Log this event when the user has unlocked an achievement in your +/// game. Since achievements generally represent the breadth of a gaming experience, this event can +/// help you understand how many users are experiencing all that your game has to offer. Params: +/// +///
    +///
  • @c AnalyticsParameterAchievementID (String)
  • +///
+static NSString *const kFIREventUnlockAchievement NS_SWIFT_NAME(AnalyticsEventUnlockAchievement) = + @"unlock_achievement"; + +/// E-commerce View Cart event. This event signifies that a user has viewed their cart. Use this to +/// analyze your purchase funnel. Note: If you supply the @c AnalyticsParameterValue parameter, you +/// must also supply the @c AnalyticsParameterCurrency parameter so that revenue metrics can be +/// computed accurately. Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewCart NS_SWIFT_NAME(AnalyticsEventViewCart) = @"view_cart"; + +/// View Item event. This event signifies that a user has viewed an item. Use the appropriate +/// parameters to contextualize the event. Use this event to discover the most popular items viewed +/// in your app. Note: If you supply the @c AnalyticsParameterValue parameter, you must also supply +/// the @c AnalyticsParameterCurrency parameter so that revenue metrics can be computed accurately. +/// Params: +/// +///
    +///
  • @c AnalyticsParameterCurrency (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterValue (Double) (optional)
  • +///
+static NSString *const kFIREventViewItem NS_SWIFT_NAME(AnalyticsEventViewItem) = @"view_item"; + +/// View Item List event. Log this event when a user sees a list of items or offerings. Params: +/// +///
    +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterItemListID (String) (optional)
  • +///
  • @c AnalyticsParameterItemListName (String) (optional)
  • +///
+static NSString *const kFIREventViewItemList NS_SWIFT_NAME(AnalyticsEventViewItemList) = + @"view_item_list"; + +/// View Promotion event. This event signifies that a promotion was shown to a user. Add this event +/// to a funnel with the @c AnalyticsEventAddToCart and @c AnalyticsEventPurchase to gauge your +/// conversion process. Params: +/// +///
    +///
  • @c AnalyticsParameterCreativeName (String) (optional)
  • +///
  • @c AnalyticsParameterCreativeSlot (String) (optional)
  • +///
  • @c AnalyticsParameterItems ([[String: Any]]) (optional)
  • +///
  • @c AnalyticsParameterLocationID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionID (String) (optional)
  • +///
  • @c AnalyticsParameterPromotionName (String) (optional)
  • +///
+static NSString *const kFIREventViewPromotion NS_SWIFT_NAME(AnalyticsEventViewPromotion) = + @"view_promotion"; + +/// View Search Results event. Log this event when the user has been presented with the results of a +/// search. Params: +/// +///
    +///
  • @c AnalyticsParameterSearchTerm (String)
  • +///
+static NSString *const kFIREventViewSearchResults NS_SWIFT_NAME(AnalyticsEventViewSearchResults) = + @"view_search_results"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h new file mode 100644 index 0000000..58a5a21 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRParameterNames.h @@ -0,0 +1,722 @@ +/// @file FIRParameterNames.h +/// +/// Predefined event parameter names. +/// +/// Params supply information that contextualize Events. You can associate up to 25 unique Params +/// with each Event type. Some Params are suggested below for certain common Events, but you are +/// not limited to these. You may supply extra Params for suggested Events or custom Params for +/// Custom events. Param names can be up to 40 characters long, may only contain alphanumeric +/// characters and underscores ("_"), and must start with an alphabetic character. Param values can +/// be up to 100 characters long for standard Google Analytics properties and up to 500 characters +/// long for Google Analytics 360 properties. The "firebase_", "google_", and "ga_" prefixes are +/// reserved and should not be used. + +#import + +/// Game achievement ID (String). +///
+///     let params = [
+///       AnalyticsParameterAchievementID : "10_matches_won",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAchievementID NS_SWIFT_NAME(AnalyticsParameterAchievementID) = + @"achievement_id"; + +/// The ad format (e.g. Banner, Interstitial, Rewarded, Native, Rewarded Interstitial, Instream). +/// (String). +///
+///     let params = [
+///       AnalyticsParameterAdFormat : "Banner",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdFormat NS_SWIFT_NAME(AnalyticsParameterAdFormat) = + @"ad_format"; + +/// Ad Network Click ID (String). Used for network-specific click IDs which vary in format. +///
+///     let params = [
+///       AnalyticsParameterAdNetworkClickID : "1234567",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdNetworkClickID + NS_SWIFT_NAME(AnalyticsParameterAdNetworkClickID) = @"aclid"; + +/// The ad platform (e.g. MoPub, IronSource) (String). +///
+///     let params = [
+///       AnalyticsParameterAdPlatform : "MoPub",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdPlatform NS_SWIFT_NAME(AnalyticsParameterAdPlatform) = + @"ad_platform"; + +/// The ad source (e.g. AdColony) (String). +///
+///     let params = [
+///       AnalyticsParameterAdSource : "AdColony",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdSource NS_SWIFT_NAME(AnalyticsParameterAdSource) = + @"ad_source"; + +/// The ad unit name (e.g. Banner_03) (String). +///
+///     let params = [
+///       AnalyticsParameterAdUnitName : "Banner_03",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAdUnitName NS_SWIFT_NAME(AnalyticsParameterAdUnitName) = + @"ad_unit_name"; + +/// A product affiliation to designate a supplying company or brick and mortar store location +/// (String).
+///     let params = [
+///       AnalyticsParameterAffiliation : "Google Store",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterAffiliation NS_SWIFT_NAME(AnalyticsParameterAffiliation) = + @"affiliation"; + +/// Campaign custom parameter (String). Used as a method of capturing custom data in a campaign. +/// Use varies by network. +///
+///     let params = [
+///       AnalyticsParameterCP1 : "custom_data",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCP1 NS_SWIFT_NAME(AnalyticsParameterCP1) = @"cp1"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Campaign ID (String). Used for keyword analysis to identify a specific product promotion or +/// strategic campaign. This is a required key for GA4 data import. +///
+///     let params = [
+///       AnalyticsParameterCampaignID : "7877652710",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCampaignID NS_SWIFT_NAME(AnalyticsParameterCampaignID) = + @"campaign_id"; + +/// Character used in game (String). +///
+///     let params = [
+///       AnalyticsParameterCharacter : "beat_boss",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCharacter NS_SWIFT_NAME(AnalyticsParameterCharacter) = + @"character"; + +/// Campaign content (String). +static NSString *const kFIRParameterContent NS_SWIFT_NAME(AnalyticsParameterContent) = @"content"; + +/// Type of content selected (String). +///
+///     let params = [
+///       AnalyticsParameterContentType : "news article",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterContentType NS_SWIFT_NAME(AnalyticsParameterContentType) = + @"content_type"; + +/// Coupon code used for a purchase (String). +///
+///     let params = [
+///       AnalyticsParameterCoupon : "SUMMER_FUN",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCoupon NS_SWIFT_NAME(AnalyticsParameterCoupon) = @"coupon"; + +/// Creative Format (String). Used to identify the high-level classification of the type of ad +/// served by a specific campaign. +///
+///     let params = [
+///       AnalyticsParameterCreativeFormat : "display",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeFormat NS_SWIFT_NAME(AnalyticsParameterCreativeFormat) = + @"creative_format"; + +/// The name of a creative used in a promotional spot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeName NS_SWIFT_NAME(AnalyticsParameterCreativeName) = + @"creative_name"; + +/// The name of a creative slot (String). +///
+///     let params = [
+///       AnalyticsParameterCreativeSlot : "summer_banner2",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCreativeSlot NS_SWIFT_NAME(AnalyticsParameterCreativeSlot) = + @"creative_slot"; + +/// Currency of the purchase or items associated with the event, in 3-letter +/// ISO_4217 format (String). +///
+///     let params = [
+///       AnalyticsParameterCurrency : "USD",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterCurrency NS_SWIFT_NAME(AnalyticsParameterCurrency) = + @"currency"; + +/// Flight or Travel destination (String). +///
+///     let params = [
+///       AnalyticsParameterDestination : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDestination NS_SWIFT_NAME(AnalyticsParameterDestination) = + @"destination"; + +/// Monetary value of discount associated with a purchase (Double). +///
+///     let params = [
+///       AnalyticsParameterDiscount : 2.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterDiscount NS_SWIFT_NAME(AnalyticsParameterDiscount) = + @"discount"; + +/// The arrival date, check-out date or rental end date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterEndDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterEndDate NS_SWIFT_NAME(AnalyticsParameterEndDate) = @"end_date"; + +/// Indicates that the associated event should either extend the current session or start a new +/// session if no session was active when the event was logged. Specify 1 to extend the current +/// session or to start a new session; any other value will not extend or start a session. +///
+///     let params = [
+///       AnalyticsParameterExtendSession : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterExtendSession NS_SWIFT_NAME(AnalyticsParameterExtendSession) = + @"extend_session"; + +/// Flight number for travel events (String). +///
+///     let params = [
+///       AnalyticsParameterFlightNumber : "ZZ800",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterFlightNumber NS_SWIFT_NAME(AnalyticsParameterFlightNumber) = + @"flight_number"; + +/// Group/clan/guild ID (String). +///
+///     let params = [
+///       AnalyticsParameterGroupID : "g1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterGroupID NS_SWIFT_NAME(AnalyticsParameterGroupID) = @"group_id"; + +/// The index of the item in a list (Int). +///
+///     let params = [
+///       AnalyticsParameterIndex : 5,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterIndex NS_SWIFT_NAME(AnalyticsParameterIndex) = @"index"; + +/// Item brand (String). +///
+///     let params = [
+///       AnalyticsParameterItemBrand : "Google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemBrand NS_SWIFT_NAME(AnalyticsParameterItemBrand) = + @"item_brand"; + +/// Item category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory NS_SWIFT_NAME(AnalyticsParameterItemCategory) = + @"item_category"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory2 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory2 NS_SWIFT_NAME(AnalyticsParameterItemCategory2) = + @"item_category2"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory3 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory3 NS_SWIFT_NAME(AnalyticsParameterItemCategory3) = + @"item_category3"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory4 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory4 NS_SWIFT_NAME(AnalyticsParameterItemCategory4) = + @"item_category4"; + +/// Item Category (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemCategory5 : "pants",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemCategory5 NS_SWIFT_NAME(AnalyticsParameterItemCategory5) = + @"item_category5"; + +/// Item ID (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemID : "SKU_12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemID NS_SWIFT_NAME(AnalyticsParameterItemID) = @"item_id"; + +/// The ID of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListID NS_SWIFT_NAME(AnalyticsParameterItemListID) = + @"item_list_id"; + +/// The name of the list in which the item was presented to the user (String). +///
+///     let params = [
+///       AnalyticsParameterItemListName : "Related products",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemListName NS_SWIFT_NAME(AnalyticsParameterItemListName) = + @"item_list_name"; + +/// Item Name (context-specific) (String). +///
+///     let params = [
+///       AnalyticsParameterItemName : "jeggings",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemName NS_SWIFT_NAME(AnalyticsParameterItemName) = + @"item_name"; + +/// Item variant (String). +///
+///     let params = [
+///       AnalyticsParameterItemVariant : "Black",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterItemVariant NS_SWIFT_NAME(AnalyticsParameterItemVariant) = + @"item_variant"; + +/// The list of items involved in the transaction expressed as `[[String: Any]]`. +///
+///     let params = [
+///       AnalyticsParameterItems : [
+///         [AnalyticsParameterItemName : "jeggings", AnalyticsParameterItemCategory : "pants"],
+///         [AnalyticsParameterItemName : "boots", AnalyticsParameterItemCategory : "shoes"],
+///       ],
+///     ]
+/// 
+static NSString *const kFIRParameterItems NS_SWIFT_NAME(AnalyticsParameterItems) = @"items"; + +/// Level in game (Int). +///
+///     let params = [
+///       AnalyticsParameterLevel : 42,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevel NS_SWIFT_NAME(AnalyticsParameterLevel) = @"level"; + +/// The name of a level in a game (String). +///
+///     let params = [
+///       AnalyticsParameterLevelName : "room_1",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLevelName NS_SWIFT_NAME(AnalyticsParameterLevelName) = + @"level_name"; + +/// Location (String). The Google Place ID +/// that corresponds to the associated event. Alternatively, you can supply your own custom +/// Location ID. +///
+///     let params = [
+///       AnalyticsParameterLocation : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocation NS_SWIFT_NAME(AnalyticsParameterLocation) = + @"location"; + +/// The location associated with the event. Preferred to be the Google +/// Place ID that corresponds to the +/// associated item but could be overridden to a custom location ID string.(String). +///
+///     let params = [
+///       AnalyticsParameterLocationID : "ChIJiyj437sx3YAR9kUWC8QkLzQ",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterLocationID NS_SWIFT_NAME(AnalyticsParameterLocationID) = + @"location_id"; + +/// Marketing Tactic (String). Used to identify the targeting criteria applied to a specific +/// campaign. +///
+///     let params = [
+///       AnalyticsParameterMarketingTactic : "Remarketing",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMarketingTactic + NS_SWIFT_NAME(AnalyticsParameterMarketingTactic) = @"marketing_tactic"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       AnalyticsParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// A particular approach used in an operation; for example, "facebook" or "email" in the context +/// of a sign_up or login event. (String). +///
+///     let params = [
+///       AnalyticsParameterMethod : "google",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterMethod NS_SWIFT_NAME(AnalyticsParameterMethod) = @"method"; + +/// Number of nights staying at hotel (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfNights : 3,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfNights + NS_SWIFT_NAME(AnalyticsParameterNumberOfNights) = @"number_of_nights"; + +/// Number of passengers traveling (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfPassengers : 11,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfPassengers + NS_SWIFT_NAME(AnalyticsParameterNumberOfPassengers) = @"number_of_passengers"; + +/// Number of rooms for travel events (Int). +///
+///     let params = [
+///       AnalyticsParameterNumberOfRooms : 2,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterNumberOfRooms NS_SWIFT_NAME(AnalyticsParameterNumberOfRooms) = + @"number_of_rooms"; + +/// Flight or Travel origin (String). +///
+///     let params = [
+///       AnalyticsParameterOrigin : "Mountain View, CA",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterOrigin NS_SWIFT_NAME(AnalyticsParameterOrigin) = @"origin"; + +/// The chosen method of payment (String). +///
+///     let params = [
+///       AnalyticsParameterPaymentType : "Visa",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPaymentType NS_SWIFT_NAME(AnalyticsParameterPaymentType) = + @"payment_type"; + +/// Purchase price (Double). +///
+///     let params = [
+///       AnalyticsParameterPrice : 1.0,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $1.00 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPrice NS_SWIFT_NAME(AnalyticsParameterPrice) = @"price"; + +/// The ID of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionID : "ABC123",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionID NS_SWIFT_NAME(AnalyticsParameterPromotionID) = + @"promotion_id"; + +/// The name of a product promotion (String). +///
+///     let params = [
+///       AnalyticsParameterPromotionName : "Summer Sale",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterPromotionName NS_SWIFT_NAME(AnalyticsParameterPromotionName) = + @"promotion_name"; + +/// Purchase quantity (Int). +///
+///     let params = [
+///       AnalyticsParameterQuantity : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterQuantity NS_SWIFT_NAME(AnalyticsParameterQuantity) = + @"quantity"; + +/// Score in game (Int). +///
+///     let params = [
+///       AnalyticsParameterScore : 4200,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScore NS_SWIFT_NAME(AnalyticsParameterScore) = @"score"; + +/// Current screen class, such as the class name of the UIViewController, logged with screen_view +/// event and added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenClass : "LoginViewController",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenClass NS_SWIFT_NAME(AnalyticsParameterScreenClass) = + @"screen_class"; + +/// Current screen name, such as the name of the UIViewController, logged with screen_view event and +/// added to every event (String). +///
+///     let params = [
+///       AnalyticsParameterScreenName : "LoginView",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterScreenName NS_SWIFT_NAME(AnalyticsParameterScreenName) = + @"screen_name"; + +/// The search string/keywords used (String). +///
+///     let params = [
+///       AnalyticsParameterSearchTerm : "periodic table",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSearchTerm NS_SWIFT_NAME(AnalyticsParameterSearchTerm) = + @"search_term"; + +/// Shipping cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterShipping : 5.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $5.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShipping NS_SWIFT_NAME(AnalyticsParameterShipping) = + @"shipping"; + +/// The shipping tier (e.g. Ground, Air, Next-day) selected for delivery of the purchased item +/// (String). +///
+///     let params = [
+///       AnalyticsParameterShippingTier : "Ground",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterShippingTier NS_SWIFT_NAME(AnalyticsParameterShippingTier) = + @"shipping_tier"; + +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       AnalyticsParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// Source Platform (String). Used to identify the platform responsible for directing traffic to a +/// given Analytics property (e.g., a buying platform where budgets, targeting criteria, etc. are +/// set, a platform for managing organic traffic data, etc.). +///
+///     let params = [
+///       AnalyticsParameterSourcePlatform : "sa360",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSourcePlatform NS_SWIFT_NAME(AnalyticsParameterSourcePlatform) = + @"source_platform"; + +/// The departure date, check-in date or rental start date for the item. This should be in +/// YYYY-MM-DD format (String). +///
+///     let params = [
+///       AnalyticsParameterStartDate : "2015-09-14",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterStartDate NS_SWIFT_NAME(AnalyticsParameterStartDate) = + @"start_date"; + +/// The result of an operation. Specify 1 to indicate success and 0 to indicate failure (Int). +///
+///     let params = [
+///       AnalyticsParameterSuccess : 1,
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterSuccess NS_SWIFT_NAME(AnalyticsParameterSuccess) = @"success"; + +/// Tax cost associated with a transaction (Double). +///
+///     let params = [
+///       AnalyticsParameterTax : 2.43,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $2.43 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTax NS_SWIFT_NAME(AnalyticsParameterTax) = @"tax"; + +/// If you're manually tagging keyword campaigns, you should use utm_term to specify the keyword +/// (String). +///
+///     let params = [
+///       AnalyticsParameterTerm : "game",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTerm NS_SWIFT_NAME(AnalyticsParameterTerm) = @"term"; + +/// The unique identifier of a transaction (String). +///
+///     let params = [
+///       AnalyticsParameterTransactionID : "T12345",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTransactionID NS_SWIFT_NAME(AnalyticsParameterTransactionID) = + @"transaction_id"; + +/// Travel class (String). +///
+///     let params = [
+///       AnalyticsParameterTravelClass : "business",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterTravelClass NS_SWIFT_NAME(AnalyticsParameterTravelClass) = + @"travel_class"; + +/// A context-specific numeric value which is accumulated automatically for each event type. This is +/// a general purpose parameter that is useful for accumulating a key metric that pertains to an +/// event. Examples include revenue, distance, time and points. Value should be specified as Int or +/// Double. +/// Notes: Values for pre-defined currency-related events (such as @c AnalyticsEventAddToCart) +/// should be supplied using Double and must be accompanied by a @c AnalyticsParameterCurrency +/// parameter. The valid range of accumulated values is +/// [-9,223,372,036,854.77, 9,223,372,036,854.77]. Supplying a non-numeric value, omitting the +/// corresponding @c AnalyticsParameterCurrency parameter, or supplying an invalid +/// currency code for conversion events will cause that +/// conversion to be omitted from reporting. +///
+///     let params = [
+///       AnalyticsParameterValue : 3.99,
+///       AnalyticsParameterCurrency : "USD",  // e.g. $3.99 USD
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterValue NS_SWIFT_NAME(AnalyticsParameterValue) = @"value"; + +/// Name of virtual currency type (String). +///
+///     let params = [
+///       AnalyticsParameterVirtualCurrencyName : "virtual_currency_name",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRParameterVirtualCurrencyName + NS_SWIFT_NAME(AnalyticsParameterVirtualCurrencyName) = @"virtual_currency_name"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h new file mode 100644 index 0000000..2442d8a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FIRUserPropertyNames.h @@ -0,0 +1,28 @@ +/// @file FIRUserPropertyNames.h +/// +/// Predefined user property names. +/// +/// A UserProperty is an attribute that describes the app-user. By supplying UserProperties, you can +/// later analyze different behaviors of various segments of your userbase. You may supply up to 25 +/// unique UserProperties per app, and you can use the name and value of your choosing for each one. +/// UserProperty names can be up to 24 characters long, may only contain alphanumeric characters and +/// underscores ("_"), and must start with an alphabetic character. UserProperty values can be up to +/// 36 characters long. The "firebase_", "google_", and "ga_" prefixes are reserved and should not +/// be used. + +#import + +/// Indicates whether events logged by Google Analytics can be used to personalize ads for the user. +/// Set to "YES" to enable, or "NO" to disable. Default is enabled. See the +/// documentation for +/// more details and information about related settings. +/// +///
+///     Analytics.setUserProperty("NO", forName: AnalyticsUserPropertyAllowAdPersonalizationSignals)
+/// 
+static NSString *const kFIRUserPropertyAllowAdPersonalizationSignals + NS_SWIFT_NAME(AnalyticsUserPropertyAllowAdPersonalizationSignals) = @"allow_personalized_ads"; + +/// The method used to sign in. For example, "google", "facebook" or "twitter". +static NSString *const kFIRUserPropertySignUpMethod + NS_SWIFT_NAME(AnalyticsUserPropertySignUpMethod) = @"sign_up_method"; diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h new file mode 100644 index 0000000..3dbf01a --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-Swift.h @@ -0,0 +1,620 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +#ifndef FIREBASEANALYTICS_SWIFT_H +#define FIREBASEANALYTICS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#if defined(__OBJC__) +#include +#endif +#if defined(__cplusplus) +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#include +#endif +#if defined(__cplusplus) +#if defined(__arm64e__) && __has_include() +# include +#else +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-macro-identifier" +# ifndef __ptrauth_swift_value_witness_function_pointer +# define __ptrauth_swift_value_witness_function_pointer(x) +# endif +# ifndef __ptrauth_swift_class_method_pointer +# define __ptrauth_swift_class_method_pointer(x) +# endif +#pragma clang diagnostic pop +#endif +#endif + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif +#if !defined(SWIFT_RUNTIME_NAME) +# if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +# else +# define SWIFT_RUNTIME_NAME(X) +# endif +#endif +#if !defined(SWIFT_COMPILE_NAME) +# if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +# else +# define SWIFT_COMPILE_NAME(X) +# endif +#endif +#if !defined(SWIFT_METHOD_FAMILY) +# if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +# else +# define SWIFT_METHOD_FAMILY(X) +# endif +#endif +#if !defined(SWIFT_NOESCAPE) +# if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +# else +# define SWIFT_NOESCAPE +# endif +#endif +#if !defined(SWIFT_RELEASES_ARGUMENT) +# if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +# else +# define SWIFT_RELEASES_ARGUMENT +# endif +#endif +#if !defined(SWIFT_WARN_UNUSED_RESULT) +# if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +# else +# define SWIFT_WARN_UNUSED_RESULT +# endif +#endif +#if !defined(SWIFT_NORETURN) +# if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +# else +# define SWIFT_NORETURN +# endif +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if !defined(SWIFT_DEPRECATED_OBJC) +# if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +# else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +# endif +#endif +#if defined(__OBJC__) +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#endif +#if !defined(SWIFT_EXTERN) +# if defined(__cplusplus) +# define SWIFT_EXTERN extern "C" +# else +# define SWIFT_EXTERN extern +# endif +#endif +#if !defined(SWIFT_CALL) +# define SWIFT_CALL __attribute__((swiftcall)) +#endif +#if !defined(SWIFT_INDIRECT_RESULT) +# define SWIFT_INDIRECT_RESULT __attribute__((swift_indirect_result)) +#endif +#if !defined(SWIFT_CONTEXT) +# define SWIFT_CONTEXT __attribute__((swift_context)) +#endif +#if !defined(SWIFT_ERROR_RESULT) +# define SWIFT_ERROR_RESULT __attribute__((swift_error_result)) +#endif +#if defined(__cplusplus) +# define SWIFT_NOEXCEPT noexcept +#else +# define SWIFT_NOEXCEPT +#endif +#if !defined(SWIFT_C_INLINE_THUNK) +# if __has_attribute(always_inline) +# if __has_attribute(nodebug) +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) __attribute__((nodebug)) +# else +# define SWIFT_C_INLINE_THUNK inline __attribute__((always_inline)) +# endif +# else +# define SWIFT_C_INLINE_THUNK inline +# endif +#endif +#if defined(_WIN32) +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL __declspec(dllimport) +#endif +#else +#if !defined(SWIFT_IMPORT_STDLIB_SYMBOL) +# define SWIFT_IMPORT_STDLIB_SYMBOL +#endif +#endif +#if defined(__OBJC__) +#if __has_feature(objc_modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#endif +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" +#pragma clang diagnostic ignored "-Wdollar-in-identifier-extension" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="FirebaseAnalytics",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + +#if defined(__OBJC__) + +#endif +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#if defined(__cplusplus) +#endif +#pragma clang diagnostic pop +#endif + +#else +#error unsupported Swift architecture +#endif diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h new file mode 100644 index 0000000..ad84fbb --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics-umbrella.h @@ -0,0 +1,24 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FirebaseAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" + +FOUNDATION_EXPORT double FirebaseAnalyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseAnalyticsVersionString[]; + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h new file mode 100644 index 0000000..351da20 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Headers/FirebaseAnalytics.h @@ -0,0 +1,7 @@ +#import "FIRAnalytics+AppDelegate.h" +#import "FIRAnalytics+Consent.h" +#import "FIRAnalytics+OnDevice.h" +#import "FIRAnalytics.h" +#import "FIREventNames.h" +#import "FIRParameterNames.h" +#import "FIRUserPropertyNames.h" diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist new file mode 100644 index 0000000..6a51dbd --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + FirebaseAnalytics + CFBundleIdentifier + org.cocoapods.FirebaseAnalytics + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + FirebaseAnalytics + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvsimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvsimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos-simulator.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos-simulator.swiftsourceinfo new file mode 100644 index 0000000..10bf057 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/arm64-apple-tvos-simulator.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-tvos-simulator.swiftsourceinfo b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-tvos-simulator.swiftsourceinfo new file mode 100644 index 0000000..7c406b6 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/Project/x86_64-apple-tvos-simulator.swiftsourceinfo differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.private.swiftinterface new file mode 100644 index 0000000..4f9c398 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-tvos13.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftdoc new file mode 100644 index 0000000..389577d Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftinterface new file mode 100644 index 0000000..4f9c398 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/arm64-apple-tvos-simulator.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target arm64-apple-tvos13.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.abi.json b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.abi.json new file mode 100644 index 0000000..665fe28 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.abi.json @@ -0,0 +1,288 @@ +{ + "ABIRoot": { + "kind": "Root", + "name": "TopLevel", + "printedName": "TopLevel", + "children": [ + { + "kind": "Import", + "name": "StoreKit", + "printedName": "StoreKit", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "Import", + "name": "SwiftUI", + "printedName": "SwiftUI", + "declKind": "Import", + "moduleName": "FirebaseAnalytics" + }, + { + "kind": "TypeDecl", + "name": "Analytics", + "printedName": "Analytics", + "children": [ + { + "kind": "Function", + "name": "logTransaction", + "printedName": "logTransaction(_:)", + "children": [ + { + "kind": "TypeNominal", + "name": "Void", + "printedName": "()" + }, + { + "kind": "TypeNominal", + "name": "Transaction", + "printedName": "StoreKit.Transaction", + "usr": "s:8StoreKit11TransactionV" + } + ], + "declKind": "Func", + "usr": "s:So12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "mangledName": "$sSo12FIRAnalyticsC17FirebaseAnalyticsE14logTransactionyy8StoreKit0E0VFZ", + "moduleName": "FirebaseAnalytics", + "static": true, + "declAttributes": [ + "Final", + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Class", + "usr": "c:objc(cs)FIRAnalytics", + "moduleName": "FirebaseAnalytics", + "isOpen": true, + "objc_name": "FIRAnalytics", + "declAttributes": [ + "ObjC", + "Dynamic" + ], + "superclassUsr": "c:objc(cs)NSObject", + "isExternal": true, + "inheritsConvenienceInitializers": true, + "superclassNames": [ + "ObjectiveC.NSObject" + ], + "conformances": [ + { + "kind": "Conformance", + "name": "Equatable", + "printedName": "Equatable", + "usr": "s:SQ", + "mangledName": "$sSQ" + }, + { + "kind": "Conformance", + "name": "Hashable", + "printedName": "Hashable", + "usr": "s:SH", + "mangledName": "$sSH" + }, + { + "kind": "Conformance", + "name": "CVarArg", + "printedName": "CVarArg", + "usr": "s:s7CVarArgP", + "mangledName": "$ss7CVarArgP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObservingPublishing", + "printedName": "_KeyValueCodingAndObservingPublishing", + "usr": "s:10Foundation37_KeyValueCodingAndObservingPublishingP", + "mangledName": "$s10Foundation37_KeyValueCodingAndObservingPublishingP" + }, + { + "kind": "Conformance", + "name": "_KeyValueCodingAndObserving", + "printedName": "_KeyValueCodingAndObserving", + "usr": "s:10Foundation27_KeyValueCodingAndObservingP", + "mangledName": "$s10Foundation27_KeyValueCodingAndObservingP" + }, + { + "kind": "Conformance", + "name": "CustomStringConvertible", + "printedName": "CustomStringConvertible", + "usr": "s:s23CustomStringConvertibleP", + "mangledName": "$ss23CustomStringConvertibleP" + }, + { + "kind": "Conformance", + "name": "CustomDebugStringConvertible", + "printedName": "CustomDebugStringConvertible", + "usr": "s:s28CustomDebugStringConvertibleP", + "mangledName": "$ss28CustomDebugStringConvertibleP" + } + ] + }, + { + "kind": "TypeDecl", + "name": "View", + "printedName": "View", + "children": [ + { + "kind": "Function", + "name": "analyticsScreen", + "printedName": "analyticsScreen(name:class:extraParameters:)", + "children": [ + { + "kind": "TypeNominal", + "name": "ModifiedContent", + "printedName": "SwiftUI.ModifiedContent<τ_0_0, FirebaseAnalytics.LoggedAnalyticsModifier>", + "children": [ + { + "kind": "TypeNominal", + "name": "GenericTypeParam", + "printedName": "τ_0_0" + }, + { + "kind": "TypeNominal", + "name": "LoggedAnalyticsModifier", + "printedName": "FirebaseAnalytics.LoggedAnalyticsModifier", + "usr": "s:17FirebaseAnalytics06LoggedB8ModifierV" + } + ], + "usr": "s:7SwiftUI15ModifiedContentV" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "hasDefaultArg": true, + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "Dictionary", + "printedName": "[Swift.String : Any]", + "children": [ + { + "kind": "TypeNominal", + "name": "String", + "printedName": "Swift.String", + "usr": "s:SS" + }, + { + "kind": "TypeNominal", + "name": "ProtocolComposition", + "printedName": "Any" + } + ], + "hasDefaultArg": true, + "usr": "s:SD" + } + ], + "declKind": "Func", + "usr": "s:7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "mangledName": "$s7SwiftUI4ViewP17FirebaseAnalyticsE15analyticsScreen4name5class15extraParametersQrSS_SSSDySSypGtF", + "moduleName": "FirebaseAnalytics", + "genericSig": "<τ_0_0 where τ_0_0 : SwiftUI.View>", + "sugared_genericSig": "", + "declAttributes": [ + "AccessControl", + "RawDocComment" + ], + "isFromExtension": true, + "funcSelfKind": "NonMutating" + } + ], + "declKind": "Protocol", + "usr": "s:7SwiftUI4ViewP", + "mangledName": "$s7SwiftUI4ViewP", + "moduleName": "SwiftUI", + "genericSig": "<τ_0_0.Body : SwiftUI.View>", + "sugared_genericSig": "", + "intro_Macosx": "10.15", + "intro_iOS": "13.0", + "intro_tvOS": "13.0", + "intro_watchOS": "6.0", + "declAttributes": [ + "TypeEraser", + "Available", + "Available", + "Available", + "Available" + ], + "isExternal": true + } + ], + "json_format_version": 8 + }, + "ConstValues": [ + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1259, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "BooleanLiteral", + "offset": 1297, + "length": 5, + "value": "false" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2523, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2564, + "length": 1, + "value": "1" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2607, + "length": 1, + "value": "2" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2651, + "length": 1, + "value": "3" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+StoreKit.swift", + "kind": "IntegerLiteral", + "offset": 2683, + "length": 1, + "value": "0" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "StringLiteral", + "offset": 2654, + "length": 6, + "value": "\"View\"" + }, + { + "filePath": "\/Volumes\/google\/src\/cloud\/hantran\/m152\/google3\/googlemac\/iPhone\/Firebase\/Analytics\/Sources\/Swift\/Analytics+SwiftUI.swift", + "kind": "Dictionary", + "offset": 2701, + "length": 3, + "value": "[]" + } + ] +} \ No newline at end of file diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.private.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.private.swiftinterface new file mode 100644 index 0000000..fd735f7 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.private.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-tvos13.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc new file mode 100644 index 0000000..82cf8a8 Binary files /dev/null and b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftdoc differ diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftinterface b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftinterface new file mode 100644 index 0000000..fd735f7 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/FirebaseAnalytics.swiftmodule/x86_64-apple-tvos-simulator.swiftinterface @@ -0,0 +1,22 @@ +// swift-interface-format-version: 1.0 +// swift-compiler-version: Apple Swift version 5.9.2 (swiftlang-5.9.2.2.56 clang-1500.1.0.2.5) +// swift-module-flags: -target x86_64-apple-tvos13.0-simulator -enable-objc-interop -enable-library-evolution -swift-version 5 -enforce-exclusivity=checked -O -module-name FirebaseAnalytics +// swift-module-flags-ignorable: -enable-bare-slash-regex +@_exported import FirebaseAnalytics +import StoreKit +import Swift +import SwiftUI +import _Concurrency +import _StringProcessing +import _SwiftConcurrencyShims +@available(iOS 15.0, macOS 12.0, macCatalyst 15.0, tvOS 15.0, *) +@available(watchOS, unavailable) +extension FirebaseAnalytics.Analytics { + public static func logTransaction(_ transaction: StoreKit.Transaction) +} +@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, *) +@available(watchOS, unavailable) +extension SwiftUI.View { + public func analyticsScreen(name: Swift.String, class: Swift.String = "View", extraParameters: [Swift.String : Any] = [:]) -> some SwiftUI.View + +} diff --git a/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap new file mode 100644 index 0000000..fa10817 --- /dev/null +++ b/Pods/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator/FirebaseAnalytics.framework/Modules/module.modulemap @@ -0,0 +1,16 @@ +framework module FirebaseAnalytics { +umbrella header "FirebaseAnalytics-umbrella.h" +export * +module * { export * } + link framework "Foundation" + link framework "Security" + link framework "SystemConfiguration" + link framework "UIKit" + link "c++" + link "sqlite3" + link "z" +} +module FirebaseAnalytics.Swift { + header "FirebaseAnalytics-Swift.h" + requires objc +} \ No newline at end of file diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h new file mode 100644 index 0000000..6429ac7 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.h @@ -0,0 +1,56 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// Values stored in analyticsEnabledState. Never alter these constants since they must match with +/// values persisted to disk. +typedef NS_ENUM(int64_t, FIRAnalyticsEnabledState) { + // 0 is the default value for keys not found stored in persisted config, so it cannot represent + // kFIRAnalyticsEnabledStateSetNo. It must represent kFIRAnalyticsEnabledStateNotSet. + kFIRAnalyticsEnabledStateNotSet = 0, + kFIRAnalyticsEnabledStateSetYes = 1, + kFIRAnalyticsEnabledStateSetNo = 2, +}; + +/// The user defaults key for the persisted measurementEnabledState value. FIRAPersistedConfig reads +/// measurementEnabledState using this same key. +static NSString *const kFIRAPersistedConfigMeasurementEnabledStateKey = + @"/google/measurement/measurement_enabled_state"; + +static NSString *const kFIRAnalyticsConfigurationSetEnabledNotification = + @"FIRAnalyticsConfigurationSetEnabledNotification"; +static NSString *const kFIRAnalyticsConfigurationSetMinimumSessionIntervalNotification = + @"FIRAnalyticsConfigurationSetMinimumSessionIntervalNotification"; +static NSString *const kFIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification = + @"FIRAnalyticsConfigurationSetSessionTimeoutIntervalNotification"; + +@interface FIRAnalyticsConfiguration : NSObject + +/// Returns the shared instance of FIRAnalyticsConfiguration. ++ (FIRAnalyticsConfiguration *)sharedInstance; + +// Sets whether analytics collection is enabled for this app on this device. This setting is +// persisted across app sessions. By default it is enabled. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled; + +/// Sets whether analytics collection is enabled for this app on this device, and a flag to persist +/// the value or not. The setting should not be persisted if being set by the global data collection +/// flag. +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m new file mode 100644 index 0000000..07c786c --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRAnalyticsConfiguration.m @@ -0,0 +1,62 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" +@implementation FIRAnalyticsConfiguration +#pragma clang diagnostic pop + ++ (FIRAnalyticsConfiguration *)sharedInstance { + static FIRAnalyticsConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRAnalyticsConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (void)postNotificationName:(NSString *)name value:(id)value { + if (!name.length || !value) { + return; + } + [[NSNotificationCenter defaultCenter] postNotificationName:name + object:self + userInfo:@{name : value}]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled { + [self setAnalyticsCollectionEnabled:analyticsCollectionEnabled persistSetting:YES]; +} + +- (void)setAnalyticsCollectionEnabled:(BOOL)analyticsCollectionEnabled + persistSetting:(BOOL)shouldPersist { + // Persist the measurementEnabledState. Use FIRAnalyticsEnabledState values instead of YES/NO. + FIRAnalyticsEnabledState analyticsEnabledState = + analyticsCollectionEnabled ? kFIRAnalyticsEnabledStateSetYes : kFIRAnalyticsEnabledStateSetNo; + if (shouldPersist) { + NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults]; + [userDefaults setObject:@(analyticsEnabledState) + forKey:kFIRAPersistedConfigMeasurementEnabledStateKey]; + [userDefaults synchronize]; + } + + [self postNotificationName:kFIRAnalyticsConfigurationSetEnabledNotification + value:@(analyticsCollectionEnabled)]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m new file mode 100644 index 0000000..abec966 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRApp.m @@ -0,0 +1,896 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#if __has_include() +#import +#endif + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Extension/FIROptionsInternal.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#import + +#import + +NSString *const kFIRDefaultAppName = @"__FIRAPP_DEFAULT"; +NSString *const kFIRAppReadyToConfigureSDKNotification = @"FIRAppReadyToConfigureSDKNotification"; +NSString *const kFIRAppDeleteNotification = @"FIRAppDeleteNotification"; +NSString *const kFIRAppIsDefaultAppKey = @"FIRAppIsDefaultAppKey"; +NSString *const kFIRAppNameKey = @"FIRAppNameKey"; +NSString *const kFIRGoogleAppIDKey = @"FIRGoogleAppIDKey"; + +NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat = + @"/google/firebase/global_data_collection_enabled:%@"; +NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey = + @"FirebaseDataCollectionDefaultEnabled"; + +NSString *const kFIRAppDiagnosticsConfigurationTypeKey = @"ConfigType"; +NSString *const kFIRAppDiagnosticsErrorKey = @"Error"; +NSString *const kFIRAppDiagnosticsFIRAppKey = @"FIRApp"; +NSString *const kFIRAppDiagnosticsSDKNameKey = @"SDKName"; +NSString *const kFIRAppDiagnosticsSDKVersionKey = @"SDKVersion"; +NSString *const kFIRAppDiagnosticsApplePlatformPrefix = @"apple-platform"; + +// Auth internal notification notification and key. +NSString *const FIRAuthStateDidChangeInternalNotification = + @"FIRAuthStateDidChangeInternalNotification"; +NSString *const FIRAuthStateDidChangeInternalNotificationAppKey = + @"FIRAuthStateDidChangeInternalNotificationAppKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey = + @"FIRAuthStateDidChangeInternalNotificationTokenKey"; +NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey = + @"FIRAuthStateDidChangeInternalNotificationUIDKey"; + +/** + * Error domain for exceptions and NSError construction. + */ +NSString *const kFirebaseCoreErrorDomain = @"com.firebase.core"; + +/** + * The URL to download plist files. + */ +static NSString *const kPlistURL = @"https://console.firebase.google.com/"; + +@interface FIRApp () + +#ifdef DEBUG +@property(nonatomic) BOOL alreadyOutputDataCollectionFlag; +#endif // DEBUG + +@end + +@implementation FIRApp + +// This is necessary since our custom getter prevents `_options` from being created. +@synthesize options = _options; + +static NSMutableDictionary *sAllApps; +static FIRApp *sDefaultApp; + ++ (void)configure { + FIROptions *options = [FIROptions defaultOptions]; + if (!options) { +#if DEBUG + [self findMisnamedGoogleServiceInfoPlist]; +#endif // DEBUG + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find " + @"a valid GoogleService-Info.plist in your project. Please download one " + @"from %@.", + kPlistURL]; + } + [FIRApp configureWithOptions:options]; +} + ++ (void)configureWithOptions:(FIROptions *)options { + if (!options) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Options is nil. Please pass a valid options."]; + } + [FIRApp configureWithName:kFIRDefaultAppName options:options]; +} + ++ (NSCharacterSet *)applicationNameAllowedCharacters { + static NSCharacterSet *applicationNameAllowedCharacters; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableCharacterSet *allowedNameCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedNameCharacters addCharactersInString:@"-_"]; + applicationNameAllowedCharacters = [allowedNameCharacters copy]; + }); + return applicationNameAllowedCharacters; +} + ++ (void)configureWithName:(NSString *)name options:(FIROptions *)options { + if (!name || !options) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Neither name nor options can be nil."]; + } + if (name.length == 0) { + [NSException raise:kFirebaseCoreErrorDomain format:@"Name cannot be empty."]; + } + + if ([name isEqualToString:kFIRDefaultAppName]) { + if (sDefaultApp) { + // The default app already exists. Handle duplicate `configure` calls and return. + [self appWasConfiguredTwice:sDefaultApp usingOptions:options]; + return; + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configuring the default app."); + } else { + // Validate the app name and ensure it hasn't been configured already. + NSCharacterSet *nameCharacters = [NSCharacterSet characterSetWithCharactersInString:name]; + + if (![[self applicationNameAllowedCharacters] isSupersetOfSet:nameCharacters]) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App name can only contain alphanumeric, " + @"hyphen (-), and underscore (_) characters"]; + } + + @synchronized(self) { + if (sAllApps && sAllApps[name]) { + // The app already exists. Handle a duplicate `configure` call and return. + [self appWasConfiguredTwice:sAllApps[name] usingOptions:options]; + return; + } + } + + FIRLogDebug(kFIRLoggerCore, @"I-COR000002", @"Configuring app named %@", name); + } + + // Default instantiation, make sure we populate with Swift SDKs that can't register in time. + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + [self registerSwiftComponents]; + }); + + @synchronized(self) { + FIRApp *app = [[FIRApp alloc] initInstanceWithName:name options:options]; + if (app.isDefaultApp) { + sDefaultApp = app; + } + + [FIRApp addAppToAppDictionary:app]; + + // The FIRApp instance is ready to go, `sDefaultApp` is assigned, other SDKs are now ready to be + // instantiated. + [app.container instantiateEagerComponents]; + [FIRApp sendNotificationsToSDKs:app]; + } +} + +/// Called when `configure` has been called multiple times for the same app. This can either throw +/// an exception (most cases) or ignore the duplicate configuration in situations where it's allowed +/// like an extension. ++ (void)appWasConfiguredTwice:(FIRApp *)app usingOptions:(FIROptions *)options { + // Only extensions should potentially be able to call `configure` more than once. + if (![GULAppEnvironmentUtil isAppExtension]) { + // Throw an exception since this is now an invalid state. + if (app.isDefaultApp) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Default app has already been configured."]; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } + } + + // In an extension, the entry point could be called multiple times. As long as the options are + // identical we should allow multiple `configure` calls. + if ([options isEqual:app.options]) { + // Everything is identical but the extension's lifecycle triggered `configure` twice. + // Ignore duplicate calls and return since everything should still be in a valid state. + FIRLogDebug(kFIRLoggerCore, @"I-COR000035", + @"Ignoring second `configure` call in an extension."); + return; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"App named %@ has already been configured.", app.name]; + } +} + ++ (FIRApp *)defaultApp { + if (sDefaultApp) { + return sDefaultApp; + } + FIRLogError(kFIRLoggerCore, @"I-COR000003", + @"The default Firebase app has not yet been " + @"configured. Add `FirebaseApp.configure()` to your " + @"application initialization. This can be done in " + @"in the App Delegate's application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI). " + @"Read more: " + @"https://firebase.google.com/docs/ios/setup#initialize_firebase_in_your_app"); + return nil; +} + ++ (FIRApp *)appNamed:(NSString *)name { + @synchronized(self) { + if (sAllApps) { + FIRApp *app = sAllApps[name]; + if (app) { + return app; + } + } + FIRLogError(kFIRLoggerCore, @"I-COR000004", @"App with name %@ does not exist.", name); + return nil; + } +} + ++ (NSDictionary *)allApps { + @synchronized(self) { + if (!sAllApps) { + FIRLogError(kFIRLoggerCore, @"I-COR000005", @"No app has been configured yet."); + } + return [sAllApps copy]; + } +} + +// Public only for tests ++ (void)resetApps { + @synchronized(self) { + sDefaultApp = nil; + [sAllApps removeAllObjects]; + sAllApps = nil; + [[self userAgent] reset]; + } +} + +- (void)deleteApp:(FIRAppVoidBoolCallback)completion { + @synchronized([self class]) { + if (sAllApps && sAllApps[self.name]) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000006", @"Deleting app named %@", self.name); + + // Remove all registered libraries from the container to avoid creating new instances. + [self.container removeAllComponents]; + // Remove all cached instances from the container before deleting the app. + [self.container removeAllCachedInstances]; + + [sAllApps removeObjectForKey:self.name]; + [self clearDataCollectionSwitchFromUserDefaults]; + if ([self.name isEqualToString:kFIRDefaultAppName]) { + sDefaultApp = nil; + } + NSDictionary *appInfoDict = @{kFIRAppNameKey : self.name}; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppDeleteNotification + object:[self class] + userInfo:appInfoDict]; + completion(YES); + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000007", @"App does not exist."); + completion(NO); + } + } +} + ++ (void)addAppToAppDictionary:(FIRApp *)app { + if (!sAllApps) { + sAllApps = [NSMutableDictionary dictionary]; + } + if ([app configureCore]) { + sAllApps[app.name] = app; + } else { + [NSException raise:kFirebaseCoreErrorDomain + format:@"Configuration fails. It may be caused by an invalid GOOGLE_APP_ID in " + @"GoogleService-Info.plist or set in the customized options."]; + } +} + +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options { + self = [super init]; + if (self) { + _name = [name copy]; + _options = [options copy]; + _options.editingLocked = YES; + _isDefaultApp = [name isEqualToString:kFIRDefaultAppName]; + _container = [[FIRComponentContainer alloc] initWithApp:self]; + _heartbeatLogger = [[FIRHeartbeatLogger alloc] initWithAppID:self.options.googleAppID]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (BOOL)configureCore { + [self checkExpectedBundleID]; + if (![self isAppIDValid]) { + return NO; + } + + // Initialize the Analytics once there is a valid options under default app. Analytics should + // always initialize first by itself before the other SDKs. + if ([self.name isEqualToString:kFIRDefaultAppName]) { + Class firAnalyticsClass = NSClassFromString(@"FIRAnalytics"); + if (firAnalyticsClass) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundeclared-selector" + SEL startWithConfigurationSelector = @selector(startWithConfiguration:options:); +#pragma clang diagnostic pop + if ([firAnalyticsClass respondsToSelector:startWithConfigurationSelector]) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [firAnalyticsClass performSelector:startWithConfigurationSelector + withObject:[FIRConfiguration sharedInstance].analyticsConfiguration + withObject:_options]; +#pragma clang diagnostic pop + } + } + } + + [self subscribeForAppDidBecomeActiveNotifications]; + + return YES; +} + +- (FIROptions *)options { + return [_options copy]; +} + +- (void)setDataCollectionDefaultEnabled:(BOOL)dataCollectionDefaultEnabled { +#ifdef DEBUG + FIRLogDebug(kFIRLoggerCore, @"I-COR000034", @"Explicitly %@ data collection flag.", + dataCollectionDefaultEnabled ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; +#endif // DEBUG + + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] setBool:dataCollectionDefaultEnabled forKey:key]; + + // Core also controls the FirebaseAnalytics flag, so check if the Analytics flags are set + // within FIROptions and change the Analytics value if necessary. Analytics only works with the + // default app, so return if this isn't the default app. + if (!self.isDefaultApp) { + return; + } + + // Check if the Analytics flag is explicitly set. If so, no further actions are necessary. + if ([self.options isAnalyticsCollectionExplicitlySet]) { + return; + } + + // The Analytics flag has not been explicitly set, so update with the value being set. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[FIRAnalyticsConfiguration sharedInstance] + setAnalyticsCollectionEnabled:dataCollectionDefaultEnabled + persistSetting:NO]; +#pragma clang diagnostic pop +} + +- (BOOL)isDataCollectionDefaultEnabled { + // Check if it's been manually set before in code, and use that as the higher priority value. + NSNumber *defaultsObject = [[self class] readDataCollectionSwitchFromUserDefaultsForApp:self]; + if (defaultsObject != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000031", @"Data Collection flag is %@ in user defaults.", + [defaultsObject boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [defaultsObject boolValue]; + } + + // Read the Info.plist to see if the flag is set. If it's not set, it should default to `YES`. + // As per the implementation of `readDataCollectionSwitchFromPlist`, it's a cached value and has + // no performance impact calling multiple times. + NSNumber *collectionEnabledPlistValue = [[self class] readDataCollectionSwitchFromPlist]; + if (collectionEnabledPlistValue != nil) { +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000032", @"Data Collection flag is %@ in plist.", + [collectionEnabledPlistValue boolValue] ? @"enabled" : @"disabled"); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return [collectionEnabledPlistValue boolValue]; + } + +#ifdef DEBUG + if (!self.alreadyOutputDataCollectionFlag) { + FIRLogDebug(kFIRLoggerCore, @"I-COR000033", @"Data Collection flag is not set."); + self.alreadyOutputDataCollectionFlag = YES; + } +#endif // DEBUG + return YES; +} + +#pragma mark - private + ++ (void)sendNotificationsToSDKs:(FIRApp *)app { + // TODO: Remove this notification once all SDKs are registered with `FIRCoreConfigurable`. + NSNumber *isDefaultApp = [NSNumber numberWithBool:app.isDefaultApp]; + NSDictionary *appInfoDict = @{ + kFIRAppNameKey : app.name, + kFIRAppIsDefaultAppKey : isDefaultApp, + kFIRGoogleAppIDKey : app.options.googleAppID + }; + [[NSNotificationCenter defaultCenter] postNotificationName:kFIRAppReadyToConfigureSDKNotification + object:self + userInfo:appInfoDict]; +} + ++ (NSError *)errorForMissingOptions { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : + @"Unable to parse GoogleService-Info.plist in order to configure services.", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-100 userInfo:errorDict]; +} + ++ (NSError *)errorForInvalidAppID { + NSDictionary *errorDict = @{ + NSLocalizedDescriptionKey : @"Unable to validate Google App ID", + NSLocalizedRecoverySuggestionErrorKey : + @"Check formatting and location of GoogleService-Info.plist or GoogleAppID set in the " + @"customized options." + }; + return [NSError errorWithDomain:kFirebaseCoreErrorDomain code:-101 userInfo:errorDict]; +} + ++ (BOOL)isDefaultAppConfigured { + return (sDefaultApp != nil); +} + ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version { + // Create the set of characters which aren't allowed, only if this feature is used. + NSMutableCharacterSet *allowedSet = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedSet addCharactersInString:@"-_."]; + NSCharacterSet *disallowedSet = [allowedSet invertedSet]; + // Make sure the library name and version strings do not contain unexpected characters, and + // add the name/version pair to the dictionary. + if ([name rangeOfCharacterFromSet:disallowedSet].location == NSNotFound && + [version rangeOfCharacterFromSet:disallowedSet].location == NSNotFound) { + [[self userAgent] setValue:version forComponent:name]; + } else { + FIRLogError(kFIRLoggerCore, @"I-COR000027", + @"The library name (%@) or version number (%@) contain invalid characters. " + @"Only alphanumeric, dash, underscore and period characters are allowed.", + name, version); + } +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name { + [self registerInternalLibrary:library withName:name withVersion:FIRFirebaseVersion()]; +} + ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version { + // This is called at +load time, keep the work to a minimum. + + // Ensure the class given conforms to the proper protocol. + if (![(Class)library conformsToProtocol:@protocol(FIRLibrary)] || + ![(Class)library respondsToSelector:@selector(componentsToRegister)]) { + [NSException raise:NSInvalidArgumentException + format:@"Class %@ attempted to register components, but it does not conform to " + @"`FIRLibrary or provide a `componentsToRegister:` method.", + library]; + } + + [FIRComponentContainer registerAsComponentRegistrant:library]; + [self registerLibrary:name withVersion:version]; +} + ++ (FIRFirebaseUserAgent *)userAgent { + static dispatch_once_t onceToken; + static FIRFirebaseUserAgent *_userAgent; + dispatch_once(&onceToken, ^{ + _userAgent = [[FIRFirebaseUserAgent alloc] init]; + [_userAgent setValue:FIRFirebaseVersion() forComponent:@"fire-ios"]; + }); + return _userAgent; +} + ++ (NSString *)firebaseUserAgent { + return [[self userAgent] firebaseUserAgent]; +} + +- (void)checkExpectedBundleID { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *expectedBundleID = [self expectedBundleID]; + // The checking is only done when the bundle ID is provided in the serviceInfo dictionary for + // backward compatibility. + if (expectedBundleID != nil && ![FIRBundleUtil hasBundleIdentifierPrefix:expectedBundleID + inBundles:bundles]) { + FIRLogError(kFIRLoggerCore, @"I-COR000008", + @"The project's Bundle ID is inconsistent with " + @"either the Bundle ID in '%@.%@', or the Bundle ID in the options if you are " + @"using a customized options. To ensure that everything can be configured " + @"correctly, you may need to make the Bundle IDs consistent. To continue with this " + @"plist file, you may change your app's bundle identifier to '%@'. Or you can " + @"download a new configuration file that matches your bundle identifier from %@ " + @"and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + } +} + +#pragma mark - private - App ID Validation + +/** + * Validates the format of app ID and its included bundle ID hash contained in GOOGLE_APP_ID in the + * plist file. This is the main method for validating app ID. + * + * @return YES if the app ID fulfills the expected format and contains a hashed bundle ID, NO + * otherwise. + */ +- (BOOL)isAppIDValid { + NSString *appID = _options.googleAppID; + BOOL isValid = [FIRApp validateAppID:appID]; + if (!isValid) { + NSString *expectedBundleID = [self expectedBundleID]; + FIRLogError(kFIRLoggerCore, @"I-COR000009", + @"The GOOGLE_APP_ID either in the plist file " + @"'%@.%@' or the one set in the customized options is invalid. If you are using " + @"the plist file, use the iOS version of bundle identifier to download the file, " + @"and do not manually edit the GOOGLE_APP_ID. You may change your app's bundle " + @"identifier to '%@'. Or you can download a new configuration file that matches " + @"your bundle identifier from %@ and replace the current one.", + kServiceInfoFileName, kServiceInfoFileType, expectedBundleID, kPlistURL); + }; + return isValid; +} + ++ (BOOL)validateAppID:(NSString *)appID { + // Failing validation only occurs when we are sure we are looking at a V2 app ID and it does not + // have a valid hashed bundle ID, otherwise we just warn about the potential issue. + if (!appID.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + NSString *appIDVersion; + if (![stringScanner scanCharactersFromSet:[NSCharacterSet decimalDigitCharacterSet] + intoString:&appIDVersion]) { + return NO; + } + + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + NSArray *knownVersions = @[ @"1" ]; + if (![knownVersions containsObject:appIDVersion]) { + // Permit unknown yet properly formatted app ID versions. + FIRLogInfo(kFIRLoggerCore, @"I-COR000010", @"Unknown GOOGLE_APP_ID version: %@", appIDVersion); + return YES; + } + + if (![self validateAppIDFormat:appID withVersion:appIDVersion]) { + return NO; + } + + if (![self validateBundleIDHashWithinAppID:appID forVersion:appIDVersion]) { + return NO; + } + + return YES; +} + ++ (NSString *)actualBundleID { + return [[NSBundle mainBundle] bundleIdentifier]; +} + +/** + * Validates that the format of the app ID string is what is expected based on the supplied version. + * The version must end in ":". + * + * For v1 app ids the format is expected to be + * '::ios:'. + * + * This method does not verify that the contents of the app id are correct, just that they fulfill + * the expected format. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fulfills the expected format, NO otherwise. + */ ++ (BOOL)validateAppIDFormat:(NSString *)appID withVersion:(NSString *)version { + if (!appID.length || !version.length) { + return NO; + } + + NSScanner *stringScanner = [NSScanner scannerWithString:appID]; + stringScanner.charactersToBeSkipped = nil; + + // Skip version part + // '**::ios:' + if (![stringScanner scanString:version intoString:NULL]) { + // The version part is missing or mismatched + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '*:*:ios:' + if (![stringScanner scanString:@":" intoString:NULL]) { + // appIDVersion must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':**:ios:'. + NSInteger projectNumber = NSNotFound; + if (![stringScanner scanInteger:&projectNumber]) { + // NO project number found. + return NO; + } + + // Validate version part (see part between '*' symbols below) + // ':*:*ios:'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The project number must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::*ios*:'. + NSString *platform; + if (![stringScanner scanUpToString:@":" intoString:&platform]) { + return NO; + } + + if (![platform isEqualToString:@"ios"]) { + // The platform must be @"ios" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios*:*'. + if (![stringScanner scanString:@":" intoString:NULL]) { + // The platform must be separated by ":" + return NO; + } + + // Validate version part (see part between '*' symbols below) + // '::ios:**'. + unsigned long long bundleIDHash = NSNotFound; + if (![stringScanner scanHexLongLong:&bundleIDHash]) { + // Hashed bundleID part is missing + return NO; + } + + if (!stringScanner.isAtEnd) { + // There are not allowed characters in the hashed bundle ID part + return NO; + } + + return YES; +} + +/** + * Validates that the hashed bundle ID included in the app ID string is what is expected based on + * the supplied version. + * + * Note that the v1 hash algorithm is not permitted on the client and cannot be fully validated. + * + * @param appID Contents of GOOGLE_APP_ID from the plist file. + * @param version Indicates what version of the app id format this string should be. + * @return YES if provided string fulfills the expected hashed bundle ID and the version is known, + * NO otherwise. + */ ++ (BOOL)validateBundleIDHashWithinAppID:(NSString *)appID forVersion:(NSString *)version { + // Extract the hashed bundle ID from the given app ID. + // This assumes the app ID format is the same for all known versions below. + // If the app ID format changes in future versions, the tokenizing of the app + // ID format will need to take into account the version of the app ID. + NSArray *components = [appID componentsSeparatedByString:@":"]; + if (components.count != 4) { + return NO; + } + + NSString *suppliedBundleIDHashString = components[3]; + if (!suppliedBundleIDHashString.length) { + return NO; + } + + uint64_t suppliedBundleIDHash; + NSScanner *scanner = [NSScanner scannerWithString:suppliedBundleIDHashString]; + if (![scanner scanHexLongLong:&suppliedBundleIDHash]) { + return NO; + } + + if ([version isEqual:@"1"]) { + // The v1 hash algorithm is not permitted on the client so the actual hash cannot be validated. + return YES; + } + + // Unknown version. + return NO; +} + +- (NSString *)expectedBundleID { + return _options.bundleID; +} + +// end App ID validation + +#pragma mark - Reading From Plist & User Defaults + +/** + * Clears the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ +- (void)clearDataCollectionSwitchFromUserDefaults { + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, self.name]; + [[NSUserDefaults standardUserDefaults] removeObjectForKey:key]; +} + +/** + * Reads the data collection switch from the standard NSUserDefaults for easier testing and + * readability. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromUserDefaultsForApp:(FIRApp *)app { + // Read the object in user defaults, and only return if it's an NSNumber. + NSString *key = + [NSString stringWithFormat:kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat, app.name]; + id collectionEnabledDefaultsObject = [[NSUserDefaults standardUserDefaults] objectForKey:key]; + if ([collectionEnabledDefaultsObject isKindOfClass:[NSNumber class]]) { + return collectionEnabledDefaultsObject; + } + + return nil; +} + +/** + * Reads the data collection switch from the Info.plist for easier testing and readability. Will + * only read once from the plist and return the cached value. + */ ++ (nullable NSNumber *)readDataCollectionSwitchFromPlist { + static NSNumber *collectionEnabledPlistObject; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // Read the data from the `Info.plist`, only assign it if it's there and an NSNumber. + id plistValue = [[NSBundle mainBundle] + objectForInfoDictionaryKey:kFIRGlobalAppDataCollectionEnabledPlistKey]; + if (plistValue && [plistValue isKindOfClass:[NSNumber class]]) { + collectionEnabledPlistObject = (NSNumber *)plistValue; + } + }); + + return collectionEnabledPlistObject; +} + +#pragma mark - Swift Components. + ++ (void)registerSwiftComponents { + SEL componentsToRegisterSEL = @selector(componentsToRegister); + // Dictionary of class names that conform to `FIRLibrary` and their user agents. These should only + // be SDKs that are written in Swift but still visible to ObjC. + // This is only necessary for products that need to do work at launch during configuration. + NSDictionary *swiftComponents = @{ + @"FIRSessions" : @"fire-ses", + @"FIRAuthComponent" : @"fire-auth", + }; + for (NSString *className in swiftComponents.allKeys) { + Class klass = NSClassFromString(className); + if (klass && [klass respondsToSelector:componentsToRegisterSEL]) { + [FIRApp registerInternalLibrary:klass withName:swiftComponents[className]]; + } + } + + // Swift libraries that don't need component behaviour + NSDictionary *swiftLibraries = @{ + @"FIRCombineAuthLibrary" : @"comb-auth", + @"FIRCombineFirestoreLibrary" : @"comb-firestore", + @"FIRCombineFunctionsLibrary" : @"comb-functions", + @"FIRCombineStorageLibrary" : @"comb-storage", + @"FIRFunctions" : @"fire-fun", + @"FIRStorage" : @"fire-str", + @"FIRVertexAIComponent" : @"fire-vertex", + }; + for (NSString *className in swiftLibraries.allKeys) { + Class klass = NSClassFromString(className); + if (klass) { + [FIRApp registerLibrary:swiftLibraries[className] withVersion:FIRFirebaseVersion()]; + } + } +} + +#pragma mark - App Life Cycle + +- (void)subscribeForAppDidBecomeActiveNotifications { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + NSNotificationName notificationName = UIApplicationDidBecomeActiveNotification; +#elif TARGET_OS_OSX + NSNotificationName notificationName = NSApplicationDidBecomeActiveNotification; +#elif TARGET_OS_WATCH + // TODO(ncooke3): Remove when minimum supported watchOS version is watchOS 7.0. + // On watchOS 7.0+, heartbeats are logged when the watch app becomes active. + // On watchOS 6.0, heartbeats are logged when the Firebase app is configuring. + // While it does not cover all use cases, logging when the Firebase app is + // configuring is done because watchOS lifecycle notifications are a + // watchOS 7.0+ feature. + NSNotificationName notificationName = kFIRAppReadyToConfigureSDKNotification; + if (@available(watchOS 7.0, *)) { + notificationName = WKApplicationDidBecomeActiveNotification; + } +#endif + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActive:) + name:notificationName + object:nil]; +} + +- (void)appDidBecomeActive:(NSNotification *)notification { + if ([self isDataCollectionDefaultEnabled]) { + // If changing the below line, consult with the Games team to ensure they + // are not negatively impacted. For more details, see + // go/firebase-game-sdk-user-agent-register-timing. + [self.heartbeatLogger log]; + } +} + +#if DEBUG ++ (void)findMisnamedGoogleServiceInfoPlist { + for (NSBundle *bundle in [NSBundle allBundles]) { + // Not recursive, but we're looking for misnames, not people accidentally + // hiding their config file in a subdirectory of their bundle. + NSArray *plistPaths = [bundle pathsForResourcesOfType:@"plist" inDirectory:nil]; + for (NSString *path in plistPaths) { + @autoreleasepool { + NSDictionary *contents = [NSDictionary dictionaryWithContentsOfFile:path]; + if (contents == nil) { + continue; + } + + NSString *projectID = contents[@"PROJECT_ID"]; + if (projectID != nil) { + [NSException raise:kFirebaseCoreErrorDomain + format:@"`FirebaseApp.configure()` could not find the default " + @"configuration plist in your project, but did find one at " + @"%@. Please rename this file to GoogleService-Info.plist to " + @"use it as the default configuration.", + path]; + } + } + } + } +} +#endif // DEBUG + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h new file mode 100644 index 0000000..d9475dd --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.h @@ -0,0 +1,53 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * This class provides utilities for accessing resources in bundles. + */ +@interface FIRBundleUtil : NSObject + +/** + * Finds all relevant bundles, starting with [NSBundle mainBundle]. + */ ++ (NSArray *)relevantBundles; + +/** + * Reads the options dictionary from one of the provided bundles. + * + * @param resourceName The resource name, e.g. @"GoogleService-Info". + * @param fileType The file type (extension), e.g. @"plist". + * @param bundles The bundles to expect, in priority order. See also + * +[FIRBundleUtil relevantBundles]. + */ ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles; + +/** + * Finds URL schemes defined in all relevant bundles, starting with those from + * [NSBundle mainBundle]. + */ ++ (NSArray *)relevantURLSchemes; + +/** + * Checks if any of the given bundles have a matching bundle identifier prefix (removing extension + * suffixes). + */ ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m new file mode 100644 index 0000000..de2c295 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRBundleUtil.m @@ -0,0 +1,79 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRBundleUtil.h" + +#import + +@implementation FIRBundleUtil + ++ (NSArray *)relevantBundles { + return @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; +} + ++ (NSString *)optionsDictionaryPathWithResourceName:(NSString *)resourceName + andFileType:(NSString *)fileType + inBundles:(NSArray *)bundles { + // Loop through all bundles to find the config dict. + for (NSBundle *bundle in bundles) { + NSString *path = [bundle pathForResource:resourceName ofType:fileType]; + // Use the first one we find. + if (path) { + return path; + } + } + return nil; +} + ++ (NSArray *)relevantURLSchemes { + NSMutableArray *result = [[NSMutableArray alloc] init]; + for (NSBundle *bundle in [[self class] relevantBundles]) { + NSArray *urlTypes = [bundle objectForInfoDictionaryKey:@"CFBundleURLTypes"]; + for (NSDictionary *urlType in urlTypes) { + [result addObjectsFromArray:urlType[@"CFBundleURLSchemes"]]; + } + } + return result; +} + ++ (BOOL)hasBundleIdentifierPrefix:(NSString *)bundleIdentifier inBundles:(NSArray *)bundles { + for (NSBundle *bundle in bundles) { + if ([bundle.bundleIdentifier isEqualToString:bundleIdentifier]) { + return YES; + } + + if ([GULAppEnvironmentUtil isAppExtension]) { + // A developer could be using the same `FIROptions` for both their app and extension. Since + // extensions have a suffix added to the bundleID, we consider a matching prefix as valid. + NSString *appBundleIDFromExtension = + [self bundleIdentifierByRemovingLastPartFrom:bundle.bundleIdentifier]; + if ([appBundleIDFromExtension isEqualToString:bundleIdentifier]) { + return YES; + } + } + } + return NO; +} + ++ (NSString *)bundleIdentifierByRemovingLastPartFrom:(NSString *)bundleIdentifier { + NSString *bundleIDComponentsSeparator = @"."; + + NSMutableArray *bundleIDComponents = + [[bundleIdentifier componentsSeparatedByString:bundleIDComponentsSeparator] mutableCopy]; + [bundleIDComponents removeLastObject]; + + return [bundleIDComponents componentsJoinedByString:bundleIDComponentsSeparator]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m new file mode 100644 index 0000000..78c06ff --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponent.m @@ -0,0 +1,58 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponent.h" + +#import "FirebaseCore/Extension/FIRComponentContainer.h" + +@interface FIRComponent () + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock; + +@end + +@implementation FIRComponent + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:FIRInstantiationTimingLazy + creationBlock:creationBlock]; +} + ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock { + return [[FIRComponent alloc] initWithProtocol:protocol + instantiationTiming:instantiationTiming + creationBlock:creationBlock]; +} + +- (instancetype)initWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock { + self = [super init]; + if (self) { + _protocol = protocol; + _instantiationTiming = instantiationTiming; + _creationBlock = creationBlock; + } + return self; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m new file mode 100644 index 0000000..b70881c --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainer.m @@ -0,0 +1,251 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponentContainer.h" + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRComponent.h" +#import "FirebaseCore/Extension/FIRLibrary.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Extension/FIROptionsInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer () + +/// The dictionary of components that are registered for a particular app. The key is an `NSString` +/// of the protocol. +@property(nonatomic, strong) NSMutableDictionary *components; + +/// Cached instances of components that requested to be cached. +@property(nonatomic, strong) NSMutableDictionary *cachedInstances; + +/// Protocols of components that have requested to be eagerly instantiated. +@property(nonatomic, strong, nullable) NSMutableArray *eagerProtocolsToInstantiate; + +@end + +@implementation FIRComponentContainer + +// Collection of all classes that register to provide components. +static NSMutableSet *sFIRComponentRegistrants; + +#pragma mark - Public Registration + ++ (void)registerAsComponentRegistrant:(Class)klass { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sFIRComponentRegistrants = [[NSMutableSet alloc] init]; + }); + + [self registerAsComponentRegistrant:klass inSet:sFIRComponentRegistrants]; +} + ++ (void)registerAsComponentRegistrant:(Class)klass + inSet:(NSMutableSet *)allRegistrants { + [allRegistrants addObject:klass]; +} + +#pragma mark - Internal Initialization + +- (instancetype)initWithApp:(FIRApp *)app { + NSMutableSet *componentRegistrants = sFIRComponentRegistrants; + // If the app being created is for the ARCore SDK, remove the App Check + // component (if it exists) since it does not support App Check. + if ([self isAppForARCore:app]) { + Class klass = NSClassFromString(@"FIRAppCheckComponent"); + if (klass && [sFIRComponentRegistrants containsObject:klass]) { + componentRegistrants = [componentRegistrants mutableCopy]; + [componentRegistrants removeObject:klass]; + } + } + + return [self initWithApp:app registrants:componentRegistrants]; +} + +- (instancetype)initWithApp:(FIRApp *)app registrants:(NSMutableSet *)allRegistrants { + self = [super init]; + if (self) { + _app = app; + _cachedInstances = [NSMutableDictionary dictionary]; + _components = [NSMutableDictionary dictionary]; + + [self populateComponentsFromRegisteredClasses:allRegistrants forApp:app]; + } + return self; +} + +- (void)populateComponentsFromRegisteredClasses:(NSSet *)classes forApp:(FIRApp *)app { + // Keep track of any components that need to eagerly instantiate after all components are added. + self.eagerProtocolsToInstantiate = [[NSMutableArray alloc] init]; + + // Loop through the verified component registrants and populate the components array. + for (Class klass in classes) { + // Loop through all the components being registered and store them as appropriate. + // Classes which do not provide functionality should use a dummy FIRComponentRegistrant + // protocol. + for (FIRComponent *component in [klass componentsToRegister]) { + // Check if the component has been registered before, and error out if so. + NSString *protocolName = NSStringFromProtocol(component.protocol); + if (self.components[protocolName]) { + FIRLogError(kFIRLoggerCore, @"I-COR000029", + @"Attempted to register protocol %@, but it already has an implementation.", + protocolName); + continue; + } + + // Store the creation block for later usage. + self.components[protocolName] = component.creationBlock; + + // Queue any protocols that should be eagerly instantiated. Don't instantiate them yet + // because they could depend on other components that haven't been added to the components + // array yet. + BOOL shouldInstantiateEager = + (component.instantiationTiming == FIRInstantiationTimingAlwaysEager); + BOOL shouldInstantiateDefaultEager = + (component.instantiationTiming == FIRInstantiationTimingEagerInDefaultApp && + [app isDefaultApp]); + if (shouldInstantiateEager || shouldInstantiateDefaultEager) { + [self.eagerProtocolsToInstantiate addObject:component.protocol]; + } + } + } +} + +#pragma mark - Instance Creation + +- (void)instantiateEagerComponents { + // After all components are registered, instantiate the ones that are requesting eager + // instantiation. + @synchronized(self) { + for (Protocol *protocol in self.eagerProtocolsToInstantiate) { + // Get an instance for the protocol, which will instantiate it since it couldn't have been + // cached yet. Ignore the instance coming back since we don't need it. + __unused id unusedInstance = [self instanceForProtocol:protocol]; + } + + // All eager instantiation is complete, clear the stored property now. + self.eagerProtocolsToInstantiate = nil; + } +} + +/// Instantiate an instance of a class that conforms to the specified protocol. +/// This will: +/// - Call the block to create an instance if possible, +/// - Validate that the instance returned conforms to the protocol it claims to, +/// - Cache the instance if the block requests it +/// +/// Note that this method assumes the caller already has @synchronized on self. +- (nullable id)instantiateInstanceForProtocol:(Protocol *)protocol + withBlock:(FIRComponentCreationBlock)creationBlock { + if (!creationBlock) { + return nil; + } + + // Create an instance using the creation block. + BOOL shouldCache = NO; + id instance = creationBlock(self, &shouldCache); + if (!instance) { + return nil; + } + + // An instance was created, validate that it conforms to the protocol it claims to. + NSString *protocolName = NSStringFromProtocol(protocol); + if (![instance conformsToProtocol:protocol]) { + FIRLogError(kFIRLoggerCore, @"I-COR000030", + @"An instance conforming to %@ was requested, but the instance provided does not " + @"conform to the protocol", + protocolName); + } + + // The instance is ready to be returned, but check if it should be cached first before returning. + if (shouldCache) { + self.cachedInstances[protocolName] = instance; + } + + return instance; +} + +#pragma mark - Internal Retrieval + +// Redirected for Swift users. +- (nullable id)__instanceForProtocol:(Protocol *)protocol { + return [self instanceForProtocol:protocol]; +} + +- (nullable id)instanceForProtocol:(Protocol *)protocol { + // Check if there is a cached instance, and return it if so. + NSString *protocolName = NSStringFromProtocol(protocol); + + id cachedInstance; + @synchronized(self) { + cachedInstance = self.cachedInstances[protocolName]; + if (!cachedInstance) { + // Use the creation block to instantiate an instance and return it. + FIRComponentCreationBlock creationBlock = self.components[protocolName]; + cachedInstance = [self instantiateInstanceForProtocol:protocol withBlock:creationBlock]; + } + } + return cachedInstance; +} + +#pragma mark - Lifecycle + +- (void)removeAllCachedInstances { + @synchronized(self) { + // Loop through the cache and notify each instance that is a maintainer to clean up after + // itself. + for (id instance in self.cachedInstances.allValues) { + if ([instance conformsToProtocol:@protocol(FIRComponentLifecycleMaintainer)] && + [instance respondsToSelector:@selector(appWillBeDeleted:)]) { + [instance appWillBeDeleted:self.app]; + } + } + + // Empty the cache. + [self.cachedInstances removeAllObjects]; + } +} + +- (void)removeAllComponents { + @synchronized(self) { + [self.components removeAllObjects]; + } +} + +#pragma mark - Helpers + +- (BOOL)isAppForARCore:(FIRApp *)app { + // First, check if the app name matches that of the one used by ARCore. + if ([app.name isEqualToString:@"ARCoreFIRApp"]) { + // Second, check if the app's gcmSenderID matches that of ARCore. This + // prevents false positives in the unlikely event a 3P Firebase app is + // named `ARCoreFIRApp`. + const char *p1 = "406756"; + const char *p2 = "893798"; + const char gcmSenderIDKey[27] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], + p2[3], p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], + p1[7], p2[7], p1[8], p2[8], p1[9], p2[9], p1[10], + p2[10], p1[11], p2[11], p1[12], p2[12], '\0'}; + NSString *gcmSenderID = [NSString stringWithUTF8String:gcmSenderIDKey]; + return [app.options.GCMSenderID isEqualToString:gcmSenderID]; + } + return NO; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h new file mode 100644 index 0000000..169e181 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentContainerInternal.h @@ -0,0 +1,50 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +#import "FirebaseCore/Extension/FIRComponentContainer.h" +#import "FirebaseCore/Extension/FIRLibrary.h" + +@class FIRApp; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRComponentContainer (Private) + +/// Initializes a container for a given app. This should only be called by the app itself. +- (instancetype)initWithApp:(FIRApp *)app; + +/// Retrieves an instance that conforms to the specified protocol. This will return `nil` if the +/// protocol wasn't registered, or if the instance couldn't be instantiated for the provided app. +- (nullable id)instanceForProtocol:(Protocol *)protocol + NS_SWIFT_UNAVAILABLE("Use `instance(for:)` from the FirebaseCoreExtension module instead."); + +/// Instantiates all the components that have registered as "eager" after initialization. +- (void)instantiateEagerComponents; + +/// Remove all of the cached instances stored and allow them to clean up after themselves. +- (void)removeAllCachedInstances; + +/// Removes all the components. After calling this method no new instances will be created. +- (void)removeAllComponents; + +/// Register a class to provide components for the interoperability system. The class should conform +/// to `FIRComponentRegistrant` and provide an array of `FIRComponent` objects. ++ (void)registerAsComponentRegistrant:(Class)klass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m new file mode 100644 index 0000000..2204fd6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRComponentType.m @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Extension/FIRComponentType.h" + +#import "FirebaseCore/Sources/FIRComponentContainerInternal.h" + +@implementation FIRComponentType + ++ (nullable id)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container { + // Forward the call to the container. + return [container instanceForProtocol:protocol]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m new file mode 100644 index 0000000..83b3248 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfiguration.m @@ -0,0 +1,46 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Sources/FIRConfigurationInternal.h" + +#import "FirebaseCore/Sources/FIRAnalyticsConfiguration.h" + +extern void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +@implementation FIRConfiguration + ++ (instancetype)sharedInstance { + static FIRConfiguration *sharedInstance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FIRConfiguration alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _analyticsConfiguration = [FIRAnalyticsConfiguration sharedInstance]; + } + return self; +} + +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel { + NSAssert(loggerLevel <= FIRLoggerLevelMax && loggerLevel >= FIRLoggerLevelMin, + @"Invalid logger level, %ld", (long)loggerLevel); + FIRSetLoggerLevel(loggerLevel); +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h new file mode 100644 index 0000000..9361e73 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRConfigurationInternal.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h" + +@class FIRAnalyticsConfiguration; + +@interface FIRConfiguration () + +/** + * The configuration class for Firebase Analytics. This should be removed once the logic for + * enabling and disabling Analytics is moved to Analytics. + */ +@property(nonatomic, readwrite) FIRAnalyticsConfiguration *analyticsConfiguration; + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h new file mode 100644 index 0000000..ffb11fb --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.h @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRFirebaseUserAgent : NSObject + +/** Returns the firebase user agent which consists of environment part and the components added via + * `setValue:forComponent` method. */ +- (NSString *)firebaseUserAgent; + +/** Sets value associated with the specified component. If value is `nil` then the component is + * removed. */ +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName; + +/** Resets manually added components. */ +- (void)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m new file mode 100644 index 0000000..04e7566 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRFirebaseUserAgent.m @@ -0,0 +1,107 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/FIRFirebaseUserAgent.h" + +#import + +@interface FIRFirebaseUserAgent () + +@property(nonatomic, readonly) NSMutableDictionary *valuesByComponent; +@property(nonatomic, readonly) NSDictionary *environmentComponents; +@property(nonatomic, readonly) NSString *firebaseUserAgent; + +@end + +@implementation FIRFirebaseUserAgent + +@synthesize firebaseUserAgent = _firebaseUserAgent; +@synthesize environmentComponents = _environmentComponents; + +- (instancetype)init { + self = [super init]; + if (self) { + _valuesByComponent = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (NSString *)firebaseUserAgent { + @synchronized(self) { + if (_firebaseUserAgent == nil) { + NSMutableDictionary *allComponents = + [self.valuesByComponent mutableCopy]; + [allComponents setValuesForKeysWithDictionary:self.environmentComponents]; + + __block NSMutableArray *components = + [[NSMutableArray alloc] initWithCapacity:self.valuesByComponent.count]; + [allComponents enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull name, NSString *_Nonnull value, BOOL *_Nonnull stop) { + [components addObject:[NSString stringWithFormat:@"%@/%@", name, value]]; + }]; + [components sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; + _firebaseUserAgent = [components componentsJoinedByString:@" "]; + } + return _firebaseUserAgent; + } +} + +- (void)setValue:(nullable NSString *)value forComponent:(NSString *)componentName { + @synchronized(self) { + self.valuesByComponent[componentName] = value; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +- (void)reset { + @synchronized(self) { + // Reset components. + _valuesByComponent = [[[self class] environmentComponents] mutableCopy]; + // Reset cached user agent string. + _firebaseUserAgent = nil; + } +} + +#pragma mark - Environment components + +- (NSDictionary *)environmentComponents { + if (_environmentComponents == nil) { + _environmentComponents = [[self class] environmentComponents]; + } + return _environmentComponents; +} + ++ (NSDictionary *)environmentComponents { + NSMutableDictionary *components = [NSMutableDictionary dictionary]; + + NSDictionary *info = [[NSBundle mainBundle] infoDictionary]; + NSString *xcodeVersion = info[@"DTXcodeBuild"]; + NSString *appleSdkVersion = info[@"DTSDKBuild"]; + NSString *isFromAppstoreFlagValue = [GULAppEnvironmentUtil isFromAppStore] ? @"true" : @"false"; + + components[@"apple-platform"] = [GULAppEnvironmentUtil applePlatform]; + components[@"apple-sdk"] = appleSdkVersion; + components[@"appstore"] = isFromAppstoreFlagValue; + components[@"deploy"] = [GULAppEnvironmentUtil deploymentType]; + components[@"device"] = [GULAppEnvironmentUtil deviceModel]; + components[@"os-version"] = [GULAppEnvironmentUtil systemVersion]; + components[@"xcode"] = xcodeVersion; + + return [components copy]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m new file mode 100644 index 0000000..08cd396 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRHeartbeatLogger.m @@ -0,0 +1,97 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#ifndef FIREBASE_BUILD_CMAKE +@import FirebaseCoreInternal; +#endif // FIREBASE_BUILD_CMAKE + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRHeartbeatLogger.h" + +#ifndef FIREBASE_BUILD_CMAKE +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload) { + if ([heartbeatsPayload isEmpty]) { + return nil; + } + + return [heartbeatsPayload headerValue]; +} +#endif // FIREBASE_BUILD_CMAKE + +@interface FIRHeartbeatLogger () +#ifndef FIREBASE_BUILD_CMAKE +@property(nonatomic, readonly) FIRHeartbeatController *heartbeatController; +#endif // FIREBASE_BUILD_CMAKE +@property(copy, readonly) NSString * (^userAgentProvider)(void); +@end + +@implementation FIRHeartbeatLogger + +- (instancetype)initWithAppID:(NSString *)appID { + return [self initWithAppID:appID userAgentProvider:[[self class] currentUserAgentProvider]]; +} + +- (instancetype)initWithAppID:(NSString *)appID + userAgentProvider:(NSString * (^)(void))userAgentProvider { + self = [super init]; + if (self) { +#ifndef FIREBASE_BUILD_CMAKE + _heartbeatController = [[FIRHeartbeatController alloc] initWithId:[appID copy]]; +#endif // FIREBASE_BUILD_CMAKE + _userAgentProvider = [userAgentProvider copy]; + } + return self; +} + ++ (NSString * (^)(void))currentUserAgentProvider { + return ^NSString * { + return [FIRApp firebaseUserAgent]; + }; +} + +- (void)log { + NSString *userAgent = _userAgentProvider(); +#ifndef FIREBASE_BUILD_CMAKE + [_heartbeatController log:userAgent]; +#endif // FIREBASE_BUILD_CMAKE +} + +#ifndef FIREBASE_BUILD_CMAKE +- (NSString *_Nullable)headerValue { + return FIRHeaderValueFromHeartbeatsPayload([self flushHeartbeatsIntoPayload]); +} + +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload { + FIRHeartbeatsPayload *payload = [_heartbeatController flush]; + return payload; +} +#endif // FIREBASE_BUILD_CMAKE + +- (FIRDailyHeartbeatCode)heartbeatCodeForToday { +#ifndef FIREBASE_BUILD_CMAKE + FIRHeartbeatsPayload *todaysHeartbeatPayload = [_heartbeatController flushHeartbeatFromToday]; + + if ([todaysHeartbeatPayload isEmpty]) { + return FIRDailyHeartbeatCodeNone; + } else { + return FIRDailyHeartbeatCodeSome; + } +#else + return FIRDailyHeartbeatCodeNone; +#endif // FIREBASE_BUILD_CMAKE +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m new file mode 100644 index 0000000..382a3a9 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRLogger.m @@ -0,0 +1,173 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Extension/FIRLogger.h" + +#import +#import +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h" + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +NSString *const kFIRLoggerSubsystem = @"com.google.firebase"; + +NSString *const kFIRLoggerCore = @"[FirebaseCore]"; + +// All the FIRLoggerService definitions should be migrated to clients. Do not add new ones! +NSString *const kFIRLoggerAnalytics = @"[FirebaseAnalytics]"; +NSString *const kFIRLoggerCrash = @"[FirebaseCrash]"; +NSString *const kFIRLoggerRemoteConfig = @"[FirebaseRemoteConfig]"; + +/// Arguments passed on launch. +NSString *const kFIRDisableDebugModeApplicationArgument = @"-FIRDebugDisabled"; +NSString *const kFIREnableDebugModeApplicationArgument = @"-FIRDebugEnabled"; + +/// Key for the debug mode bit in NSUserDefaults. +NSString *const kFIRPersistedDebugModeKey = @"/google/firebase/debug_mode"; + +/// NSUserDefaults that should be used to store and read variables. If nil, `standardUserDefaults` +/// will be used. +static NSUserDefaults *sFIRLoggerUserDefaults; + +static dispatch_once_t sFIRLoggerOnceToken; + +// The sFIRAnalyticsDebugMode flag is here to support the -FIRDebugEnabled/-FIRDebugDisabled +// flags used by Analytics. Users who use those flags expect Analytics to log verbosely, +// while the rest of Firebase logs at the default level. This flag is introduced to support +// that behavior. +static BOOL sFIRAnalyticsDebugMode; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void FIRLoggerInitialize(void) { + dispatch_once(&sFIRLoggerOnceToken, ^{ + // Register Firebase Version with GULLogger. + GULLoggerRegisterVersion(FIRFirebaseVersion()); + + NSArray *arguments = [NSProcessInfo processInfo].arguments; + + // Use the standard NSUserDefaults if it hasn't been explicitly set. + if (sFIRLoggerUserDefaults == nil) { + sFIRLoggerUserDefaults = [NSUserDefaults standardUserDefaults]; + } + + BOOL forceDebugMode = NO; + BOOL debugMode = [sFIRLoggerUserDefaults boolForKey:kFIRPersistedDebugModeKey]; + if ([arguments containsObject:kFIRDisableDebugModeApplicationArgument]) { // Default mode + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + } else if ([arguments containsObject:kFIREnableDebugModeApplicationArgument] || + debugMode) { // Debug mode + [sFIRLoggerUserDefaults setBool:YES forKey:kFIRPersistedDebugModeKey]; + forceDebugMode = YES; + } + GULLoggerInitialize(); + if (forceDebugMode) { + GULLoggerForceDebug(); + } + }); +} + +__attribute__((no_sanitize("thread"))) void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode) { + sFIRAnalyticsDebugMode = analyticsDebugMode; +} + +FIRLoggerLevel FIRGetLoggerLevel(void) { + return (FIRLoggerLevel)GULGetLoggerLevel(); +} + +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel) { + FIRLoggerInitialize(); + GULSetLoggerLevel((GULLoggerLevel)loggerLevel); +} + +#ifdef DEBUG +void FIRResetLogger(void) { + extern void GULResetLogger(void); + sFIRLoggerOnceToken = 0; + [sFIRLoggerUserDefaults removeObjectForKey:kFIRPersistedDebugModeKey]; + sFIRLoggerUserDefaults = nil; + GULResetLogger(); +} + +void FIRSetLoggerUserDefaults(NSUserDefaults *defaults) { + sFIRLoggerUserDefaults = defaults; +} +#endif + +/** + * Check if the level is high enough to be loggable. + * + * Analytics can override the log level with an intentional race condition. + * Add the attribute to get a clean thread sanitizer run. + */ +__attribute__((no_sanitize("thread"))) BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, + BOOL analyticsComponent) { + FIRLoggerInitialize(); + if (sFIRAnalyticsDebugMode && analyticsComponent) { + return YES; + } + return GULIsLoggableLevel((GULLoggerLevel)loggerLevel); +} + +void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + FIRLoggerInitialize(); + GULOSLogBasic((GULLoggerLevel)level, kFIRLoggerSubsystem, category, + sFIRAnalyticsDebugMode && [kFIRLoggerAnalytics isEqualToString:category], + messageCode, message, args_ptr); +} + +/** + * Generates the logging functions using macros. + * + * Calling FIRLogError(kFIRLoggerCore, @"I-COR000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure blah failed. + * Calling FIRLogDebug(kFIRLoggerCore, @"I-COR000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [Firebase/Core][I-COR000001] Configure succeed. + */ +#define FIR_LOGGING_FUNCTION(level) \ + void FIRLog##level(NSString *category, NSString *messageCode, NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + FIRLogBasic(FIRLoggerLevel##level, category, messageCode, message, args_ptr); \ + va_end(args_ptr); \ + } + +FIR_LOGGING_FUNCTION(Error) +FIR_LOGGING_FUNCTION(Warning) +FIR_LOGGING_FUNCTION(Notice) +FIR_LOGGING_FUNCTION(Info) +FIR_LOGGING_FUNCTION(Debug) + +#undef FIR_LOGGING_FUNCTION + +#pragma mark - FIRLoggerWrapper + +@implementation FIRLoggerWrapper + ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)service + code:(NSString *)code + message:(NSString *)message { + FIRLogBasic(level, service, code, message, NULL); +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m new file mode 100644 index 0000000..4676a57 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIROptions.m @@ -0,0 +1,487 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Extension/FIRAppInternal.h" +#import "FirebaseCore/Extension/FIRLogger.h" +#import "FirebaseCore/Extension/FIROptionsInternal.h" +#import "FirebaseCore/Sources/FIRBundleUtil.h" +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +// Keys for the strings in the plist file. +NSString *const kFIRAPIKey = @"API_KEY"; +NSString *const kFIRTrackingID = @"TRACKING_ID"; +NSString *const kFIRGoogleAppID = @"GOOGLE_APP_ID"; +NSString *const kFIRClientID = @"CLIENT_ID"; +NSString *const kFIRGCMSenderID = @"GCM_SENDER_ID"; +NSString *const kFIRAndroidClientID = @"ANDROID_CLIENT_ID"; +NSString *const kFIRDatabaseURL = @"DATABASE_URL"; +NSString *const kFIRStorageBucket = @"STORAGE_BUCKET"; +// The key to locate the expected bundle identifier in the plist file. +NSString *const kFIRBundleID = @"BUNDLE_ID"; +// The key to locate the project identifier in the plist file. +NSString *const kFIRProjectID = @"PROJECT_ID"; + +NSString *const kFIRIsMeasurementEnabled = @"IS_MEASUREMENT_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionEnabled = @"FIREBASE_ANALYTICS_COLLECTION_ENABLED"; +NSString *const kFIRIsAnalyticsCollectionDeactivated = @"FIREBASE_ANALYTICS_COLLECTION_DEACTIVATED"; + +// Library version ID formatted like: +// @"5" // Major version (one or more digits) +// @"04" // Minor version (exactly 2 digits) +// @"01" // Build number (exactly 2 digits) +// @"000"; // Fixed "000" +NSString *kFIRLibraryVersionID; + +// Plist file name. +NSString *const kServiceInfoFileName = @"GoogleService-Info"; +// Plist file type. +NSString *const kServiceInfoFileType = @"plist"; + +// Exception raised from attempting to modify a FIROptions after it's been copied to a FIRApp. +NSString *const kFIRExceptionBadModification = + @"Attempted to modify options after it's set on FIRApp. Please modify all properties before " + @"initializing FIRApp."; + +@interface FIROptions () + +/** + * This property maintains the actual configuration key-value pairs. + */ +@property(nonatomic, readwrite) NSMutableDictionary *optionsDictionary; + +/** + * Calls `analyticsOptionsDictionaryWithInfoDictionary:` using [NSBundle mainBundle].infoDictionary. + * It combines analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the main plist override values from the GoogleService-Info.plist. + */ +@property(nonatomic, readonly) NSDictionary *analyticsOptionsDictionary; + +/** + * Combination of analytics options from both the infoDictionary and the GoogleService-Info.plist. + * Values which are present in the infoDictionary override values from the GoogleService-Info.plist. + */ +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary; + +/** + * Throw exception if editing is locked when attempting to modify an option. + */ +- (void)checkEditingLocked; + +@end + +@implementation FIROptions { + /// Backing variable for self.analyticsOptionsDictionary. + NSDictionary *_analyticsOptionsDictionary; +} + +static FIROptions *sDefaultOptions = nil; +static NSDictionary *sDefaultOptionsDictionary = nil; +static dispatch_once_t sDefaultOptionsOnceToken; +static dispatch_once_t sDefaultOptionsDictionaryOnceToken; + +#pragma mark - Public only for internal class methods + ++ (FIROptions *)defaultOptions { + dispatch_once(&sDefaultOptionsOnceToken, ^{ + NSDictionary *defaultOptionsDictionary = [self defaultOptionsDictionary]; + if (defaultOptionsDictionary != nil) { + sDefaultOptions = + [[FIROptions alloc] initInternalWithOptionsDictionary:defaultOptionsDictionary]; + } + }); + + return sDefaultOptions; +} + +#pragma mark - Private class methods + ++ (NSDictionary *)defaultOptionsDictionary { + dispatch_once(&sDefaultOptionsDictionaryOnceToken, ^{ + NSString *plistFilePath = [FIROptions plistFilePathWithName:kServiceInfoFileName]; + if (plistFilePath == nil) { + return; + } + sDefaultOptionsDictionary = [NSDictionary dictionaryWithContentsOfFile:plistFilePath]; + if (sDefaultOptionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000011", + @"The configuration file is not a dictionary: " + @"'%@.%@'.", + kServiceInfoFileName, kServiceInfoFileType); + } + }); + + return sDefaultOptionsDictionary; +} + +// Returns the path of the plist file with a given file name. ++ (NSString *)plistFilePathWithName:(NSString *)fileName { + NSArray *bundles = [FIRBundleUtil relevantBundles]; + NSString *plistFilePath = + [FIRBundleUtil optionsDictionaryPathWithResourceName:fileName + andFileType:kServiceInfoFileType + inBundles:bundles]; + if (plistFilePath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000012", @"Could not locate configuration file: '%@.%@'.", + fileName, kServiceInfoFileType); + } + return plistFilePath; +} + ++ (void)resetDefaultOptions { + sDefaultOptions = nil; + sDefaultOptionsDictionary = nil; + sDefaultOptionsOnceToken = 0; + sDefaultOptionsDictionaryOnceToken = 0; +} + +#pragma mark - Private instance methods + +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)optionsDictionary { + self = [super init]; + if (self) { + _optionsDictionary = [optionsDictionary mutableCopy]; + _usingOptionsFromDefaultPlist = YES; + } + return self; +} + +- (id)copyWithZone:(NSZone *)zone { + FIROptions *newOptions = [(FIROptions *)[[self class] allocWithZone:zone] + initInternalWithOptionsDictionary:self.optionsDictionary]; + if (newOptions) { + newOptions.deepLinkURLScheme = self.deepLinkURLScheme; + newOptions.appGroupID = self.appGroupID; + newOptions.editingLocked = self.isEditingLocked; + newOptions.usingOptionsFromDefaultPlist = self.usingOptionsFromDefaultPlist; + } + return newOptions; +} + +#pragma mark - Public instance methods + +- (instancetype)init { + // Unavailable. + [self doesNotRecognizeSelector:_cmd]; + return nil; +} + +- (instancetype)initWithContentsOfFile:(NSString *)plistPath { + self = [super init]; + if (self) { + if (plistPath == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000013", @"The plist file path is nil."); + return nil; + } + _optionsDictionary = [[NSDictionary dictionaryWithContentsOfFile:plistPath] mutableCopy]; + if (_optionsDictionary == nil) { + FIRLogError(kFIRLoggerCore, @"I-COR000014", + @"The configuration file at %@ does not exist or " + @"is not a well-formed plist file.", + plistPath); + return nil; + } + // TODO: Do we want to validate the dictionary here? It says we do that already in + // the public header. + } + return self; +} + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID GCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + NSMutableDictionary *mutableOptionsDict = [NSMutableDictionary dictionary]; + [mutableOptionsDict setValue:googleAppID forKey:kFIRGoogleAppID]; + [mutableOptionsDict setValue:GCMSenderID forKey:kFIRGCMSenderID]; + [mutableOptionsDict setValue:[[NSBundle mainBundle] bundleIdentifier] forKey:kFIRBundleID]; + self.optionsDictionary = mutableOptionsDict; + } + return self; +} + +- (NSString *)APIKey { + return self.optionsDictionary[kFIRAPIKey]; +} + +- (void)checkEditingLocked { + if (self.isEditingLocked) { + [NSException raise:kFirebaseCoreErrorDomain format:kFIRExceptionBadModification]; + } +} + +- (void)setAPIKey:(NSString *)APIKey { + [self checkEditingLocked]; + _optionsDictionary[kFIRAPIKey] = [APIKey copy]; +} + +- (NSString *)clientID { + return self.optionsDictionary[kFIRClientID]; +} + +- (void)setClientID:(NSString *)clientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRClientID] = [clientID copy]; +} + +- (NSString *)trackingID { + return self.optionsDictionary[kFIRTrackingID]; +} + +- (void)setTrackingID:(NSString *)trackingID { + [self checkEditingLocked]; + _optionsDictionary[kFIRTrackingID] = [trackingID copy]; +} + +- (NSString *)GCMSenderID { + return self.optionsDictionary[kFIRGCMSenderID]; +} + +- (void)setGCMSenderID:(NSString *)GCMSenderID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGCMSenderID] = [GCMSenderID copy]; +} + +- (NSString *)projectID { + return self.optionsDictionary[kFIRProjectID]; +} + +- (void)setProjectID:(NSString *)projectID { + [self checkEditingLocked]; + _optionsDictionary[kFIRProjectID] = [projectID copy]; +} + +- (NSString *)androidClientID { + return self.optionsDictionary[kFIRAndroidClientID]; +} + +- (void)setAndroidClientID:(NSString *)androidClientID { + [self checkEditingLocked]; + _optionsDictionary[kFIRAndroidClientID] = [androidClientID copy]; +} + +- (NSString *)googleAppID { + return self.optionsDictionary[kFIRGoogleAppID]; +} + +- (void)setGoogleAppID:(NSString *)googleAppID { + [self checkEditingLocked]; + _optionsDictionary[kFIRGoogleAppID] = [googleAppID copy]; +} + +- (NSString *)libraryVersionID { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // The unit tests are set up to catch anything that does not properly convert. + NSString *version = FIRFirebaseVersion(); + NSArray *components = [version componentsSeparatedByString:@"."]; + NSString *major = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:0] intValue]]; + NSString *minor = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:1] intValue]]; + NSString *patch = [NSString stringWithFormat:@"%02d", [[components objectAtIndex:2] intValue]]; + kFIRLibraryVersionID = [NSString stringWithFormat:@"%@%@%@000", major, minor, patch]; + }); + return kFIRLibraryVersionID; +} + +- (void)setLibraryVersionID:(NSString *)libraryVersionID { + _optionsDictionary[kFIRLibraryVersionID] = [libraryVersionID copy]; +} + +- (NSString *)databaseURL { + return self.optionsDictionary[kFIRDatabaseURL]; +} + +- (void)setDatabaseURL:(NSString *)databaseURL { + [self checkEditingLocked]; + + _optionsDictionary[kFIRDatabaseURL] = [databaseURL copy]; +} + +- (NSString *)storageBucket { + return self.optionsDictionary[kFIRStorageBucket]; +} + +- (void)setStorageBucket:(NSString *)storageBucket { + [self checkEditingLocked]; + _optionsDictionary[kFIRStorageBucket] = [storageBucket copy]; +} + +- (void)setDeepLinkURLScheme:(NSString *)deepLinkURLScheme { + [self checkEditingLocked]; + _deepLinkURLScheme = [deepLinkURLScheme copy]; +} + +- (NSString *)bundleID { + return self.optionsDictionary[kFIRBundleID]; +} + +- (void)setBundleID:(NSString *)bundleID { + [self checkEditingLocked]; + _optionsDictionary[kFIRBundleID] = [bundleID copy]; +} + +- (void)setAppGroupID:(NSString *)appGroupID { + [self checkEditingLocked]; + _appGroupID = [appGroupID copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqual:(id)object { + if (!object || ![object isKindOfClass:[FIROptions class]]) { + return NO; + } + + return [self isEqualToOptions:(FIROptions *)object]; +} + +- (BOOL)isEqualToOptions:(FIROptions *)options { + // Skip any non-FIROptions classes. + if (![options isKindOfClass:[FIROptions class]]) { + return NO; + } + + // Check the internal dictionary and custom properties for differences. + if (![options.optionsDictionary isEqualToDictionary:self.optionsDictionary]) { + return NO; + } + + // Validate extra properties not contained in the dictionary. Only validate it if one of the + // objects has the property set. + if ((options.deepLinkURLScheme != nil || self.deepLinkURLScheme != nil) && + ![options.deepLinkURLScheme isEqualToString:self.deepLinkURLScheme]) { + return NO; + } + + if ((options.appGroupID != nil || self.appGroupID != nil) && + ![options.appGroupID isEqualToString:self.appGroupID]) { + return NO; + } + + // Validate the Analytics options haven't changed with the Info.plist. + if (![options.analyticsOptionsDictionary isEqualToDictionary:self.analyticsOptionsDictionary]) { + return NO; + } + + // We don't care about the `editingLocked` or `usingOptionsFromDefaultPlist` properties since + // those relate to lifecycle and construction, we only care if the contents of the options + // themselves are equal. + return YES; +} + +- (NSUInteger)hash { + // This is strongly recommended for any object that implements a custom `isEqual:` method to + // ensure that dictionary and set behavior matches other `isEqual:` checks. + // Note: `self.analyticsOptionsDictionary` was left out here since it solely relies on the + // contents of the main bundle's `Info.plist`. We should avoid reading that file and the contents + // should be identical. + return self.optionsDictionary.hash ^ self.deepLinkURLScheme.hash ^ self.appGroupID.hash; +} + +#pragma mark - Internal instance methods + +- (NSDictionary *)analyticsOptionsDictionaryWithInfoDictionary:(NSDictionary *)infoDictionary { + if (_analyticsOptionsDictionary == nil) { + NSMutableDictionary *tempAnalyticsOptions = [[NSMutableDictionary alloc] init]; + NSArray *measurementKeys = @[ + kFIRIsMeasurementEnabled, kFIRIsAnalyticsCollectionEnabled, + kFIRIsAnalyticsCollectionDeactivated + ]; + for (NSString *key in measurementKeys) { + id value = infoDictionary[key] ?: self.optionsDictionary[key] ?: nil; + if (!value) { + continue; + } + tempAnalyticsOptions[key] = value; + } + _analyticsOptionsDictionary = tempAnalyticsOptions; + } + return _analyticsOptionsDictionary; +} + +- (NSDictionary *)analyticsOptionsDictionary { + return [self analyticsOptionsDictionaryWithInfoDictionary:[NSBundle mainBundle].infoDictionary]; +} + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. This uses the old plist flag IS_MEASUREMENT_ENABLED, which should still + * be supported. + */ +- (BOOL)isMeasurementEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (value == nil) { + // TODO: This could probably be cleaned up since FIROptions shouldn't know about FIRApp or have + // to check if it's the default app. The FIROptions instance can't be modified after + // `+configure` is called, so it's not a good place to copy it either in case the flag is + // changed at runtime. + + // If no values are set for Analytics, fall back to the global collection switch in FIRApp. + // Analytics only supports the default FIRApp, so check that first. + if (![FIRApp isDefaultAppConfigured]) { + return NO; + } + + // Fall back to the default app's collection switch when the key is not in the dictionary. + return [FIRApp defaultApp].isDataCollectionDefaultEnabled; + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionExplicitlySet { + // If it's de-activated, it classifies as explicitly set. If not, it's not a good enough + // indication that the developer wants FirebaseAnalytics enabled so continue checking. + if (self.isAnalyticsCollectionDeactivated) { + return YES; + } + + // Check if the current Analytics flag is set. + id collectionEnabledObject = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (collectionEnabledObject && [collectionEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // Check if the old measurement flag is set. + id measurementEnabledObject = self.analyticsOptionsDictionary[kFIRIsMeasurementEnabled]; + if (measurementEnabledObject && [measurementEnabledObject isKindOfClass:[NSNumber class]]) { + // It doesn't matter what the value is, it's explicitly set. + return YES; + } + + // No flags are set to explicitly enable or disable FirebaseAnalytics. + return NO; +} + +- (BOOL)isAnalyticsCollectionEnabled { + if (self.isAnalyticsCollectionDeactivated) { + return NO; + } + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionEnabled]; + if (value == nil) { + return self.isMeasurementEnabled; // Fall back to older plist flag. + } + return [value boolValue]; +} + +- (BOOL)isAnalyticsCollectionDeactivated { + NSNumber *value = self.analyticsOptionsDictionary[kFIRIsAnalyticsCollectionDeactivated]; + if (value == nil) { + return NO; // Analytics Collection is not deactivated when the key is not in the dictionary. + } + return [value boolValue]; +} + +@end diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m new file mode 100644 index 0000000..8db07ce --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestamp.m @@ -0,0 +1,152 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/FIRTimestampInternal.h" + +NS_ASSUME_NONNULL_BEGIN + +static const int kNanosPerSecond = 1000000000; + +@implementation FIRTimestamp (Internal) + +#pragma mark - Internal public methods + +- (NSString *)ISO8601String { + NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; + formatter.dateFormat = @"yyyy-MM-dd'T'HH:mm:ss"; + formatter.timeZone = [NSTimeZone timeZoneWithName:@"UTC"]; + NSDate *secondsDate = [NSDate dateWithTimeIntervalSince1970:self.seconds]; + NSString *secondsString = [formatter stringFromDate:secondsDate]; + if (secondsString.length != 19) { + [NSException raise:@"Invalid ISO string" format:@"Invalid ISO string: %@", secondsString]; + } + + NSString *nanosString = [NSString stringWithFormat:@"%09d", self.nanoseconds]; + return [NSString stringWithFormat:@"%@.%@Z", secondsString, nanosString]; +} + +@end + +@implementation FIRTimestamp + +#pragma mark - Constructors + ++ (instancetype)timestampWithDate:(NSDate *)date { + double secondsDouble; + double fraction = modf(date.timeIntervalSince1970, &secondsDouble); + // GCP Timestamps always have non-negative nanos. + if (fraction < 0) { + fraction += 1.0; + secondsDouble -= 1.0; + } + int64_t seconds = (int64_t)secondsDouble; + int32_t nanos = (int32_t)(fraction * kNanosPerSecond); + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanos]; +} + ++ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + return [[FIRTimestamp alloc] initWithSeconds:seconds nanoseconds:nanoseconds]; +} + ++ (instancetype)timestamp { + return [FIRTimestamp timestampWithDate:[NSDate date]]; +} + +- (instancetype)initWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds { + self = [super init]; + if (self) { + if (nanoseconds < 0) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + if (nanoseconds >= 1e9) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp nanoseconds out of range: %d", nanoseconds]; + } + // Midnight at the beginning of 1/1/1 is the earliest timestamp supported. + if (seconds < -62135596800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + // This will break in the year 10,000. + if (seconds >= 253402300800L) { + [NSException raise:@"Invalid timestamp" + format:@"Timestamp seconds out of range: %lld", seconds]; + } + + _seconds = seconds; + _nanoseconds = nanoseconds; + } + return self; +} + +#pragma mark - NSObject methods + +- (BOOL)isEqual:(id)object { + if (self == object) { + return YES; + } + if (![object isKindOfClass:[FIRTimestamp class]]) { + return NO; + } + return [self isEqualToTimestamp:(FIRTimestamp *)object]; +} + +- (NSUInteger)hash { + return (NSUInteger)((self.seconds >> 32) ^ self.seconds ^ self.nanoseconds); +} + +- (NSString *)description { + return [NSString stringWithFormat:@"", self.seconds, + self.nanoseconds]; +} + +/** Implements NSCopying without actually copying because timestamps are immutable. */ +- (id)copyWithZone:(__unused NSZone *_Nullable)zone { + return self; +} + +#pragma mark - Public methods + +- (NSDate *)dateValue { + NSTimeInterval interval = (NSTimeInterval)self.seconds + ((NSTimeInterval)self.nanoseconds) / 1e9; + return [NSDate dateWithTimeIntervalSince1970:interval]; +} + +- (NSComparisonResult)compare:(FIRTimestamp *)other { + if (self.seconds < other.seconds) { + return NSOrderedAscending; + } else if (self.seconds > other.seconds) { + return NSOrderedDescending; + } + + if (self.nanoseconds < other.nanoseconds) { + return NSOrderedAscending; + } else if (self.nanoseconds > other.nanoseconds) { + return NSOrderedDescending; + } + return NSOrderedSame; +} + +#pragma mark - Private methods + +- (BOOL)isEqualToTimestamp:(FIRTimestamp *)other { + return [self compare:other] == NSOrderedSame; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h b/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h new file mode 100644 index 0000000..6261c63 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRTimestampInternal.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Internal FIRTimestamp API we don't want exposed in our public header files. */ +@interface FIRTimestamp (Internal) + +/** + * Converts the given date to an ISO 8601 timestamp string, useful for rendering in JSON. + * + * ISO 8601 dates times in UTC look like this: "1912-04-14T23:40:00.000000000Z". + * + * @see http://www.ecma-international.org/ecma-262/6.0/#sec-date-time-string-format + */ +- (NSString *)ISO8601String; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m b/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m new file mode 100644 index 0000000..f458a3a --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/FIRVersion.m @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h" + +#ifndef Firebase_VERSION +#error "Firebase_VERSION is not defined: add -DFirebase_VERSION=... to the build invocation" +#endif + +// The following two macros supply the incantation so that the C +// preprocessor does not try to parse the version as a floating +// point number. See +// https://www.guyrutenberg.com/2008/12/20/expanding-macros-into-string-constants-in-c/ +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x + +NSString* FIRFirebaseVersion(void) { + return @STR(Firebase_VERSION); +} diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h new file mode 100644 index 0000000..58ef2a6 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRApp.h @@ -0,0 +1,129 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIROptions; + +NS_ASSUME_NONNULL_BEGIN + +/** A block that takes a BOOL and has no return value. */ +typedef void (^FIRAppVoidBoolCallback)(BOOL success) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The entry point of Firebase SDKs. + * + * Initialize and configure `FirebaseApp` using `FirebaseApp.configure()` + * or other customized ways as shown below. + * + * The logging system has two modes: default mode and debug mode. In default mode, only logs with + * log level Notice, Warning and Error will be sent to device. In debug mode, all logs will be sent + * to device. The log levels that Firebase uses are consistent with the ASL log levels. + * + * Enable debug mode by passing the `-FIRDebugEnabled` argument to the application. You can add this + * argument in the application's Xcode scheme. When debug mode is enabled via `-FIRDebugEnabled`, + * further executions of the application will also be in debug mode. In order to return to default + * mode, you must explicitly disable the debug mode with the application argument + * `-FIRDebugDisabled`. + * + * It is also possible to change the default logging level in code by calling + * `FirebaseConfiguration.shared.setLoggerLevel(_:)` with the desired level. + */ +NS_SWIFT_NAME(FirebaseApp) +@interface FIRApp : NSObject + +/** + * Configures a default Firebase app. Raises an exception if any configuration step fails. The + * default app is named "__FIRAPP_DEFAULT". This method should be called after the app is launched + * and before using Firebase services. This method should be called from the main thread and + * contains synchronous file I/O (reading GoogleService-Info.plist from disk). + */ ++ (void)configure; + +/** + * Configures the default Firebase app with the provided options. The default app is named + * "__FIRAPP_DEFAULT". Raises an exception if any configuration step fails. This method should be + * called from the main thread. + * + * @param options The Firebase application options used to configure the service. + */ ++ (void)configureWithOptions:(FIROptions *)options NS_SWIFT_NAME(configure(options:)); + +/** + * Configures a Firebase app with the given name and options. Raises an exception if any + * configuration step fails. This method should be called from the main thread. + * + * @param name The application's name given by the developer. The name should should only contain + Letters, Numbers and Underscore. + * @param options The Firebase application options used to configure the services. + */ +// clang-format off ++ (void)configureWithName:(NSString *)name + options:(FIROptions *)options NS_SWIFT_NAME(configure(name:options:)); +// clang-format on + +/** + * Returns the default app, or `nil` if the default app does not exist. + */ ++ (nullable FIRApp *)defaultApp NS_SWIFT_NAME(app()); + +/** + * Returns a previously created `FirebaseApp` instance with the given name, or `nil` if no such app + * exists. This method is thread safe. + */ ++ (nullable FIRApp *)appNamed:(NSString *)name NS_SWIFT_NAME(app(name:)); + +/** + * Returns the set of all extant `FirebaseApp` instances, or `nil` if there are no `FirebaseApp` + * instances. This method is thread safe. + */ +@property(class, readonly, nullable) NSDictionary *allApps; + +/** + * Cleans up the current `FirebaseApp`, freeing associated data and returning its name to the pool + * for future use. This method is thread safe. + */ +- (void)deleteApp:(void (^)(BOOL success))completion; + +/** + * `FirebaseApp` instances should not be initialized directly. Call `FirebaseApp.configure()`, + * `FirebaseApp.configure(options:)`, or `FirebaseApp.configure(name:options:)` directly. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Gets the name of this app. + */ +@property(nonatomic, copy, readonly) NSString *name; + +/** + * Gets a copy of the options for this app. These are non-modifiable. + */ +@property(nonatomic, copy, readonly) FIROptions *options; + +/** + * Gets or sets whether automatic data collection is enabled for all products. Defaults to `true` + * unless `FirebaseDataCollectionDefaultEnabled` is set to `NO` in your app's Info.plist. This value + * is persisted across runs of the app so that it can be set once when users have consented to + * collection. + */ +@property(nonatomic, readwrite, getter=isDataCollectionDefaultEnabled) + BOOL dataCollectionDefaultEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h new file mode 100644 index 0000000..408bcad --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRConfiguration.h @@ -0,0 +1,45 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FIRLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This interface provides global level properties that the developer can tweak. + */ +NS_SWIFT_NAME(FirebaseConfiguration) +@interface FIRConfiguration : NSObject + +/** Returns the shared configuration object. */ +@property(class, nonatomic, readonly) FIRConfiguration *sharedInstance NS_SWIFT_NAME(shared); + +/** + * Sets the logging level for internal Firebase logging. Firebase will only log messages + * that are logged at or below `loggerLevel`. The messages are logged both to the Xcode + * console and to the device's log. Note that if an app is running from AppStore, it will + * never log above `.notice` even if `loggerLevel` is set to a higher (more verbose) + * setting. + * + * @param loggerLevel The maximum logging level. The default level is set to FIRLoggerLevelNotice. + */ +- (void)setLoggerLevel:(FIRLoggerLevel)loggerLevel; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h new file mode 100644 index 0000000..dca3aa0 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRLoggerLevel.h @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Note that importing GULLoggerLevel.h will lead to a non-modular header +// import error. + +/** + * The log levels used by internal logging. + */ +typedef NS_ENUM(NSInteger, FIRLoggerLevel) { + /** Error level, matches ASL_LEVEL_ERR. */ + FIRLoggerLevelError = 3, + /** Warning level, matches ASL_LEVEL_WARNING. */ + FIRLoggerLevelWarning = 4, + /** Notice level, matches ASL_LEVEL_NOTICE. */ + FIRLoggerLevelNotice = 5, + /** Info level, matches ASL_LEVEL_INFO. */ + FIRLoggerLevelInfo = 6, + /** Debug level, matches ASL_LEVEL_DEBUG. */ + FIRLoggerLevelDebug = 7, + /** Minimum log level. */ + FIRLoggerLevelMin = FIRLoggerLevelError, + /** Maximum log level. */ + FIRLoggerLevelMax = FIRLoggerLevelDebug +} NS_SWIFT_NAME(FirebaseLoggerLevel); diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h new file mode 100644 index 0000000..8f8d945 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIROptions.h @@ -0,0 +1,131 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class provides constant fields of Google APIs. + */ +NS_SWIFT_NAME(FirebaseOptions) +@interface FIROptions : NSObject + +/** + * Returns the default options. The first time this is called it synchronously reads + * GoogleService-Info.plist from disk. + */ ++ (nullable FIROptions *)defaultOptions NS_SWIFT_NAME(defaultOptions()); + +/** + * An API key used for authenticating requests from your Apple app, e.g. + * The key must begin with "A" and contain exactly 39 alphanumeric characters, used to identify your + * app to Google servers. + */ +@property(nonatomic, copy, nullable) NSString *APIKey NS_SWIFT_NAME(apiKey); + +/** + * The bundle ID for the application. Defaults to `Bundle.main.bundleIdentifier` when not set + * manually or in a plist. + */ +@property(nonatomic, copy) NSString *bundleID; + +/** + * The OAuth2 client ID for Apple applications used to authenticate Google users, for example + * @"12345.apps.googleusercontent.com", used for signing in with Google. + */ +@property(nonatomic, copy, nullable) NSString *clientID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *trackingID DEPRECATED_ATTRIBUTE; + +/** + * The Project Number from the Google Developer's console, for example @"012345678901", used to + * configure Firebase Cloud Messaging. + */ +@property(nonatomic, copy) NSString *GCMSenderID NS_SWIFT_NAME(gcmSenderID); + +/** + * The Project ID from the Firebase console, for example @"abc-xyz-123". + */ +@property(nonatomic, copy, nullable) NSString *projectID; + +/** + * Unused. + */ +@property(nonatomic, copy, nullable) NSString *androidClientID DEPRECATED_ATTRIBUTE; + +/** + * The Google App ID that is used to uniquely identify an instance of an app. + */ +@property(nonatomic, copy) NSString *googleAppID; + +/** + * The database root URL, e.g. @"http://abc-xyz-123.firebaseio.com". + */ +@property(nonatomic, copy, nullable) NSString *databaseURL; + +/** + * The URL scheme used to set up Durable Deep Link service. + */ +@property(nonatomic, copy, nullable) NSString *deepLinkURLScheme; + +/** + * The Google Cloud Storage bucket name, e.g. @"abc-xyz-123.storage.firebase.com". + */ +@property(nonatomic, copy, nullable) NSString *storageBucket; + +/** + * The App Group identifier to share data between the application and the application extensions. + * The App Group must be configured in the application and on the Apple Developer Portal. Default + * value `nil`. + */ +@property(nonatomic, copy, nullable) NSString *appGroupID; + +/** + * Initializes a customized instance of FirebaseOptions from the file at the given plist file path. + * This will read the file synchronously from disk. + * For example: + * ```swift + * if let path = Bundle.main.path(forResource:"GoogleServices-Info", ofType:"plist") { + * let options = FirebaseOptions(contentsOfFile: path) + * } + * ``` + * Note that it is not possible to customize `FirebaseOptions` for Firebase Analytics which expects + * a static file named `GoogleServices-Info.plist` - + * https://github.com/firebase/firebase-ios-sdk/issues/230. + * Returns `nil` if the plist file does not exist or is invalid. + */ +- (nullable instancetype)initWithContentsOfFile:(NSString *)plistPath NS_DESIGNATED_INITIALIZER; + +/** + * Initializes a customized instance of `FirebaseOptions` with required fields. Use the mutable + * properties to modify fields for configuring specific services. Note that it is not possible to + * customize `FirebaseOptions` for Firebase Analytics which expects a static file named + * `GoogleServices-Info.plist` - https://github.com/firebase/firebase-ios-sdk/issues/230. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + GCMSenderID:(NSString *)GCMSenderID + NS_SWIFT_NAME(init(googleAppID:gcmSenderID:))NS_DESIGNATED_INITIALIZER; + +/** Unavailable. Please use `init(contentsOfFile:)` or `init(googleAppID:gcmSenderID:)` instead. */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h new file mode 100644 index 0000000..375f697 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRTimestamp.h @@ -0,0 +1,89 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A Timestamp represents a point in time independent of any time zone or calendar, represented as + * seconds and fractions of seconds at nanosecond resolution in UTC Epoch time. It is encoded using + * the Proleptic Gregorian Calendar which extends the Gregorian calendar backwards to year one. It + * is encoded assuming all minutes are 60 seconds long, i.e. leap seconds are "smeared" so that no + * leap second table is needed for interpretation. Range is from 0001-01-01T00:00:00Z to + * 9999-12-31T23:59:59.999999999Z. By restricting to that range, we ensure that we can convert to + * and from RFC 3339 date strings. + * + * @see https://github.com/google/protobuf/blob/main/src/google/protobuf/timestamp.proto for the + * reference timestamp definition. + */ +NS_SWIFT_NAME(Timestamp) +@interface FIRTimestamp : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates a new timestamp. + * + * @param seconds the number of seconds since epoch. + * @param nanoseconds the number of nanoseconds after the seconds. + */ +- (instancetype)initWithSeconds:(int64_t)seconds + nanoseconds:(int32_t)nanoseconds NS_DESIGNATED_INITIALIZER; + +/** + * Creates a new timestamp. + * + * @param seconds the number of seconds since epoch. + * @param nanoseconds the number of nanoseconds after the seconds. + */ ++ (instancetype)timestampWithSeconds:(int64_t)seconds nanoseconds:(int32_t)nanoseconds; + +/** Creates a new timestamp from the given date. */ ++ (instancetype)timestampWithDate:(NSDate *)date; + +/** Creates a new timestamp with the current date / time. */ ++ (instancetype)timestamp; + +/** Returns a new `Date` corresponding to this timestamp. This may lose precision. */ +- (NSDate *)dateValue; + +/** + * Returns the result of comparing the receiver with another timestamp. + * @param other the other timestamp to compare. + * @return `orderedAscending` if `other` is chronologically following self, + * `orderedDescending` if `other` is chronologically preceding self, + * `orderedSame` otherwise. + */ +- (NSComparisonResult)compare:(FIRTimestamp *)other; + +/** + * Represents seconds of UTC time since Unix epoch 1970-01-01T00:00:00Z. + * Must be from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59Z inclusive. + */ +@property(nonatomic, assign, readonly) int64_t seconds; + +/** + * Non-negative fractions of a second at nanosecond resolution. Negative second values with + * fractions must still have non-negative nanos values that count forward in time. + * Must be from 0 to 999,999,999 inclusive. + */ +@property(nonatomic, assign, readonly) int32_t nanoseconds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h new file mode 100644 index 0000000..651edaf --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FIRVersion.h @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Returns the current version of Firebase. */ +NS_SWIFT_NAME(FirebaseVersion()) +NSString* FIRFirebaseVersion(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h new file mode 100644 index 0000000..fff8631 --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Public/FirebaseCore/FirebaseCore.h @@ -0,0 +1,22 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRTimestamp.h" +#import "FIRVersion.h" diff --git a/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..0244f2f --- /dev/null +++ b/Pods/FirebaseCore/FirebaseCore/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,26 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + + diff --git a/Pods/FirebaseCore/LICENSE b/Pods/FirebaseCore/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseCore/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseCore/README.md b/Pods/FirebaseCore/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseCore/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..c89c88f --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,18 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/Pods/FirebaseCoreExtension/FirebaseCore/Extension/dummy.m b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/dummy.m new file mode 100644 index 0000000..2e503fe --- /dev/null +++ b/Pods/FirebaseCoreExtension/FirebaseCore/Extension/dummy.m @@ -0,0 +1,17 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// Swift Package Manager needs at least one source file. diff --git a/Pods/FirebaseCoreExtension/LICENSE b/Pods/FirebaseCoreExtension/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseCoreExtension/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseCoreExtension/README.md b/Pods/FirebaseCoreExtension/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseCoreExtension/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift new file mode 100644 index 0000000..aa265ed --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Heartbeat.swift @@ -0,0 +1,76 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An enumeration of time periods. +enum TimePeriod: Int, CaseIterable, Codable { + /// The raw value is the number of calendar days within each time period. + /// More types can be enabled in future iterations (i.e. `weekly = 7, monthly = 28`). + case daily = 1 + + /// The number of seconds in a given time period. + var timeInterval: TimeInterval { + Double(rawValue) * 86400 /* seconds in day */ + } +} + +/// A structure representing SDK usage. +struct Heartbeat: Codable, Equatable { + /// The version of the heartbeat. + private static let version: Int = 0 + + /// An anonymous string of information (i.e. user agent) to associate the heartbeat with. + let agent: String + + /// The date when the heartbeat was recorded. + let date: Date + + /// The heartbeat's model version. + let version: Int + + /// An array of `TimePeriod`s that the heartbeat is tagged with. See `TimePeriod`. + /// + /// Heartbeats represent anonymous data points that measure SDK usage in moving averages for + /// various time periods. Because a single heartbeat can help calculate moving averages for + /// multiple + /// time periods, this property serves to capture all the time periods that the heartbeat can + /// represent in + /// a moving average. + let timePeriods: [TimePeriod] + + /// Designated initializer. + /// - Parameters: + /// - agent: An anonymous string of information to associate the heartbeat with. + /// - date: The date when the heartbeat was recorded. + /// - version: The heartbeat's version. Defaults to the current version. + init(agent: String, + date: Date, + timePeriods: [TimePeriod] = [], + version: Int = version) { + self.agent = agent + self.date = date + self.timePeriods = timePeriods + self.version = version + } +} + +extension Heartbeat: HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let userAgentPayloads = [ + HeartbeatsPayload.UserAgentPayload(agent: agent, dates: [date]), + ] + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift new file mode 100644 index 0000000..93b335a --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatController.swift @@ -0,0 +1,157 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +public final class HeartbeatController { + /// Used for standardizing dates for calendar-day comparison. + private enum DateStandardizer { + private static let calendar: Calendar = { + var calendar = Calendar(identifier: .iso8601) + calendar.locale = Locale(identifier: "en_US_POSIX") + calendar.timeZone = TimeZone(secondsFromGMT: 0)! + return calendar + }() + + static func standardize(_ date: Date) -> (Date) { + return calendar.startOfDay(for: date) + } + } + + /// The thread-safe storage object to log and flush heartbeats from. + private let storage: HeartbeatStorageProtocol + /// The max capacity of heartbeats to store in storage. + private let heartbeatsStorageCapacity: Int = 30 + /// Current date provider. It is used for testability. + private let dateProvider: () -> Date + /// Used for standardizing dates for calendar-day comparison. + private static let dateStandardizer = DateStandardizer.self + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public convenience init(id: String) { + self.init(id: id, dateProvider: Date.init) + } + + /// Convenience initializer. Mirrors the semantics of the public initializer with the added + /// benefit of + /// injecting a custom date provider for improved testability. + /// - Parameters: + /// - id: The id to associate this controller's heartbeat storage with. + /// - dateProvider: A date provider. + convenience init(id: String, dateProvider: @escaping () -> Date) { + let storage = HeartbeatStorage.getInstance(id: id) + self.init(storage: storage, dateProvider: dateProvider) + } + + /// Designated initializer. + /// - Parameters: + /// - storage: A heartbeat storage container. + /// - dateProvider: A date provider. Defaults to providing the current date. + init(storage: HeartbeatStorageProtocol, + dateProvider: @escaping () -> Date = Date.init) { + self.storage = storage + self.dateProvider = { Self.dateStandardizer.standardize(dateProvider()) } + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged + /// heartbeat with. + public func log(_ agent: String) { + let date = dateProvider() + + storage.readAndWriteAsync { heartbeatsBundle in + var heartbeatsBundle = heartbeatsBundle ?? + HeartbeatsBundle(capacity: self.heartbeatsStorageCapacity) + + // Filter for the time periods where the last heartbeat to be logged for + // that time period was logged more than one time period (i.e. day) ago. + let timePeriods = heartbeatsBundle.lastAddedHeartbeatDates.filter { timePeriod, lastDate in + date.timeIntervalSince(lastDate) >= timePeriod.timeInterval + } + .map { timePeriod, _ in timePeriod } + + if !timePeriods.isEmpty { + // A heartbeat should only be logged if there is a time period(s) to + // associate it with. + let heartbeat = Heartbeat(agent: agent, date: date, timePeriods: timePeriods) + heartbeatsBundle.append(heartbeat) + } + + return heartbeatsBundle + } + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: The flushed heartbeats in the form of `HeartbeatsPayload`. + @discardableResult + public func flush() -> HeartbeatsPayload { + let resetTransform = { (heartbeatsBundle: HeartbeatsBundle?) -> HeartbeatsBundle? in + guard let oldHeartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + // The new value that's stored will use the old's cache to prevent the + // logging of duplicates after flushing. + return HeartbeatsBundle( + capacity: self.heartbeatsStorageCapacity, + cache: oldHeartbeatsBundle.lastAddedHeartbeatDates + ) + } + + do { + // Synchronously gets and returns the stored heartbeats, resetting storage + // using the given transform. + let heartbeatsBundle = try storage.getAndSet(using: resetTransform) + // If no heartbeats bundle was stored, return an empty payload. + return heartbeatsBundle?.makeHeartbeatsPayload() ?? HeartbeatsPayload.emptyPayload + } catch { + // If the operation throws, assume no heartbeat(s) were retrieved or set. + return HeartbeatsPayload.emptyPayload + } + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + @discardableResult + public func flushHeartbeatFromToday() -> HeartbeatsPayload { + let todaysDate = dateProvider() + var todaysHeartbeat: Heartbeat? + + storage.readAndWriteSync { heartbeatsBundle in + guard var heartbeatsBundle = heartbeatsBundle else { + return nil // Storage was empty. + } + + todaysHeartbeat = heartbeatsBundle.removeHeartbeat(from: todaysDate) + + return heartbeatsBundle + } + + // Note that `todaysHeartbeat` is updated in the above read/write block. + if todaysHeartbeat != nil { + return todaysHeartbeat!.makeHeartbeatsPayload() + } else { + return HeartbeatsPayload.emptyPayload + } + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift new file mode 100644 index 0000000..96dbcf8 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatLoggingTestUtils.swift @@ -0,0 +1,140 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if DEBUG + + import Foundation + + /// A utility class intended to be used only in testing contexts. + @objc(FIRHeartbeatLoggingTestUtils) + @objcMembers + public class HeartbeatLoggingTestUtils: NSObject { + /// This should mirror the `Constants` enum in the `HeartbeatLogging` module. + /// See `HeartbeatLogging/Sources/StorageFactory.swift`. + public enum Constants { + /// The name of the file system directory where heartbeat data is stored. + public static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + public static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" + } + + public static var dateFormatter: DateFormatter { + HeartbeatsPayload.dateFormatter + } + + public static var emptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + public static var nonEmptyHeartbeatsPayload: _ObjC_HeartbeatsPayload { + let literalData = """ + { + "version": 2, + "heartbeats": [ + { + "agent": "dummy_agent_1", + "dates": ["2021-11-01", "2021-11-02"] + }, + { + "agent": "dummy_agent_2", + "dates": ["2021-11-03"] + } + ] + } + """ + .data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let heartbeatsPayload = try! decoder.decode(HeartbeatsPayload.self, from: literalData) + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + @objc(assertEncodedPayloadString:isEqualToLiteralString:withError:) + public static func assertEqualPayloadStrings(_ encoded: String, _ literal: String) throws { + var encodedData = Data(base64URLEncoded: encoded)! + if encodedData.count > 0 { + encodedData = try! encodedData.unzipped() + } + + let literalData = literal.data(using: .utf8)! + + let decoder = JSONDecoder() + decoder.dateDecodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + + let payloadFromEncoded = try? decoder.decode(HeartbeatsPayload.self, from: encodedData) + + let payloadFromLiteral = try? decoder.decode(HeartbeatsPayload.self, from: literalData) + + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(HeartbeatsPayload.dateFormatter) + encoder.outputFormatting = .prettyPrinted + + let payloadDataFromEncoded = try! encoder.encode(payloadFromEncoded) + let payloadDataFromLiteral = try! encoder.encode(payloadFromLiteral) + + assert( + payloadFromEncoded == payloadFromLiteral, + """ + Mismatched payloads! + + Payload 1: + \(String(data: payloadDataFromEncoded, encoding: .utf8) ?? "") + + Payload 2: + \(String(data: payloadDataFromLiteral, encoding: .utf8) ?? "") + + """ + ) + } + + /// Removes all underlying storage containers used by the module. + /// - Throws: An error if the storage container could not be removed. + public static func removeUnderlyingHeartbeatStorageContainers() throws { + #if os(tvOS) + UserDefaults().removePersistentDomain(forName: Constants.heartbeatUserDefaultsSuiteName) + #else + + let applicationSupportDirectory = FileManager.default + .urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + + let heartbeatsDirectoryURL = applicationSupportDirectory + .appendingPathComponent( + Constants.heartbeatFileStorageDirectoryPath, isDirectory: true + ) + do { + try FileManager.default.removeItem(at: heartbeatsDirectoryURL) + } catch CocoaError.fileNoSuchFile { + // Do nothing. + } catch { + throw error + } + #endif // os(tvOS) + } + } + +#endif // ENABLE_FIREBASE_CORE_INTERNAL_TESTING_UTILS diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift new file mode 100644 index 0000000..e5bb83f --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatStorage.swift @@ -0,0 +1,180 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that can perform atomic operations using block-based transformations. +protocol HeartbeatStorageProtocol { + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) + func readAndWriteAsync(using transform: @escaping (HeartbeatsBundle?) -> HeartbeatsBundle?) + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? +} + +/// Thread-safe storage object designed for transforming heartbeat data that is persisted to disk. +final class HeartbeatStorage: HeartbeatStorageProtocol { + /// The identifier used to differentiate instances. + private let id: String + /// The underlying storage container to read from and write to. + private let storage: Storage + /// The encoder used for encoding heartbeat data. + private let encoder: JSONEncoder = .init() + /// The decoder used for decoding heartbeat data. + private let decoder: JSONDecoder = .init() + /// The queue for synchronizing storage operations. + private let queue: DispatchQueue + + /// Designated initializer. + /// - Parameters: + /// - id: A string identifier. + /// - storage: The underlying storage container where heartbeat data is stored. + init(id: String, + storage: Storage) { + self.id = id + self.storage = storage + queue = DispatchQueue(label: "com.heartbeat.storage.\(id)") + } + + // MARK: - Instance Management + + /// Statically allocated cache of `HeartbeatStorage` instances keyed by string IDs. + private static var cachedInstances: [String: WeakContainer] = [:] + + /// Gets an existing `HeartbeatStorage` instance with the given `id` if one exists. Otherwise, + /// makes a new instance with the given `id`. + /// + /// - Parameter id: A string identifier. + /// - Returns: A `HeartbeatStorage` instance. + static func getInstance(id: String) -> HeartbeatStorage { + if let cachedInstance = cachedInstances[id]?.object { + return cachedInstance + } else { + let newInstance = HeartbeatStorage.makeHeartbeatStorage(id: id) + cachedInstances[id] = WeakContainer(object: newInstance) + return newInstance + } + } + + /// Makes a `HeartbeatStorage` instance using a given `String` identifier. + /// + /// The created persistent storage object is platform dependent. For tvOS, user defaults + /// is used as the underlying storage container due to system storage limits. For all other + /// platforms, + /// the file system is used. + /// + /// - Parameter id: A `String` identifier used to create the `HeartbeatStorage`. + /// - Returns: A `HeartbeatStorage` instance. + private static func makeHeartbeatStorage(id: String) -> HeartbeatStorage { + #if os(tvOS) + let storage = UserDefaultsStorage.makeStorage(id: id) + #else + let storage = FileStorage.makeStorage(id: id) + #endif // os(tvOS) + return HeartbeatStorage(id: id, storage: storage) + } + + deinit { + // Removes the instance if it was cached. + Self.cachedInstances.removeValue(forKey: id) + } + + // MARK: - HeartbeatStorageProtocol + + /// Synchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteSync(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) { + queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Asynchronously reads from and writes to storage using the given transform block. + /// - Parameter transform: A block to transform the currently stored heartbeats bundle to a new + /// heartbeats bundle value. + func readAndWriteAsync(using transform: @escaping (HeartbeatsBundle?) -> HeartbeatsBundle?) { + queue.async { [self] in + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try? save(newHeartbeatsBundle, to: storage) + } + } + + /// Synchronously gets the current heartbeat data from storage and resets the storage using the + /// given transform block. + /// + /// This API is like any `getAndSet`-style API in that it gets (and returns) the current value and + /// uses + /// a block to transform the current value (or, soon-to-be old value) to a new value. + /// + /// - Parameter transform: An optional block used to reset the currently stored heartbeat. + /// - Returns: The heartbeat data that was stored (before the `transform` was applied). + @discardableResult + func getAndSet(using transform: (HeartbeatsBundle?) -> HeartbeatsBundle?) throws + -> HeartbeatsBundle? { + let heartbeatsBundle: HeartbeatsBundle? = try queue.sync { + let oldHeartbeatsBundle = try? load(from: storage) + let newHeartbeatsBundle = transform(oldHeartbeatsBundle) + try save(newHeartbeatsBundle, to: storage) + return oldHeartbeatsBundle + } + return heartbeatsBundle + } + + /// Loads and decodes the stored heartbeats bundle from a given storage object. + /// - Parameter storage: The storage container to read from. + /// - Returns: The decoded `HeartbeatsBundle` loaded from storage; `nil` if storage is empty. + /// - Throws: An error if storage could not be read or the data could not be decoded. + private func load(from storage: Storage) throws -> HeartbeatsBundle? { + let data = try storage.read() + if data.isEmpty { + return nil + } else { + let heartbeatData = try data.decoded(using: decoder) as HeartbeatsBundle + return heartbeatData + } + } + + /// Saves the encoding of the given value to the given storage container. + /// - Parameters: + /// - heartbeatsBundle: The heartbeats bundle to encode and save. + /// - storage: The storage container to write to. + private func save(_ heartbeatsBundle: HeartbeatsBundle?, to storage: Storage) throws { + if let heartbeatsBundle { + let data = try heartbeatsBundle.encoded(using: encoder) + try storage.write(data) + } else { + try storage.write(nil) + } + } +} + +private extension Data { + /// Returns the decoded value of this `Data` using the given decoder. Defaults to `JSONDecoder`. + /// - Returns: The decoded value. + func decoded(using decoder: JSONDecoder = .init()) throws -> T where T: Decodable { + try decoder.decode(T.self, from: self) + } +} + +private extension Encodable { + /// Returns the `Data` encoding of this value using the given encoder. + /// - Parameter encoder: An encoder used to encode the value. Defaults to `JSONEncoder`. + /// - Returns: The data encoding of the value. + func encoded(using encoder: JSONEncoder = .init()) throws -> Data { + try encoder.encode(self) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift new file mode 100644 index 0000000..a6e258e --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsBundle.swift @@ -0,0 +1,151 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that can be converted to a `HeartbeatsPayload`. +protocol HeartbeatsPayloadConvertible { + func makeHeartbeatsPayload() -> HeartbeatsPayload +} + +/// A codable collection of heartbeats that has a fixed capacity and optimizations for storing +/// heartbeats of +/// multiple time periods. +struct HeartbeatsBundle: Codable, HeartbeatsPayloadConvertible { + /// The maximum number of heartbeats that can be stored in the buffer. + let capacity: Int + /// A cache used for keeping track of the last heartbeat date recorded for a given time period. + /// + /// The cache contains the last added date for each time period. The reason only the date is + /// cached is + /// because it's the only piece of information that should be used by clients to determine whether + /// or not + /// to append a new heartbeat. + private(set) var lastAddedHeartbeatDates: [TimePeriod: Date] + /// A ring buffer of heartbeats. + private var buffer: RingBuffer + + /// A default cache provider that provides a dictionary of all time periods mapping to a default + /// date. + static var cacheProvider: () -> [TimePeriod: Date] { + let timePeriodsAndDates = TimePeriod.allCases.map { ($0, Date.distantPast) } + return { Dictionary(uniqueKeysWithValues: timePeriodsAndDates) } + } + + /// Designated initializer. + /// - Parameters: + /// - capacity: The heartbeat capacity of the initialized collection. + /// - cache: A cache of time periods mapping to dates. Defaults to using static `cacheProvider`. + init(capacity: Int, + cache: [TimePeriod: Date] = cacheProvider()) { + buffer = RingBuffer(capacity: capacity) + self.capacity = capacity + lastAddedHeartbeatDates = cache + } + + /// Appends a heartbeat to this collection. + /// - Parameter heartbeat: The heartbeat to append. + mutating func append(_ heartbeat: Heartbeat) { + guard capacity > 0 else { + return // Do not append if capacity is non-positive. + } + + do { + // Push the heartbeat to the back of the buffer. + if let overwrittenHeartbeat = try buffer.push(heartbeat) { + // If a heartbeat was overwritten, update the cache to ensure it's date + // is removed. + lastAddedHeartbeatDates = lastAddedHeartbeatDates.mapValues { date in + overwrittenHeartbeat.date == date ? .distantPast : date + } + } + + // Update cache with the new heartbeat's date. + for timePeriod in heartbeat.timePeriods { + lastAddedHeartbeatDates[timePeriod] = heartbeat.date + } + + } catch let error as RingBuffer.Error { + // A ring buffer error occurred while pushing to the buffer so the bundle + // is reset. + self = HeartbeatsBundle(capacity: capacity) + + // Create a diagnostic heartbeat to capture the failure and add it to the + // buffer. The failure is added as a key/value pair to the agent string. + // Given that the ring buffer has been reset, it is not expected for the + // second push attempt to fail. + let errorDescription = error.errorDescription.replacingOccurrences(of: " ", with: "-") + let diagnosticHeartbeat = Heartbeat( + agent: "\(heartbeat.agent) error/\(errorDescription)", + date: heartbeat.date, + timePeriods: heartbeat.timePeriods + ) + + let secondPushAttempt = Result { + try buffer.push(diagnosticHeartbeat) + } + + if case .success = secondPushAttempt { + // Update cache with the new heartbeat's date. + for timePeriod in diagnosticHeartbeat.timePeriods { + lastAddedHeartbeatDates[timePeriod] = diagnosticHeartbeat.date + } + } + } catch { + // Ignore other error. + } + } + + /// Removes the heartbeat associated with the given date. + /// - Parameter date: The date of the heartbeat needing removal. + /// - Returns: The heartbeat that was removed or `nil` if there was no heartbeat to remove. + @discardableResult + mutating func removeHeartbeat(from date: Date) -> Heartbeat? { + var removedHeartbeat: Heartbeat? + + var poppedHeartbeats: [Heartbeat] = [] + + while let poppedHeartbeat = buffer.pop() { + if poppedHeartbeat.date == date { + removedHeartbeat = poppedHeartbeat + break + } + poppedHeartbeats.append(poppedHeartbeat) + } + + for poppedHeartbeat in poppedHeartbeats.reversed() { + do { + try buffer.push(poppedHeartbeat) + } catch { + // Ignore error. + } + } + + return removedHeartbeat + } + + /// Makes and returns a `HeartbeatsPayload` from this heartbeats bundle. + /// - Returns: A heartbeats payload. + func makeHeartbeatsPayload() -> HeartbeatsPayload { + let agentAndDates = buffer.map { heartbeat in + (heartbeat.agent, [heartbeat.date]) + } + + let userAgentPayloads = [String: [Date]](agentAndDates, uniquingKeysWith: +) + .map(HeartbeatsPayload.UserAgentPayload.init) + .sorted { $0.agent < $1.agent } // Sort payloads by user agent. + + return HeartbeatsPayload(userAgentPayloads: userAgentPayloads) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift new file mode 100644 index 0000000..525b480 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/HeartbeatsPayload.swift @@ -0,0 +1,181 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_NSData +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// A type that provides a string representation for use in an HTTP header. +public protocol HTTPHeaderRepresentable { + func headerValue() -> String +} + +/// A value type representing a payload of heartbeat data intended for sending in network requests. +/// +/// This type's structure is optimized for type-safe encoding into a HTTP payload format. +/// The current encoding format for the payload's current version is: +/// +/// { +/// "version": 2, +/// "heartbeats": [ +/// { +/// "agent": "dummy_agent_1", +/// "dates": ["2021-11-01", "2021-11-02"] +/// }, +/// { +/// "agent": "dummy_agent_2", +/// "dates": ["2021-11-03"] +/// } +/// ] +/// } +/// +public struct HeartbeatsPayload: Codable, Sendable { + /// The version of the payload. See go/firebase-apple-heartbeats for details regarding current + /// version. + static let version: Int = 2 + + /// A payload component composed of a user agent and array of dates (heartbeats). + struct UserAgentPayload: Codable { + /// An anonymous agent string. + let agent: String + /// An array of dates where each date represents a "heartbeat". + let dates: [Date] + } + + /// An array of user agent payloads. + let userAgentPayloads: [UserAgentPayload] + /// The version of the payload structure. + let version: Int + + /// Alternative keys for properties so encoding follows platform-wide payload structure. + enum CodingKeys: String, CodingKey { + case userAgentPayloads = "heartbeats" + case version + } + + /// Designated initializer. + /// - Parameters: + /// - userAgentPayloads: An array of payloads containing heartbeat data corresponding to a + /// given user agent. + /// - version: A version of the payload. Defaults to the static default. + init(userAgentPayloads: [UserAgentPayload] = [], version: Int = version) { + self.userAgentPayloads = userAgentPayloads + self.version = version + } + + /// A Boolean value indicating whether the payload is empty. + public var isEmpty: Bool { + userAgentPayloads.isEmpty + } +} + +// MARK: - HTTPHeaderRepresentable + +extension HeartbeatsPayload: HTTPHeaderRepresentable { + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + public func headerValue() -> String { + let encoder = JSONEncoder() + encoder.dateEncodingStrategy = .formatted(Self.dateFormatter) + #if DEBUG + // Sort keys in debug builds to simplify output comparisons in unit tests. + encoder.outputFormatting = .sortedKeys + #endif // DEBUG + + guard let data = try? encoder.encode(self) else { + // If encoding fails, fall back to encoding with an empty payload. + return Self.emptyPayload.headerValue() + } + + do { + let gzippedData = try data.zipped() + return gzippedData.base64URLEncodedString() + } catch { + // If gzipping fails, fall back to encoding with base64URL. + return data.base64URLEncodedString() + } + } +} + +// MARK: - Static Defaults + +extension HeartbeatsPayload { + /// Convenience instance that represents an empty payload. + static let emptyPayload = HeartbeatsPayload() + + /// A default date formatter that uses `yyyy-MM-dd` format. + public static let dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.dateFormat = "yyyy-MM-dd" + formatter.locale = Locale(identifier: "en_US_POSIX") + formatter.timeZone = TimeZone(secondsFromGMT: 0) + return formatter + }() +} + +// MARK: - Equatable + +extension HeartbeatsPayload: Equatable {} +extension HeartbeatsPayload.UserAgentPayload: Equatable {} + +// MARK: - Data + +public extension Data { + /// Returns a Base-64 URL-safe encoded string. + /// + /// - parameter options: The options to use for the encoding. Default value is `[]`. + /// - returns: The Base-64 URL-safe encoded string. + func base64URLEncodedString(options: Data.Base64EncodingOptions = []) -> String { + base64EncodedString() + .replacingOccurrences(of: "/", with: "_") + .replacingOccurrences(of: "+", with: "-") + .replacingOccurrences(of: "=", with: "") + } + + /// Initialize a `Data` from a Base-64 URL encoded String using the given options. + /// + /// Returns nil when the input is not recognized as valid Base-64. + /// - parameter base64URLString: The string to parse. + /// - parameter options: Encoding options. Default value is `[]`. + init?(base64URLEncoded base64URLString: String, options: Data.Base64DecodingOptions = []) { + var base64Encoded = base64URLString + .replacingOccurrences(of: "_", with: "/") + .replacingOccurrences(of: "-", with: "+") + + // Pad the string with "=" signs until the string's length is a multiple of 4. + while !base64Encoded.count.isMultiple(of: 4) { + base64Encoded.append("=") + } + + self.init(base64Encoded: base64Encoded, options: options) + } + + /// Returns the compressed data. + /// - Returns: The compressed data. + /// - Throws: An error if compression failed. + func zipped() throws -> Data { + try NSData.gul_data(byGzippingData: self) + } + + /// Returns the uncompressed data. + /// - Returns: The decompressed data. + /// - Throws: An error if decompression failed. + func unzipped() throws -> Data { + try NSData.gul_data(byInflatingGzippedData: self) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift new file mode 100644 index 0000000..7269c4d --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/RingBuffer.swift @@ -0,0 +1,111 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A generic circular queue structure. +struct RingBuffer: Sequence { + /// An array of heartbeats treated as a circular queue and initialized with a fixed capacity. + private var circularQueue: [Element?] + /// The current "tail" and insert point for the `circularQueue`. + private var tailIndex: Array.Index + + /// Error types for `RingBuffer` operations. + enum Error: LocalizedError { + case outOfBoundsPush(pushIndex: Array.Index, endIndex: Array.Index) + + var errorDescription: String { + switch self { + case let .outOfBoundsPush(pushIndex, endIndex): + return "Out-of-bounds push at index \(pushIndex) to ring buffer with" + + "end index of \(endIndex)." + } + } + } + + /// Designated initializer. + /// - Parameter capacity: An `Int` representing the capacity. + init(capacity: Int) { + circularQueue = Array(repeating: nil, count: capacity) + tailIndex = circularQueue.startIndex + } + + /// Pushes an element to the back of the buffer, returning the element (`Element?`) that was + /// overwritten. + /// - Parameter element: The element to push to the back of the buffer. + /// - Returns: The element that was overwritten or `nil` if nothing was overwritten. + /// - Complexity: O(1) + @discardableResult + mutating func push(_ element: Element) throws -> Element? { + guard circularQueue.count > 0 else { + // Do not push if `circularQueue` is a fixed empty array. + return nil + } + + guard circularQueue.indices.contains(tailIndex) else { + // We have somehow entered an invalid state (#10025). + throw Self.Error.outOfBoundsPush( + pushIndex: tailIndex, + endIndex: circularQueue.endIndex + ) + } + + let replaced = circularQueue[tailIndex] + circularQueue[tailIndex] = element + + // Increment index, wrapping around to the start if needed. + tailIndex += 1 + if tailIndex >= circularQueue.endIndex { + tailIndex = circularQueue.startIndex + } + + return replaced + } + + /// Pops an element from the back of the buffer, returning the element (`Element?`) that was + /// popped. + /// - Returns: The element that was popped or `nil` if there was no element to pop. + /// - Complexity: O(1) + @discardableResult + mutating func pop() -> Element? { + guard circularQueue.count > 0 else { + // Do not pop if `circularQueue` is a fixed empty array. + return nil + } + + // Decrement index, wrapping around to the back if needed. + tailIndex -= 1 + if tailIndex < circularQueue.startIndex { + tailIndex = circularQueue.endIndex - 1 + } + + guard let popped = circularQueue[tailIndex] else { + return nil // There is no element to pop. + } + + circularQueue[tailIndex] = nil + + return popped + } + + func makeIterator() -> IndexingIterator<[Element]> { + circularQueue + .compactMap { $0 } // Remove `nil` elements. + .makeIterator() + } +} + +// MARK: - Codable + +extension RingBuffer: Codable where Element: Codable {} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift new file mode 100644 index 0000000..a4cac33 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/Storage.swift @@ -0,0 +1,145 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A type that reads from and writes to an underlying storage container. +protocol Storage { + /// Reads and returns the data stored by this storage type. + /// - Returns: The data read from storage. + /// - Throws: An error if the read failed. + func read() throws -> Data + + /// Writes the given data to this storage type. + /// - Throws: An error if the write failed. + func write(_ data: Data?) throws +} + +/// Error types for `Storage` operations. +enum StorageError: Error { + case readError + case writeError +} + +// MARK: - FileStorage + +/// A object that provides API for reading and writing to a file system resource. +final class FileStorage: Storage { + /// A file system URL to the underlying file resource. + private let url: URL + /// The file manager used to perform file system operations. + private let fileManager: FileManager + + /// Designated initializer. + /// - Parameters: + /// - url: A file system URL for the underlying file resource. + /// - fileManager: A file manager. Defaults to `default` manager. + init(url: URL, fileManager: FileManager = .default) { + self.url = url + self.fileManager = fileManager + } + + /// Reads and returns the data from this object's associated file resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if reading the contents of the file resource fails (i.e. file doesn't + /// exist). + func read() throws -> Data { + do { + return try Data(contentsOf: url) + } catch { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated file resource. + /// + /// When the given `data` is `nil`, this object's associated file resource is emptied. + /// + /// - Parameter data: The `Data?` to write to this object's associated file resource. + func write(_ data: Data?) throws { + do { + try createDirectories(in: url.deletingLastPathComponent()) + if let data { + try data.write(to: url, options: .atomic) + } else { + let emptyData = Data() + try emptyData.write(to: url, options: .atomic) + } + } catch { + throw StorageError.writeError + } + } + + /// Creates all directories in the given file system URL. + /// + /// If the directory for the given URL already exists, the error is ignored because the directory + /// has already been created. + /// + /// - Parameter url: The URL to create directories in. + private func createDirectories(in url: URL) throws { + do { + try fileManager.createDirectory( + at: url, + withIntermediateDirectories: true + ) + } catch CocoaError.fileWriteFileExists { + // Directory already exists. + } catch { throw error } + } +} + +// MARK: - UserDefaultsStorage + +/// A object that provides API for reading and writing to a user defaults resource. +final class UserDefaultsStorage: Storage { + /// The underlying defaults container. + private let defaults: UserDefaults + /// The key mapping to the object's associated resource in `defaults`. + private let key: String + + /// Designated initializer. + /// - Parameters: + /// - defaults: The defaults container. + /// - key: The key mapping to the value stored in the defaults container. + init(defaults: UserDefaults, key: String) { + self.defaults = defaults + self.key = key + } + + /// Reads and returns the data from this object's associated defaults resource. + /// + /// - Returns: The data stored on disk. + /// - Throws: An error if no data has been stored to the defaults container. + func read() throws -> Data { + if let data = defaults.data(forKey: key) { + return data + } else { + throw StorageError.readError + } + } + + /// Writes the given data to this object's associated defaults. + /// + /// When the given `data` is `nil`, the associated default is removed. + /// + /// - Parameter data: The `Data?` to write to this object's associated defaults. + func write(_ data: Data?) throws { + if let data { + defaults.set(data, forKey: key) + } else { + defaults.removeObject(forKey: key) + } + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift new file mode 100644 index 0000000..6552a31 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/StorageFactory.swift @@ -0,0 +1,66 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +private enum Constants { + /// The name of the file system directory where heartbeat data is stored. + static let heartbeatFileStorageDirectoryPath = "google-heartbeat-storage" + /// The name of the user defaults suite where heartbeat data is stored. + static let heartbeatUserDefaultsSuiteName = "com.google.heartbeat.storage" +} + +/// A factory type for `Storage`. +protocol StorageFactory { + static func makeStorage(id: String) -> Storage +} + +// MARK: - FileStorage + StorageFactory + +extension FileStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let rootDirectory = FileManager.default.applicationSupportDirectory + let heartbeatDirectoryPath = Constants.heartbeatFileStorageDirectoryPath + + // Sanitize the `id` so the heartbeat file name does not include a ":". + let sanitizedID = id.replacingOccurrences(of: ":", with: "_") + let heartbeatFilePath = "heartbeats-\(sanitizedID)" + + let storageURL = rootDirectory + .appendingPathComponent(heartbeatDirectoryPath, isDirectory: true) + .appendingPathComponent(heartbeatFilePath, isDirectory: false) + + return FileStorage(url: storageURL) + } +} + +extension FileManager { + var applicationSupportDirectory: URL { + urls(for: .applicationSupportDirectory, in: .userDomainMask).first! + } +} + +// MARK: - UserDefaultsStorage + StorageFactory + +extension UserDefaultsStorage: StorageFactory { + static func makeStorage(id: String) -> Storage { + let suiteName = Constants.heartbeatUserDefaultsSuiteName + // It's safe to force unwrap the below defaults instance because the + // initializer only returns `nil` when the bundle id or `globalDomain` + // is passed in as the `suiteName`. + let defaults = UserDefaults(suiteName: suiteName)! + let key = "heartbeats-\(id)" + return UserDefaultsStorage(defaults: defaults, key: key) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift new file mode 100644 index 0000000..f1dd177 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/WeakContainer.swift @@ -0,0 +1,20 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A structure used to weakly box reference types. +struct WeakContainer { + weak var object: Object? +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift new file mode 100644 index 0000000..50cd247 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatController.swift @@ -0,0 +1,58 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// An object that provides API to log and flush heartbeats from a synchronized storage container. +@objc(FIRHeartbeatController) +@objcMembers +public class _ObjC_HeartbeatController: NSObject { + /// The underlying Swift object. + private let heartbeatController: HeartbeatController + + /// Public initializer. + /// - Parameter id: The `id` to associate this controller's heartbeat storage with. + public init(id: String) { + heartbeatController = HeartbeatController(id: id) + } + + /// Asynchronously logs a new heartbeat, if needed. + /// + /// - Note: This API is thread-safe. + /// - Parameter agent: The string agent (i.e. Firebase User Agent) to associate the logged + /// heartbeat with. + public func log(_ agent: String) { + heartbeatController.log(agent) + } + + /// Synchronously flushes heartbeats from storage into a heartbeats payload. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat(s). + public func flush() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flush() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } + + /// Synchronously flushes the heartbeat for today. + /// + /// If no heartbeat was logged today, the returned payload is empty. + /// + /// - Note: This API is thread-safe. + /// - Returns: A heartbeats payload for the flushed heartbeat. + public func flushHeartbeatFromToday() -> _ObjC_HeartbeatsPayload { + let heartbeatsPayload = heartbeatController.flushHeartbeatFromToday() + return _ObjC_HeartbeatsPayload(heartbeatsPayload) + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift new file mode 100644 index 0000000..83d72a2 --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/HeartbeatLogging/_ObjC_HeartbeatsPayload.swift @@ -0,0 +1,40 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// A model object representing a payload of heartbeat data intended for sending in network +/// requests. +@objc(FIRHeartbeatsPayload) +public class _ObjC_HeartbeatsPayload: NSObject, HTTPHeaderRepresentable { + /// The underlying Swift structure. + private let heartbeatsPayload: HeartbeatsPayload + + /// Designated initializer. + /// - Parameter heartbeatsPayload: A native-Swift heartbeats payload. + public init(_ heartbeatsPayload: HeartbeatsPayload) { + self.heartbeatsPayload = heartbeatsPayload + } + + /// Returns a processed payload string intended for use in a HTTP header. + /// - Returns: A string value from the heartbeats payload. + @objc public func headerValue() -> String { + heartbeatsPayload.headerValue() + } + + /// A Boolean value indicating whether the payload is empty. + @objc public var isEmpty: Bool { + heartbeatsPayload.isEmpty + } +} diff --git a/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..3fb515f --- /dev/null +++ b/Pods/FirebaseCoreInternal/FirebaseCore/Internal/Sources/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,26 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + + diff --git a/Pods/FirebaseCoreInternal/LICENSE b/Pods/FirebaseCoreInternal/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseCoreInternal/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseCoreInternal/README.md b/Pods/FirebaseCoreInternal/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseCoreInternal/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.h new file mode 100644 index 0000000..8e7510e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.h @@ -0,0 +1,95 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#if CLS_TARGET_OS_HAS_UIKIT +#import +#endif + +__BEGIN_DECLS + +#define FIRCLSApplicationActivityDefault \ + (NSActivitySuddenTerminationDisabled | NSActivityAutomaticTerminationDisabled) + +/** + * Type to indicate application installation source + */ +typedef NS_ENUM(NSInteger, FIRCLSApplicationInstallationSourceType) { + FIRCLSApplicationInstallationSourceTypeDeveloperInstall = 1, + // 2 and 3 are reserved for legacy values. + FIRCLSApplicationInstallationSourceTypeAppStore = 4 +}; + +/** + * Returns the application bundle identifier with occurrences of "/" replaced by "_" + */ +NSString* FIRCLSApplicationGetBundleIdentifier(void); + +/** + * Returns the SDK's bundle ID + */ +NSString* FIRCLSApplicationGetSDKBundleID(void); + +/** + * Returns the platform identifier, either: ios, mac, or tvos. + * Catalyst apps are treated as mac. + * This is a legacy function, for platform identificaiton please use + * FIRCLSApplicationGetFirebasePlatform. + */ +NSString* FIRCLSApplicationGetPlatform(void); + +/** + * Returns the operating system for filtering. Should be kept consistent with Analytics. + */ +NSString* FIRCLSApplicationGetFirebasePlatform(void); + +/** + * Returns the user-facing app name + */ +NSString* FIRCLSApplicationGetName(void); + +/** + * Returns the build number + */ +NSString* FIRCLSApplicationGetBundleVersion(void); + +/** + * Returns the human-readable build version + */ +NSString* FIRCLSApplicationGetShortBundleVersion(void); + +/** + * Returns a number to indicate how the app has been installed: Developer / App Store + */ +FIRCLSApplicationInstallationSourceType FIRCLSApplicationInstallationSource(void); + +BOOL FIRCLSApplicationIsExtension(void); +NSString* FIRCLSApplicationExtensionPointIdentifier(void); + +#if CLS_TARGET_OS_HAS_UIKIT +UIApplication* FIRCLSApplicationSharedInstance(void); +#else +id FIRCLSApplicationSharedInstance(void); +#endif + +void FIRCLSApplicationOpenURL(NSURL* url, + NSExtensionContext* extensionContext, + void (^completionBlock)(BOOL success)); + +id FIRCLSApplicationBeginActivity(NSActivityOptions options, NSString* reason); +void FIRCLSApplicationEndActivity(id activity); + +void FIRCLSApplicationActivity(NSActivityOptions options, NSString* reason, void (^block)(void)); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.m new file mode 100644 index 0000000..e1a0db6 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSApplication.m @@ -0,0 +1,234 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import + +#if CLS_TARGET_OS_OSX +#import +#endif + +#if CLS_TARGET_OS_HAS_UIKIT +#import +#endif + +NSString* FIRCLSApplicationGetBundleIdentifier(void) { + return [[[NSBundle mainBundle] bundleIdentifier] stringByReplacingOccurrencesOfString:@"/" + withString:@"_"]; +} + +NSString* FIRCLSApplicationGetSDKBundleID(void) { + return + [@"com.google.firebase.crashlytics." stringByAppendingString:FIRCLSApplicationGetPlatform()]; +} + +// Legacy function, we use FIRCLSApplicationGetFirebasePlatform now for platform specification. +// Can't clean the code since some endpoints setup depend on this function. +NSString* FIRCLSApplicationGetPlatform(void) { +#if defined(TARGET_OS_MACCATALYST) && TARGET_OS_MACCATALYST + return @"mac"; +#elif TARGET_OS_IOS + return @"ios"; +#elif TARGET_OS_OSX + return @"mac"; +#elif TARGET_OS_TV + return @"tvos"; +#elif TARGET_OS_WATCH + return @"ios"; +#elif defined(TARGET_OS_VISION) && TARGET_OS_VISION + return @"ios"; +#endif +} + +NSString* FIRCLSApplicationGetFirebasePlatform(void) { + NSString* firebasePlatform = [GULAppEnvironmentUtil applePlatform]; +#if TARGET_OS_IOS + // This check is necessary because iOS-only apps running on iPad + // will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM(). + if ([firebasePlatform isEqualToString:@"ios"] && + ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"] || + [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) { + return @"ipados"; + } +#endif + + return firebasePlatform; +} + +// these defaults match the FIRCLSInfoPlist helper in FIRCLSIDEFoundation +NSString* FIRCLSApplicationGetBundleVersion(void) { + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; +} + +NSString* FIRCLSApplicationGetShortBundleVersion(void) { + return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; +} + +NSString* FIRCLSApplicationGetName(void) { + NSString* name; + NSBundle* mainBundle; + + mainBundle = [NSBundle mainBundle]; + + name = [mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"]; + if (name) { + return name; + } + + name = [mainBundle objectForInfoDictionaryKey:@"CFBundleName"]; + if (name) { + return name; + } + + return FIRCLSApplicationGetBundleVersion(); +} + +BOOL FIRCLSApplicationHasAppStoreReceipt(void) { + NSURL* url = NSBundle.mainBundle.appStoreReceiptURL; + return [NSFileManager.defaultManager fileExistsAtPath:[url path]]; +} + +FIRCLSApplicationInstallationSourceType FIRCLSApplicationInstallationSource(void) { + if (FIRCLSApplicationHasAppStoreReceipt()) { + return FIRCLSApplicationInstallationSourceTypeAppStore; + } + + return FIRCLSApplicationInstallationSourceTypeDeveloperInstall; +} + +BOOL FIRCLSApplicationIsExtension(void) { + return FIRCLSApplicationExtensionPointIdentifier() != nil; +} + +NSString* FIRCLSApplicationExtensionPointIdentifier(void) { + id extensionDict = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"NSExtension"]; + + if (!extensionDict) { + return nil; + } + + if (![extensionDict isKindOfClass:[NSDictionary class]]) { + FIRCLSSDKLog("Error: NSExtension Info.plist entry is mal-formed\n"); + return nil; + } + + id typeValue = [(NSDictionary*)extensionDict objectForKey:@"NSExtensionPointIdentifier"]; + + if (![typeValue isKindOfClass:[NSString class]]) { + FIRCLSSDKLog("Error: NSExtensionPointIdentifier Info.plist entry is mal-formed\n"); + return nil; + } + + return typeValue; +} + +#if CLS_TARGET_OS_HAS_UIKIT +UIApplication* FIRCLSApplicationSharedInstance(void) { + if (FIRCLSApplicationIsExtension()) { + return nil; + } + + return [[UIApplication class] performSelector:@selector(sharedApplication)]; +} +#elif CLS_TARGET_OS_OSX +id FIRCLSApplicationSharedInstance(void) { + return [NSClassFromString(@"NSApplication") sharedApplication]; +} +#else +id FIRCLSApplicationSharedInstance(void) { + return nil; // FIXME: what do we actually return for watch? +} +#endif + +void FIRCLSApplicationOpenURL(NSURL* url, + NSExtensionContext* extensionContext, + void (^completionBlock)(BOOL success)) { + if (extensionContext) { + [extensionContext openURL:url completionHandler:completionBlock]; + return; + } + + BOOL result = NO; + +#if TARGET_OS_IOS + // What's going on here is the value returned is a scalar, but we really need an object to + // call this dynamically. Hoops must be jumped. + NSInvocationOperation* op = + [[NSInvocationOperation alloc] initWithTarget:FIRCLSApplicationSharedInstance() + selector:@selector(openURL:) + object:url]; + [op start]; + [op.result getValue:&result]; +#elif CLS_TARGET_OS_OSX + result = [[NSClassFromString(@"NSWorkspace") sharedWorkspace] openURL:url]; +#endif + + completionBlock(result); +} + +id FIRCLSApplicationBeginActivity(NSActivityOptions options, NSString* reason) { + if ([[NSProcessInfo processInfo] respondsToSelector:@selector(beginActivityWithOptions: + reason:)]) { + return [[NSProcessInfo processInfo] beginActivityWithOptions:options reason:reason]; + } + +#if CLS_TARGET_OS_OSX + if (options & NSActivitySuddenTerminationDisabled) { + [[NSProcessInfo processInfo] disableSuddenTermination]; + } + + if (options & NSActivityAutomaticTerminationDisabled) { + [[NSProcessInfo processInfo] disableAutomaticTermination:reason]; + } +#endif + + // encode the options, so we can undo our work later + return @{@"options" : @(options), @"reason" : reason}; +} + +void FIRCLSApplicationEndActivity(id activity) { + if (!activity) { + return; + } + + if ([[NSProcessInfo processInfo] respondsToSelector:@selector(endActivity:)]) { + [[NSProcessInfo processInfo] endActivity:activity]; + return; + } + +#if CLS_TARGET_OS_OSX + NSInteger options = [[(NSDictionary*)activity objectForKey:@"options"] integerValue]; + + if (options & NSActivitySuddenTerminationDisabled) { + [[NSProcessInfo processInfo] enableSuddenTermination]; + } + + if (options & NSActivityAutomaticTerminationDisabled) { + [[NSProcessInfo processInfo] + enableAutomaticTermination:[(NSDictionary*)activity objectForKey:@"reason"]]; + } +#endif +} + +void FIRCLSApplicationActivity(NSActivityOptions options, NSString* reason, void (^block)(void)) { + id activity = FIRCLSApplicationBeginActivity(options, reason); + + block(); + + FIRCLSApplicationEndActivity(activity); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h new file mode 100644 index 0000000..880d1cc --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h @@ -0,0 +1,80 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" + +__BEGIN_DECLS + +// Typically, apps seem to have ~700 binary images loaded +#define CLS_BINARY_IMAGE_RUNTIME_NODE_COUNT (1024) +#define CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE (32) +#define CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME 0 + +#define FIRCLSUUIDStringLength (33) + +typedef struct { + _Atomic(void*) volatile baseAddress; + uint64_t size; +#if CLS_DWARF_UNWINDING_SUPPORTED + const void* ehFrame; +#endif +#if CLS_COMPACT_UNWINDING_SUPPORTED + const void* unwindInfo; +#endif + const void* crashInfo; +#if CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME + char name[CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE]; +#endif +} FIRCLSBinaryImageRuntimeNode; + +typedef struct { + char uuidString[FIRCLSUUIDStringLength]; + bool encrypted; + FIRCLSMachOVersion builtSDK; + FIRCLSMachOVersion minSDK; + FIRCLSBinaryImageRuntimeNode node; + struct FIRCLSMachOSlice slice; + intptr_t vmaddr_slide; +} FIRCLSBinaryImageDetails; + +typedef struct { + const char* path; +} FIRCLSBinaryImageReadOnlyContext; + +typedef struct { + FIRCLSFile file; + FIRCLSBinaryImageRuntimeNode nodes[CLS_BINARY_IMAGE_RUNTIME_NODE_COUNT]; +} FIRCLSBinaryImageReadWriteContext; + +void FIRCLSBinaryImageInit(void); + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSBinaryImageSafeFindImageForAddress(uintptr_t address, + FIRCLSBinaryImageRuntimeNode* image); +bool FIRCLSBinaryImageSafeHasUnwindInfo(FIRCLSBinaryImageRuntimeNode* image); +#endif + +bool FIRCLSBinaryImageFindImageForUUID(const char* uuidString, + FIRCLSBinaryImageDetails* imageDetails); + +bool FIRCLSBinaryImageRecordMainExecutable(FIRCLSFile* file); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m new file mode 100644 index 0000000..35cb32b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m @@ -0,0 +1,607 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h" + +#include +#include + +#include + +#include + +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#include "Crashlytics/Shared/FIRCLSByteUtility.h" +#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" + +#include + +// this is defined only if __OPEN_SOURCE__ is *not* defined in the TVOS SDK's mach-o/loader.h +// also, it has not yet made it back to the OSX SDKs, for example +#ifndef LC_VERSION_MIN_TVOS +#define LC_VERSION_MIN_TVOS 0x2F +#endif + +#pragma mark Prototypes +static bool FIRCLSBinaryImageOpenIfNeeded(bool* needsClosing); + +static void FIRCLSBinaryImageAddedCallback(const struct mach_header* mh, intptr_t vmaddr_slide); +static void FIRCLSBinaryImageRemovedCallback(const struct mach_header* mh, intptr_t vmaddr_slide); +static void FIRCLSBinaryImageChanged(bool added, + const struct mach_header* mh, + intptr_t vmaddr_slide); +static bool FIRCLSBinaryImageFillInImageDetails(FIRCLSBinaryImageDetails* details); + +static void FIRCLSBinaryImageStoreNode(bool added, FIRCLSBinaryImageDetails imageDetails); +static void FIRCLSBinaryImageRecordSlice(bool added, const FIRCLSBinaryImageDetails imageDetails); + +#pragma mark - Core API +void FIRCLSBinaryImageInit(void) { + // initialize our node array to all zeros + memset(&_firclsContext.writable->binaryImage, 0, sizeof(_firclsContext.writable->binaryImage)); + _firclsContext.writable->binaryImage.file.fd = -1; + + dispatch_async(FIRCLSGetBinaryImageQueue(), ^{ + if (!FIRCLSUnlinkIfExists(_firclsContext.readonly->binaryimage.path)) { + FIRCLSSDKLog("Unable to reset the binary image log file %s\n", strerror(errno)); + } + + bool needsClosing; // unneeded + if (!FIRCLSBinaryImageOpenIfNeeded(&needsClosing)) { + FIRCLSSDKLog("Error: Unable to open the binary image log file during init\n"); + } + }); + + _dyld_register_func_for_add_image(FIRCLSBinaryImageAddedCallback); + _dyld_register_func_for_remove_image(FIRCLSBinaryImageRemovedCallback); + + dispatch_async(FIRCLSGetBinaryImageQueue(), ^{ + FIRCLSFileClose(&_firclsContext.writable->binaryImage.file); + }); +} + +static bool FIRCLSBinaryImageOpenIfNeeded(bool* needsClosing) { + if (!FIRCLSIsValidPointer(_firclsContext.writable)) { + return false; + } + + if (!FIRCLSIsValidPointer(_firclsContext.readonly)) { + return false; + } + + if (!FIRCLSIsValidPointer(needsClosing)) { + return false; + } + + *needsClosing = false; + + if (FIRCLSFileIsOpen(&_firclsContext.writable->binaryImage.file)) { + return true; + } + + if (!FIRCLSFileInitWithPath(&_firclsContext.writable->binaryImage.file, + _firclsContext.readonly->binaryimage.path, false)) { + FIRCLSSDKLog("Error: unable to open binary image log file\n"); + return false; + } + + *needsClosing = true; + + return true; +} + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSBinaryImageSafeFindImageForAddress(uintptr_t address, + FIRCLSBinaryImageRuntimeNode* image) { + if (!FIRCLSContextIsInitialized()) { + return false; + } + + if (address == 0) { + return false; + } + + if (!FIRCLSIsValidPointer(image)) { + return false; + } + + FIRCLSBinaryImageRuntimeNode* nodes = _firclsContext.writable->binaryImage.nodes; + if (!nodes) { + FIRCLSSDKLogError("The node structure is NULL\n"); + return false; + } + + for (uint32_t i = 0; i < CLS_BINARY_IMAGE_RUNTIME_NODE_COUNT; ++i) { + FIRCLSBinaryImageRuntimeNode* node = &nodes[i]; + if (!FIRCLSIsValidPointer(node)) { + FIRCLSSDKLog( + "Invalid node pointer encountered in context's writable binary image at index %i", i); + continue; + } + + if ((address >= (uintptr_t)node->baseAddress) && + (address < (uintptr_t)node->baseAddress + node->size)) { + *image = *node; // copy the image + return true; + } + } + + return false; +} + +bool FIRCLSBinaryImageSafeHasUnwindInfo(FIRCLSBinaryImageRuntimeNode* image) { + return FIRCLSIsValidPointer(image->unwindInfo); +} +#endif + +bool FIRCLSBinaryImageFindImageForUUID(const char* uuidString, + FIRCLSBinaryImageDetails* imageDetails) { + if (!imageDetails || !uuidString) { + FIRCLSSDKLog("null input\n"); + return false; + } + + uint32_t imageCount = _dyld_image_count(); + + for (uint32_t i = 0; i < imageCount; ++i) { + const struct mach_header* mh = _dyld_get_image_header(i); + + FIRCLSBinaryImageDetails image; + + image.slice = FIRCLSMachOSliceWithHeader((void*)mh); + FIRCLSBinaryImageFillInImageDetails(&image); + + if (strncmp(uuidString, image.uuidString, FIRCLSUUIDStringLength) == 0) { + *imageDetails = image; + return true; + } + } + + return false; +} + +#pragma mark - DYLD callback handlers +static void FIRCLSBinaryImageAddedCallback(const struct mach_header* mh, intptr_t vmaddr_slide) { + FIRCLSBinaryImageChanged(true, mh, vmaddr_slide); +} + +static void FIRCLSBinaryImageRemovedCallback(const struct mach_header* mh, intptr_t vmaddr_slide) { + FIRCLSBinaryImageChanged(false, mh, vmaddr_slide); +} + +#if CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME +static bool FIRCLSBinaryImagePopulateRuntimeNodeName(FIRCLSBinaryImageDetails* details) { + if (!FIRCLSIsValidPointer(details)) { + return false; + } + + memset(details->node.name, 0, CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE); + + // We have limited storage space for the name. And, we really want to store + // "CoreFoundation", not "/System/Library/Fram", so we have to play tricks + // to make sure we get the right side of the string. + const char* imageName = FIRCLSMachOSliceGetExecutablePath(&details->slice); + if (!imageName) { + return false; + } + + const size_t imageNameLength = strlen(imageName); + + // Remember to leave one character for null-termination. + if (imageNameLength > CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE - 1) { + imageName = imageName + (imageNameLength - (CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE - 1)); + } + + // subtract one to make sure the string is always null-terminated + strncpy(details->node.name, imageName, CLS_BINARY_IMAGE_RUNTIME_NODE_NAME_SIZE - 1); + + return true; +} +#endif + +// There were plans later to replace this with FIRCLSMachO +static FIRCLSMachOSegmentCommand FIRCLSBinaryImageMachOGetSegmentCommand( + const struct load_command* cmd) { + FIRCLSMachOSegmentCommand segmentCommand; + + memset(&segmentCommand, 0, sizeof(FIRCLSMachOSegmentCommand)); + + if (!cmd) { + return segmentCommand; + } + + if (cmd->cmd == LC_SEGMENT) { + struct segment_command* segCmd = (struct segment_command*)cmd; + + memcpy(segmentCommand.segname, segCmd->segname, 16); + segmentCommand.vmaddr = segCmd->vmaddr; + segmentCommand.vmsize = segCmd->vmsize; + } else if (cmd->cmd == LC_SEGMENT_64) { + struct segment_command_64* segCmd = (struct segment_command_64*)cmd; + + memcpy(segmentCommand.segname, segCmd->segname, 16); + segmentCommand.vmaddr = segCmd->vmaddr; + segmentCommand.vmsize = segCmd->vmsize; + } + + return segmentCommand; +} +#if !CLS_TARGET_OS_VISION +static bool FIRCLSBinaryImageMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice, + const char* segName, + const char* sectionName, + FIRCLSMachOSection* section) { + if (!FIRCLSIsValidPointer(slice)) { + return false; + } + + if (!section) { + return false; + } + + memset(section, 0, sizeof(FIRCLSMachOSection)); + + if (FIRCLSMachOSliceIs64Bit(slice)) { + const struct section_64* sect = + getsectbynamefromheader_64(slice->startAddress, segName, sectionName); + if (!sect) { + return false; + } + + section->addr = sect->addr; + section->size = sect->size; + section->offset = sect->offset; + } else { + const struct section* sect = getsectbynamefromheader(slice->startAddress, segName, sectionName); + if (!sect) { + return false; + } + + section->addr = sect->addr; + section->size = sect->size; + section->offset = sect->offset; + } + + return true; +} +#endif + +static void FIRCLSPopulateImageDetailWithLoadCommand(uint32_t type, + uint32_t size, + const struct load_command* cmd, + void* context) { + FIRCLSBinaryImageDetails* details = context; + switch (type) { + case LC_UUID: { + const uint8_t* uuid = FIRCLSMachOGetUUID(cmd); + FIRCLSSafeHexToString(uuid, 16, details->uuidString); + } break; + case LC_ENCRYPTION_INFO: + details->encrypted = FIRCLSMachOGetEncrypted(cmd); + break; + case LC_SEGMENT: + case LC_SEGMENT_64: { + FIRCLSMachOSegmentCommand segmentCommand = FIRCLSBinaryImageMachOGetSegmentCommand(cmd); + + if (strncmp(segmentCommand.segname, SEG_TEXT, sizeof(SEG_TEXT)) == 0) { + details->node.size = segmentCommand.vmsize; + } + } break; + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_WATCHOS: + details->minSDK = FIRCLSMachOGetMinimumOSVersion(cmd); + details->builtSDK = FIRCLSMachOGetLinkedSDKVersion(cmd); + break; + } +} + +static bool FIRCLSBinaryImageFillInImageDetails(FIRCLSBinaryImageDetails* details) { + if (!FIRCLSIsValidPointer(details)) { + return false; + } + + if (!FIRCLSIsValidPointer(details->slice.startAddress)) { + return false; + } + +#if CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME + // this is done for debugging purposes, so if it fails, its ok to continue + FIRCLSBinaryImagePopulateRuntimeNodeName(details); +#endif + + // This cast might look a little dubious, but its just because we're using the same + // struct types in a few different places. + details->node.baseAddress = (void* volatile)details->slice.startAddress; + + FIRCLSMachOSliceEnumerateLoadCommands_f(&details->slice, details, + FIRCLSPopulateImageDetailWithLoadCommand); + + // We look up the section we want, and we *should* be able to use: + // + // address of data we want = start address + section.offset + // + // However, the offset value is coming back funky in iOS 9. So, instead we look up the address + // the section should be loaded at, and compute the offset by looking up the address of the + // segment itself. + + FIRCLSMachOSection section; + +#if CLS_COMPACT_UNWINDING_SUPPORTED +#if !CLS_TARGET_OS_VISION + if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_TEXT, "__unwind_info", + §ion)) { + details->node.unwindInfo = (void*)(section.addr + details->vmaddr_slide); + } +#else + unsigned long unwindInfoSize; + details->node.unwindInfo = (void*)getsectiondata(details->slice.startAddress, "__TEXT", + "__unwind_info", &unwindInfoSize); +#endif +#endif + +#if CLS_DWARF_UNWINDING_SUPPORTED +#if !CLS_TARGET_OS_VISION + if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_TEXT, "__eh_frame", + §ion)) { + details->node.ehFrame = (void*)(section.addr + details->vmaddr_slide); + } +#else + unsigned long ehFrameSize; + details->node.ehFrame = + (void*)getsectiondata(details->slice.startAddress, "__TEXT", "__eh_frame", &ehFrameSize); +#endif +#endif + +#if !CLS_TARGET_OS_VISION + if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_DATA, "__crash_info", + §ion)) { + details->node.crashInfo = (void*)(section.addr + details->vmaddr_slide); + } +#else + unsigned long crashInfoSize; + details->node.crashInfo = + (void*)getsectiondata(details->slice.startAddress, "__TEXT", "__crash_info", &crashInfoSize); +#endif + + return true; +} + +typedef struct { + FIRCLSBinaryImageDetails details; + bool added; +} FIRCLSImageChange; + +static void FIRCLSProcessBinaryImageChange(void* context) { + FIRCLSImageChange* imageChange = context; + // this is an atomic operation + FIRCLSBinaryImageStoreNode(imageChange->added, imageChange->details); + FIRCLSBinaryImageRecordSlice(imageChange->added, imageChange->details); + free(context); +} + +static void FIRCLSBinaryImageChanged(bool added, + const struct mach_header* mh, + intptr_t vmaddr_slide) { + // FIRCLSSDKLog("Binary image %s %p\n", added ? "loaded" : "unloaded", mh); + FIRCLSBinaryImageDetails imageDetails; + memset(&imageDetails, 0, sizeof(FIRCLSBinaryImageDetails)); + + imageDetails.slice = FIRCLSMachOSliceWithHeader((void*)mh); + imageDetails.vmaddr_slide = vmaddr_slide; + // fill imageDetails fields using slice & vmaddr_slide + FIRCLSBinaryImageFillInImageDetails(&imageDetails); + + FIRCLSImageChange* change = malloc(sizeof(FIRCLSImageChange)); + if (!change) return; + change->added = added; + change->details = imageDetails; + dispatch_async_f(FIRCLSGetBinaryImageQueue(), change, FIRCLSProcessBinaryImageChange); +} + +#pragma mark - In-Memory Storage +static void FIRCLSBinaryImageStoreNode(bool added, FIRCLSBinaryImageDetails imageDetails) { + // This function is mutating a structure that needs to be accessed at crash time. We + // need to make sure the structure is always in as valid a state as possible. + // FIRCLSSDKLog("Storing %s node %p\n", added ? "loaded" : "unloaded", + // (void*)imageDetails.node.baseAddress); + + if (!_firclsContext.writable) { + FIRCLSSDKLog("Error: Writable context is NULL\n"); + return; + } + + // looking for an empty space if an image added + void* searchAddress = NULL; + bool success = false; + FIRCLSBinaryImageRuntimeNode* nodes = _firclsContext.writable->binaryImage.nodes; + + if (!added) { + // capture the search address first + searchAddress = imageDetails.node.baseAddress; + + // If we are removing a node, we need to set its entries to zero. By clearing all of + // these values, we can just copy in imageDetails.node. Using memset here is slightly + // weird, since we have to restore one field. But, this way, if/when the structure changes, + // we still do the right thing. + memset(&imageDetails.node, 0, sizeof(FIRCLSBinaryImageRuntimeNode)); + + // restore the baseAddress, which just got zeroed, and is used for indexing + imageDetails.node.baseAddress = searchAddress; + } + + for (uint32_t i = 0; i < CLS_BINARY_IMAGE_RUNTIME_NODE_COUNT; ++i) { + FIRCLSBinaryImageRuntimeNode* node = &nodes[i]; + + if (!node) { + FIRCLSSDKLog("Error: Binary image storage is NULL\n"); + break; + } + + // navigate through the array, looking for our matching address + if (node->baseAddress != searchAddress) { + continue; + } + + // Attempt to swap the base address with whatever we are searching for. Success means that + // entry has been claims/cleared. Failure means some other thread beat us to it. + if (atomic_compare_exchange_strong(&node->baseAddress, &searchAddress, + imageDetails.node.baseAddress)) { + *node = imageDetails.node; + success = true; + + break; + } + + // If this is an unload, getting here means two threads unloaded at the same time. I think + // that's highly unlikely, and possibly even impossible. So, I'm choosing to abort the process + // at this point. + if (!added) { + FIRCLSSDKLog("Error: Failed to swap during image unload\n"); + break; + } + } + + if (!success) { + FIRCLSSDKLog("Error: Unable to track a %s node %p\n", added ? "loaded" : "unloaded", + (void*)imageDetails.node.baseAddress); + } +} + +#pragma mark - On-Disk Storage +static void FIRCLSBinaryImageRecordDetails(FIRCLSFile* file, + const FIRCLSBinaryImageDetails imageDetails) { + if (!file) { + FIRCLSSDKLog("Error: file is invalid\n"); + return; + } + + FIRCLSFileWriteHashEntryString(file, "uuid", imageDetails.uuidString); + FIRCLSFileWriteHashEntryUint64(file, "base", (uintptr_t)imageDetails.slice.startAddress); + FIRCLSFileWriteHashEntryUint64(file, "size", imageDetails.node.size); +} + +static void FIRCLSBinaryImageRecordLibraryFrameworkInfo(FIRCLSFile* file, const char* path) { + if (!file) { + FIRCLSSDKLog("Error: file is invalid\n"); + return; + } + + if (!path) { + return; + } + + // Because this function is so expensive, we've decided to omit this info for all Apple-supplied + // frameworks. This really isn't that bad, because we can know their info ahead of time (within a + // small margin of error). With this implementation, we will still record this info for any + // user-built framework, which in the end is the most important thing. + if (strncmp(path, "/System", 7) == 0) { + return; + } + + // check to see if this is a potential framework bundle + if (!strstr(path, ".framework")) { + return; + } + + // My.framework/Versions/A/My for OS X + // My.framework/My for iOS + + NSString* frameworkPath = [NSString stringWithUTF8String:path]; +#if TARGET_OS_IPHONE + frameworkPath = [frameworkPath stringByDeletingLastPathComponent]; +#else + frameworkPath = [frameworkPath stringByDeletingLastPathComponent]; // My.framework/Versions/A + frameworkPath = [frameworkPath stringByDeletingLastPathComponent]; // My.framework/Versions + frameworkPath = [frameworkPath stringByDeletingLastPathComponent]; // My.framework +#endif + + NSBundle* const bundle = [NSBundle bundleWithPath:frameworkPath]; + + if (!bundle) { + return; + } + + FIRCLSFileWriteHashEntryNSStringUnlessNilOrEmpty(file, "bundle_id", [bundle bundleIdentifier]); + FIRCLSFileWriteHashEntryNSStringUnlessNilOrEmpty( + file, "build_version", [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]); + FIRCLSFileWriteHashEntryNSStringUnlessNilOrEmpty( + file, "display_version", [bundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"]); +} + +static void FIRCLSBinaryImageRecordSlice(bool added, const FIRCLSBinaryImageDetails imageDetails) { + bool needsClosing = false; + if (!FIRCLSBinaryImageOpenIfNeeded(&needsClosing)) { + FIRCLSSDKLog("Error: unable to open binary image log file\n"); + return; + } + + FIRCLSFile* file = &_firclsContext.writable->binaryImage.file; + + FIRCLSFileWriteSectionStart(file, added ? "load" : "unload"); + + FIRCLSFileWriteHashStart(file); + + const char* path = FIRCLSMachOSliceGetExecutablePath((FIRCLSMachOSliceRef)&imageDetails.slice); + + FIRCLSFileWriteHashEntryString(file, "path", path); + + if (added) { + // this won't work if the binary has been unloaded + FIRCLSBinaryImageRecordLibraryFrameworkInfo(file, path); + } + + FIRCLSBinaryImageRecordDetails(file, imageDetails); + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); + + if (needsClosing) { + FIRCLSFileClose(file); + } +} + +bool FIRCLSBinaryImageRecordMainExecutable(FIRCLSFile* file) { + FIRCLSBinaryImageDetails imageDetails; + + memset(&imageDetails, 0, sizeof(FIRCLSBinaryImageDetails)); + + imageDetails.slice = FIRCLSMachOSliceGetCurrent(); + FIRCLSBinaryImageFillInImageDetails(&imageDetails); + + FIRCLSFileWriteSectionStart(file, "executable"); + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryString(file, "architecture", + FIRCLSMachOSliceGetArchitectureName(&imageDetails.slice)); + + FIRCLSBinaryImageRecordDetails(file, imageDetails); + FIRCLSFileWriteHashEntryBoolean(file, "encrypted", imageDetails.encrypted); + FIRCLSFileWriteHashEntryString(file, "minimum_sdk_version", + [FIRCLSMachOFormatVersion(&imageDetails.minSDK) UTF8String]); + FIRCLSFileWriteHashEntryString(file, "built_sdk_version", + [FIRCLSMachOFormatVersion(&imageDetails.builtSDK) UTF8String]); + + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); + + return true; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.h new file mode 100644 index 0000000..b477ae1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.h @@ -0,0 +1,101 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h" + +#include +#include + +// The purpose of the crash context is to hold values that absolutely must be read and/or written at +// crash time. For robustness against memory corruption, they are protected with guard pages. +// Further, the context is separated into read-only and read-write sections. + +__BEGIN_DECLS + +#ifdef __OBJC__ +@class FIRCLSInternalReport; +@class FIRCLSSettings; +@class FIRCLSInstallIdentifierModel; +@class FIRCLSFileManager; +@class FIRCLSContextInitData; +#endif + +typedef struct { + volatile bool initialized; + volatile bool debuggerAttached; + const char* previouslyCrashedFileFullPath; + const char* logPath; + // Initial report path represents the report path used to initialized the context; + // where non-on-demand exceptions and other crashes will be written. + const char* initialReportPath; +#if CLS_USE_SIGALTSTACK + void* signalStack; +#endif +#if CLS_MACH_EXCEPTION_SUPPORTED + void* machStack; +#endif + + FIRCLSBinaryImageReadOnlyContext binaryimage; + FIRCLSExceptionReadOnlyContext exception; + FIRCLSHostReadOnlyContext host; +#if CLS_SIGNAL_SUPPORTED + FIRCLSSignalReadContext signal; +#endif +#if CLS_MACH_EXCEPTION_SUPPORTED + FIRCLSMachExceptionReadContext machException; +#endif + FIRCLSUserLoggingReadOnlyContext logging; +} FIRCLSReadOnlyContext; + +typedef struct { + FIRCLSInternalLoggingWritableContext internalLogging; + volatile bool crashOccurred; + FIRCLSBinaryImageReadWriteContext binaryImage; + FIRCLSUserLoggingWritableContext logging; + FIRCLSExceptionWritableContext exception; +} FIRCLSReadWriteContext; + +typedef struct { + FIRCLSReadOnlyContext* readonly; + FIRCLSReadWriteContext* writable; + FIRCLSAllocatorRef allocator; +} FIRCLSContext; +#ifdef __OBJC__ +bool FIRCLSContextInitialize(FIRCLSContextInitData* initData, FIRCLSFileManager* fileManager); +FIRCLSContextInitData* FIRCLSContextBuildInitData(FIRCLSInternalReport* report, + FIRCLSSettings* settings, + FIRCLSFileManager* fileManager, + NSString* appQualitySessionId); +bool FIRCLSContextRecordMetadata(NSString* rootPath, FIRCLSContextInitData* initData); +#endif + +void FIRCLSContextBaseInit(void); +void FIRCLSContextBaseDeinit(void); + +bool FIRCLSContextIsInitialized(void); +bool FIRCLSContextHasCrashed(void); +void FIRCLSContextMarkHasCrashed(void); +bool FIRCLSContextMarkAndCheckIfCrashed(void); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.m new file mode 100644 index 0000000..a09ab43 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSContext.m @@ -0,0 +1,438 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h" + +#include +#include + +#import "Crashlytics/Shared/FIRCLSConstants.h" + +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" + +#include "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +// The writable size is our handler stack plus whatever scratch we need. We have to use this space +// extremely carefully, however, because thread stacks always needs to be page-aligned. Only the +// first allocation is guaranteed to be page-aligned. +// +// CLS_SIGNAL_HANDLER_STACK_SIZE and CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE are platform dependant, +// defined as 0 for tv/watch. +#define CLS_MINIMUM_READWRITE_SIZE \ + (CLS_SIGNAL_HANDLER_STACK_SIZE + CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE + \ + sizeof(FIRCLSReadWriteContext)) + +// We need enough space here for the context, plus storage for strings. +#define CLS_MINIMUM_READABLE_SIZE (sizeof(FIRCLSReadOnlyContext) + 4096 * 4) + +static const int64_t FIRCLSContextInitWaitTime = 5LL * NSEC_PER_SEC; + +static const char* FIRCLSContextAppendToRoot(NSString* root, NSString* component); +static void FIRCLSContextAllocate(FIRCLSContext* context); + +FIRCLSContextInitData* FIRCLSContextBuildInitData(FIRCLSInternalReport* report, + FIRCLSSettings* settings, + FIRCLSFileManager* fileManager, + NSString* appQualitySessionId) { + // Because we need to start the crash reporter right away, + // it starts up either with default settings, or cached settings + // from the last time they were fetched + + FIRCLSContextInitData* initData = [[FIRCLSContextInitData alloc] init]; + initData.customBundleId = nil; + initData.sessionId = [report identifier]; + initData.appQualitySessionId = appQualitySessionId; + initData.rootPath = [report path]; + initData.previouslyCrashedFileRootPath = [fileManager rootPath]; + initData.errorsEnabled = [settings errorReportingEnabled]; + initData.customExceptionsEnabled = [settings customExceptionsEnabled]; + initData.maxCustomExceptions = [settings maxCustomExceptions]; + initData.maxErrorLogSize = [settings errorLogBufferSize]; + initData.maxLogSize = [settings logBufferSize]; + initData.maxKeyValues = [settings maxCustomKeys]; + initData.betaToken = @""; + + return initData; +} + +bool FIRCLSContextInitialize(FIRCLSContextInitData* initData, FIRCLSFileManager* fileManager) { + if (!initData) { + return false; + } + + FIRCLSContextBaseInit(); + + dispatch_group_t group = dispatch_group_create(); + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + if (!FIRCLSIsValidPointer(initData.rootPath)) { + return false; + } + + NSString* rootPath = initData.rootPath; + + // setup our SDK log file synchronously, because other calls may depend on it + _firclsContext.readonly->logPath = FIRCLSContextAppendToRoot(rootPath, @"sdk.log"); + _firclsContext.readonly->initialReportPath = FIRCLSDupString([[initData rootPath] UTF8String]); + if (!FIRCLSUnlinkIfExists(_firclsContext.readonly->logPath)) { + FIRCLSErrorLog(@"Unable to write initialize SDK write paths %s", strerror(errno)); + } + + // some values that aren't tied to particular subsystem + _firclsContext.readonly->debuggerAttached = FIRCLSProcessDebuggerAttached(); + + dispatch_group_async(group, queue, ^{ + FIRCLSHostInitialize(&_firclsContext.readonly->host); + }); + + dispatch_group_async(group, queue, ^{ + _firclsContext.readonly->logging.errorStorage.maxSize = 0; + _firclsContext.readonly->logging.errorStorage.maxEntries = + initData.errorsEnabled ? initData.maxCustomExceptions : 0; + _firclsContext.readonly->logging.errorStorage.restrictBySize = false; + _firclsContext.readonly->logging.errorStorage.entryCount = + &_firclsContext.writable->logging.errorsCount; + _firclsContext.readonly->logging.errorStorage.aPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorAFile); + _firclsContext.readonly->logging.errorStorage.bPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportErrorBFile); + + _firclsContext.readonly->logging.logStorage.maxSize = initData.maxLogSize; + _firclsContext.readonly->logging.logStorage.maxEntries = 0; + _firclsContext.readonly->logging.logStorage.restrictBySize = true; + _firclsContext.readonly->logging.logStorage.entryCount = NULL; + _firclsContext.readonly->logging.logStorage.aPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogAFile); + _firclsContext.readonly->logging.logStorage.bPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportLogBFile); + _firclsContext.readonly->logging.customExceptionStorage.aPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionAFile); + _firclsContext.readonly->logging.customExceptionStorage.bPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportCustomExceptionBFile); + _firclsContext.readonly->logging.customExceptionStorage.maxSize = 0; + _firclsContext.readonly->logging.customExceptionStorage.restrictBySize = false; + _firclsContext.readonly->logging.customExceptionStorage.maxEntries = + initData.maxCustomExceptions; + _firclsContext.readonly->logging.customExceptionStorage.entryCount = + &_firclsContext.writable->exception.customExceptionCount; + + _firclsContext.readonly->logging.userKVStorage.maxCount = initData.maxKeyValues; + _firclsContext.readonly->logging.userKVStorage.incrementalPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserIncrementalKVFile); + _firclsContext.readonly->logging.userKVStorage.compactedPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportUserCompactedKVFile); + + _firclsContext.readonly->logging.internalKVStorage.maxCount = 32; // Hardcode = bad + _firclsContext.readonly->logging.internalKVStorage.incrementalPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalIncrementalKVFile); + _firclsContext.readonly->logging.internalKVStorage.compactedPath = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportInternalCompactedKVFile); + + FIRCLSUserLoggingInit(&_firclsContext.readonly->logging, &_firclsContext.writable->logging); + }); + + dispatch_group_async(group, queue, ^{ + _firclsContext.readonly->binaryimage.path = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportBinaryImageFile); + + FIRCLSBinaryImageInit(); + }); + + dispatch_group_async(group, queue, ^{ + NSString* rootPath = initData.previouslyCrashedFileRootPath; + NSString* fileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName]; + _firclsContext.readonly->previouslyCrashedFileFullPath = + FIRCLSContextAppendToRoot(rootPath, fileName); + }); + + // To initialize Crashlytics handlers even if the Xcode debugger is attached, replace this check + // with YES. Note that this is only possible to do on an actual device as it will cause the + // simulator to crash. + if (!_firclsContext.readonly->debuggerAttached) { +#if CLS_SIGNAL_SUPPORTED + dispatch_group_async(group, queue, ^{ + _firclsContext.readonly->signal.path = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportSignalFile); + + FIRCLSSignalInitialize(&_firclsContext.readonly->signal); + }); +#endif + +#if CLS_MACH_EXCEPTION_SUPPORTED + dispatch_group_async(group, queue, ^{ + _firclsContext.readonly->machException.path = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportMachExceptionFile); + + FIRCLSMachExceptionInit(&_firclsContext.readonly->machException); + }); +#endif + + dispatch_group_async(group, queue, ^{ + _firclsContext.readonly->exception.path = + FIRCLSContextAppendToRoot(rootPath, FIRCLSReportExceptionFile); + _firclsContext.readonly->exception.maxCustomExceptions = + initData.customExceptionsEnabled ? initData.maxCustomExceptions : 0; + + FIRCLSExceptionInitialize(&_firclsContext.readonly->exception, + &_firclsContext.writable->exception); + }); + } else { + FIRCLSSDKLog("Debugger present - not installing handlers\n"); + } + + dispatch_group_async(group, queue, ^{ + if (!FIRCLSContextRecordMetadata(rootPath, initData)) { + FIRCLSSDKLog("Unable to record context metadata\n"); + } + }); + + // At this point we need to do two things. First, we need to do our memory protection *only* after + // all of these initialization steps are really done. But, we also want to wait as long as + // possible for these to be complete. If we do not, there's a chance that we will not be able to + // correctly report a crash shortly after start. + + // Note at this will retain the group, so its totally fine to release the group here. + dispatch_group_notify(group, queue, ^{ + _firclsContext.readonly->initialized = true; + __sync_synchronize(); + + if (!FIRCLSAllocatorProtect(_firclsContext.allocator)) { + FIRCLSSDKLog("Error: Memory protection failed\n"); + } + }); + + if (dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, FIRCLSContextInitWaitTime)) != + 0) { + FIRCLSSDKLog("Error: Delayed initialization\n"); + } + + return true; +} + +void FIRCLSContextBaseInit(void) { + NSString* sdkBundleID = FIRCLSApplicationGetSDKBundleID(); + + NSString* loggingQueueName = [sdkBundleID stringByAppendingString:@".logging"]; + NSString* binaryImagesQueueName = [sdkBundleID stringByAppendingString:@".binary-images"]; + NSString* exceptionQueueName = [sdkBundleID stringByAppendingString:@".exception"]; + + _firclsLoggingQueue = dispatch_queue_create([loggingQueueName UTF8String], DISPATCH_QUEUE_SERIAL); + _firclsBinaryImageQueue = + dispatch_queue_create([binaryImagesQueueName UTF8String], DISPATCH_QUEUE_SERIAL); + _firclsExceptionQueue = + dispatch_queue_create([exceptionQueueName UTF8String], DISPATCH_QUEUE_SERIAL); + + FIRCLSContextAllocate(&_firclsContext); + + _firclsContext.writable->internalLogging.logFd = -1; + _firclsContext.writable->internalLogging.logLevel = FIRCLSInternalLogLevelDebug; + _firclsContext.writable->crashOccurred = false; + + _firclsContext.readonly->initialized = false; + + __sync_synchronize(); +} + +static void FIRCLSContextAllocate(FIRCLSContext* context) { + // create the allocator, and the contexts + // The ordering here is really important, because the "stack" variable must be + // page-aligned. There's no mechanism to ask the allocator to do alignment, but we + // do know the very first allocation in a region is aligned to a page boundary. + + context->allocator = FIRCLSAllocatorCreate(CLS_MINIMUM_READWRITE_SIZE, CLS_MINIMUM_READABLE_SIZE); + + context->readonly = + FIRCLSAllocatorSafeAllocate(context->allocator, sizeof(FIRCLSReadOnlyContext), CLS_READONLY); + memset(context->readonly, 0, sizeof(FIRCLSReadOnlyContext)); + +#if CLS_MEMORY_PROTECTION_ENABLED +#if CLS_MACH_EXCEPTION_SUPPORTED + context->readonly->machStack = FIRCLSAllocatorSafeAllocate( + context->allocator, CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE, CLS_READWRITE); +#endif +#if CLS_USE_SIGALTSTACK + context->readonly->signalStack = + FIRCLSAllocatorSafeAllocate(context->allocator, CLS_SIGNAL_HANDLER_STACK_SIZE, CLS_READWRITE); +#endif +#else +#if CLS_MACH_EXCEPTION_SUPPORTED + context->readonly->machStack = valloc(CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE); +#endif +#if CLS_USE_SIGALTSTACK + context->readonly->signalStack = valloc(CLS_SIGNAL_HANDLER_STACK_SIZE); +#endif +#endif + +#if CLS_MACH_EXCEPTION_SUPPORTED + memset(_firclsContext.readonly->machStack, 0, CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE); +#endif +#if CLS_USE_SIGALTSTACK + memset(_firclsContext.readonly->signalStack, 0, CLS_SIGNAL_HANDLER_STACK_SIZE); +#endif + + context->writable = FIRCLSAllocatorSafeAllocate(context->allocator, + sizeof(FIRCLSReadWriteContext), CLS_READWRITE); + memset(context->writable, 0, sizeof(FIRCLSReadWriteContext)); +} + +void FIRCLSContextBaseDeinit(void) { + _firclsContext.readonly->initialized = false; + + FIRCLSAllocatorDestroy(_firclsContext.allocator); +} + +bool FIRCLSContextIsInitialized(void) { + __sync_synchronize(); + if (!FIRCLSIsValidPointer(_firclsContext.readonly)) { + return false; + } + + return _firclsContext.readonly->initialized; +} + +bool FIRCLSContextHasCrashed(void) { + if (!FIRCLSContextIsInitialized()) { + return false; + } + + // we've already run a full barrier above, so this read is ok + return _firclsContext.writable->crashOccurred; +} + +void FIRCLSContextMarkHasCrashed(void) { + if (!FIRCLSContextIsInitialized()) { + return; + } + + _firclsContext.writable->crashOccurred = true; + __sync_synchronize(); +} + +bool FIRCLSContextMarkAndCheckIfCrashed(void) { + if (!FIRCLSContextIsInitialized()) { + return false; + } + + if (_firclsContext.writable->crashOccurred) { + return true; + } + + _firclsContext.writable->crashOccurred = true; + __sync_synchronize(); + + return false; +} + +static const char* FIRCLSContextAppendToRoot(NSString* root, NSString* component) { + return FIRCLSDupString( + [[root stringByAppendingPathComponent:component] fileSystemRepresentation]); +} + +static bool FIRCLSContextRecordIdentity(FIRCLSFile* file, + const char* sessionId, + const char* betaToken, + const char* appQualitySessionId) { + FIRCLSFileWriteSectionStart(file, "identity"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryString(file, "generator", FIRCLSSDKGeneratorName().UTF8String); + FIRCLSFileWriteHashEntryString(file, "display_version", FIRCLSSDKVersion().UTF8String); + FIRCLSFileWriteHashEntryString(file, "build_version", FIRCLSSDKVersion().UTF8String); + FIRCLSFileWriteHashEntryUint64(file, "started_at", time(NULL)); + + FIRCLSFileWriteHashEntryString(file, "session_id", sessionId); + FIRCLSFileWriteHashEntryString(file, "app_quality_session_id", appQualitySessionId); + + // install_id is written into the proto directly. This is only left here to + // support Apple Report Converter. + FIRCLSFileWriteHashEntryString(file, "install_id", ""); + FIRCLSFileWriteHashEntryString(file, "beta_token", betaToken); + FIRCLSFileWriteHashEntryBoolean(file, "absolute_log_timestamps", true); + + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); + + return true; +} + +static bool FIRCLSContextRecordApplication(FIRCLSFile* file, const char* customBundleId) { + FIRCLSFileWriteSectionStart(file, "application"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryString(file, "bundle_id", + [FIRCLSApplicationGetBundleIdentifier() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "custom_bundle_id", customBundleId); + FIRCLSFileWriteHashEntryString(file, "build_version", + [FIRCLSApplicationGetBundleVersion() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "display_version", + [FIRCLSApplicationGetShortBundleVersion() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "extension_id", + [FIRCLSApplicationExtensionPointIdentifier() UTF8String]); + + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); + + return true; +} + +bool FIRCLSContextRecordMetadata(NSString* rootPath, const FIRCLSContextInitData* initData) { + const char* sessionId = [[initData sessionId] UTF8String]; + const char* betaToken = [[initData betaToken] UTF8String]; + const char* customBundleId = [[initData customBundleId] UTF8String]; + const char* appQualitySessionId = [[initData appQualitySessionId] UTF8String]; + const char* path = + [[rootPath stringByAppendingPathComponent:FIRCLSReportMetadataFile] fileSystemRepresentation]; + if (!FIRCLSUnlinkIfExists(path)) { + FIRCLSSDKLog("Unable to unlink existing metadata file %s\n", strerror(errno)); + } + + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, path, false)) { + FIRCLSSDKLog("Unable to open metadata file %s\n", strerror(errno)); + return false; + } + + if (!FIRCLSContextRecordIdentity(&file, sessionId, betaToken, appQualitySessionId)) { + FIRCLSSDKLog("Unable to write out identity metadata\n"); + } + + if (!FIRCLSHostRecord(&file)) { + FIRCLSSDKLog("Unable to write out host metadata\n"); + } + + if (!FIRCLSContextRecordApplication(&file, customBundleId)) { + FIRCLSSDKLog("Unable to write out application metadata\n"); + } + + if (!FIRCLSBinaryImageRecordMainExecutable(&file)) { + FIRCLSSDKLog("Unable to write out executable metadata\n"); + } + + FIRCLSFileClose(&file); + + return true; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.c new file mode 100644 index 0000000..5227278 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.c @@ -0,0 +1,31 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +const char *FIRCLSCrashedMarkerFileName = "previously-crashed"; + +void FIRCLSCreateCrashedMarkerFile(void) { + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, _firclsContext.readonly->previouslyCrashedFileFullPath, false)) { + FIRCLSSDKLog("Unable to create the crashed marker file\n"); + return; + } + + FIRCLSFileClose(&file); + FIRCLSSDKLog("Created the crashed marker file\n"); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h new file mode 100644 index 0000000..ccf4276 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h @@ -0,0 +1,19 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +extern const char *FIRCLSCrashedMarkerFileName; + +void FIRCLSCreateCrashedMarkerFile(void); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSGlobals.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSGlobals.h new file mode 100644 index 0000000..10173ed --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSGlobals.h @@ -0,0 +1,28 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h" + +__BEGIN_DECLS + +extern FIRCLSContext _firclsContext; +extern dispatch_queue_t _firclsLoggingQueue; +extern dispatch_queue_t _firclsBinaryImageQueue; +extern dispatch_queue_t _firclsExceptionQueue; + +#define FIRCLSGetLoggingQueue() (_firclsLoggingQueue) +#define FIRCLSGetBinaryImageQueue() (_firclsBinaryImageQueue) +#define FIRCLSGetExceptionQueue() (_firclsExceptionQueue) + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.h new file mode 100644 index 0000000..0e94d36 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.h @@ -0,0 +1,39 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +typedef struct { + const char* documentDirectoryPath; + vm_size_t pageSize; +} FIRCLSHostReadOnlyContext; + +__BEGIN_DECLS + +void FIRCLSHostInitialize(FIRCLSHostReadOnlyContext* roContext); + +vm_size_t FIRCLSHostGetPageSize(void); + +bool FIRCLSHostRecord(FIRCLSFile* file); + +void FIRCLSHostWriteDiskUsage(FIRCLSFile* file); + +bool FIRCLSHostIsRosettaTranslated(void); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.m new file mode 100644 index 0000000..c1f41a0 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSHost.m @@ -0,0 +1,195 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h" + +#include +#include + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#import "Crashlytics/Shared/FIRCLSFABHost.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +#define CLS_HOST_SYSCTL_BUFFER_SIZE (128) +#define CLS_MAX_ARM64_NATIVE_PAGE_SIZE (1024 * 16) + +#if CLS_CPU_ARM64 +#define CLS_MAX_NATIVE_PAGE_SIZE CLS_MAX_ARM64_NATIVE_PAGE_SIZE +#else +// return 4K, which is correct for all platforms except arm64, currently +#define CLS_MAX_NATIVE_PAGE_SIZE (1024 * 4) +#endif +#define CLS_MIN_NATIVE_PAGE_SIZE (1024 * 4) + +#pragma mark Prototypes +static void FIRCLSHostWriteSysctlEntry( + FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize); +static void FIRCLSHostWriteModelInfo(FIRCLSFile* file); +static void FIRCLSHostWriteOSVersionInfo(FIRCLSFile* file); + +#pragma mark - API +void FIRCLSHostInitialize(FIRCLSHostReadOnlyContext* roContext) { + _firclsContext.readonly->host.pageSize = FIRCLSHostGetPageSize(); + _firclsContext.readonly->host.documentDirectoryPath = NULL; + + // determine where the document directory is mounted, so we can get file system statistics later + NSArray* paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + if ([paths count]) { + _firclsContext.readonly->host.documentDirectoryPath = + FIRCLSDupString([[paths objectAtIndex:0] fileSystemRepresentation]); + } +} + +vm_size_t FIRCLSHostGetPageSize(void) { + size_t size; + int pageSize; + + // hw.pagesize is defined as HW_PAGESIZE, which is an int. It's important to match + // these types. Turns out that sysctl will not init the data to zero, but it appears + // that sysctlbyname does. This API is nicer, but that's important to keep in mind. + + int maxNativePageSize = CLS_MAX_NATIVE_PAGE_SIZE; + + // On Apple Silicon, we need to use the arm64 page size + // even if we're in x86 land. + if (FIRCLSHostIsRosettaTranslated()) { + FIRCLSSDKLog("Running under Rosetta 2 emulation. Using the arm64 page size.\n"); + + maxNativePageSize = CLS_MAX_ARM64_NATIVE_PAGE_SIZE; + } + + pageSize = 0; + size = sizeof(pageSize); + if (sysctlbyname("hw.pagesize", &pageSize, &size, NULL, 0) != 0) { + FIRCLSSDKLog("sysctlbyname failed while trying to get hw.pagesize\n"); + + return maxNativePageSize; + } + + // if the returned size is not the expected value, abort + if (size != sizeof(pageSize)) { + return maxNativePageSize; + } + + // put in some guards to make sure our size is reasonable + if (pageSize > maxNativePageSize) { + return maxNativePageSize; + } + + if (pageSize < CLS_MIN_NATIVE_PAGE_SIZE) { + return CLS_MIN_NATIVE_PAGE_SIZE; + } + + return pageSize; +} + +// This comes from the Apple documentation here: +// https://developer.apple.com/documentation/apple_silicon/about_the_rosetta_translation_environment +bool FIRCLSHostIsRosettaTranslated(void) { +#if TARGET_OS_MAC + int result = 0; + size_t size = sizeof(result); + if (sysctlbyname("sysctl.proc_translated", &result, &size, NULL, 0) == -1) { + // If we get an error, or 0, we're going to treat this as x86_64 macOS native + if (errno == ENOENT) { + return false; + } + // This is the error case + FIRCLSSDKLog("sysctlbyname failed while trying to get sysctl.proc_translated for Rosetta 2 " + "translation\n"); + return false; + } + return result == 1; + +#else + return false; +#endif +} + +static void FIRCLSHostWriteSysctlEntry( + FIRCLSFile* file, const char* key, const char* sysctlKey, void* buffer, size_t bufferSize) { + if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) { + FIRCLSFileWriteHashEntryString(file, key, "(failed)"); + return; + } + + FIRCLSFileWriteHashEntryString(file, key, buffer); +} + +static void FIRCLSHostWriteModelInfo(FIRCLSFile* file) { + FIRCLSFileWriteHashEntryString(file, "model", [FIRCLSHostModelInfo() UTF8String]); + + // allocate a static buffer for the sysctl values, which are typically + // quite short + char buffer[CLS_HOST_SYSCTL_BUFFER_SIZE]; + +#if TARGET_OS_EMBEDDED + FIRCLSHostWriteSysctlEntry(file, "machine", "hw.model", buffer, CLS_HOST_SYSCTL_BUFFER_SIZE); +#else + FIRCLSHostWriteSysctlEntry(file, "machine", "hw.machine", buffer, CLS_HOST_SYSCTL_BUFFER_SIZE); + FIRCLSHostWriteSysctlEntry(file, "cpu", "machdep.cpu.brand_string", buffer, + CLS_HOST_SYSCTL_BUFFER_SIZE); +#endif +} + +static void FIRCLSHostWriteOSVersionInfo(FIRCLSFile* file) { + FIRCLSFileWriteHashEntryString(file, "os_build_version", [FIRCLSHostOSBuildVersion() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "os_display_version", + [FIRCLSHostOSDisplayVersion() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "platform", [FIRCLSApplicationGetPlatform() UTF8String]); + FIRCLSFileWriteHashEntryString(file, "firebase_platform", + [FIRCLSApplicationGetFirebasePlatform() UTF8String]); +} + +bool FIRCLSHostRecord(FIRCLSFile* file) { + FIRCLSFileWriteSectionStart(file, "host"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSHostWriteModelInfo(file); + FIRCLSHostWriteOSVersionInfo(file); + FIRCLSFileWriteHashEntryString(file, "locale", + [[[NSLocale currentLocale] localeIdentifier] UTF8String]); + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); + + return true; +} + +void FIRCLSHostWriteDiskUsage(FIRCLSFile* file) { + FIRCLSFileWriteSectionStart(file, "storage"); + + FIRCLSFileWriteHashStart(file); + + // Due to Apple Privacy Manifests, Crashlytics is not collecting + // disk space using statfs. When we find a solution, we can update + // this to actually track disk space correctly. + FIRCLSFileWriteHashEntryUint64(file, "free", 0); + FIRCLSFileWriteHashEntryUint64(file, "total", 0); + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.c new file mode 100644 index 0000000..89d6e28 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.c @@ -0,0 +1,840 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include +#include +#include +#include + +#define THREAD_NAME_BUFFER_SIZE (64) + +#pragma mark Prototypes +static bool FIRCLSProcessGetThreadName(FIRCLSProcess *process, + thread_t thread, + char *buffer, + size_t length); +static const char *FIRCLSProcessGetThreadDispatchQueueName(FIRCLSProcess *process, thread_t thread); + +#pragma mark - API +bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uapVoid) { + if (!process) { + return false; + } + + process->task = mach_task_self(); + process->thisThread = mach_thread_self(); + process->crashedThread = crashedThread; + process->uapVoid = uapVoid; + + if (task_threads(process->task, &process->threads, &process->threadCount) != KERN_SUCCESS) { + // failed to get all threads + process->threadCount = 0; + FIRCLSSDKLog("Error: unable to get task threads\n"); + + return false; + } + + return true; +} + +// https://developer.apple.com/library/mac/#qa/qa2004/qa1361.html +bool FIRCLSProcessDebuggerAttached(void) { + int junk; + int mib[4]; + struct kinfo_proc info; + size_t size; + + // Initialize the flags so that, if sysctl fails for some bizarre + // reason, we get a predictable result. + info.kp_proc.p_flag = 0; + + // Initialize mib, which tells sysctl the info we want, in this case + // we're looking for information about a specific process ID. + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + + // Call sysctl. + size = sizeof(info); + junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); + if (junk != 0) { + FIRCLSSDKLog("sysctl failed while trying to get kinfo_proc\n"); + return false; + } + + // We're being debugged if the P_TRACED flag is set. + return (info.kp_proc.p_flag & P_TRACED) != 0; +} + +#pragma mark - Thread Support +static bool FIRCLSProcessIsCurrentThread(FIRCLSProcess *process, thread_t thread) { + return MACH_PORT_INDEX(process->thisThread) == MACH_PORT_INDEX(thread); +} + +static bool FIRCLSProcessIsCrashedThread(FIRCLSProcess *process, thread_t thread) { + return MACH_PORT_INDEX(process->crashedThread) == MACH_PORT_INDEX(thread); +} + +static uint32_t FIRCLSProcessGetThreadCount(FIRCLSProcess *process) { + return process->threadCount; +} + +static thread_t FIRCLSProcessGetThread(FIRCLSProcess *process, uint32_t index) { + if (index >= process->threadCount) { + return MACH_PORT_NULL; + } + + return process->threads[index]; +} + +bool FIRCLSProcessSuspendAllOtherThreads(FIRCLSProcess *process) { + mach_msg_type_number_t i; + bool success; + + success = true; + for (i = 0; i < process->threadCount; ++i) { + thread_t thread; + + thread = FIRCLSProcessGetThread(process, i); + + if (FIRCLSProcessIsCurrentThread(process, thread)) { + continue; + } + + // FIXME: workaround to get this building on watch, but we need to suspend/resume threads! +#if CLS_CAN_SUSPEND_THREADS + success = success && (thread_suspend(thread) == KERN_SUCCESS); +#endif + } + + return success; +} + +bool FIRCLSProcessResumeAllOtherThreads(FIRCLSProcess *process) { + mach_msg_type_number_t i; + bool success; + + success = true; + for (i = 0; i < process->threadCount; ++i) { + thread_t thread; + + thread = FIRCLSProcessGetThread(process, i); + + if (FIRCLSProcessIsCurrentThread(process, thread)) { + continue; + } + + // FIXME: workaround to get this building on watch, but we need to suspend/resume threads! +#if CLS_CAN_SUSPEND_THREADS + success = success && (thread_resume(thread) == KERN_SUCCESS); +#endif + } + + return success; +} + +#pragma mark - Thread Properties +void *FIRCLSThreadGetCurrentPC(void) { + return __builtin_return_address(0); +} + +static bool FIRCLSProcessGetThreadState(FIRCLSProcess *process, + thread_t thread, + FIRCLSThreadContext *context) { + if (!FIRCLSIsValidPointer(context)) { + FIRCLSSDKLogError("Invalid context supplied\n"); + return false; + } + + // If the thread context we should use is non-NULL, then just assign it here. Otherwise, + // query the thread state + if (FIRCLSProcessIsCrashedThread(process, thread) && FIRCLSIsValidPointer(process->uapVoid)) { + *context = *((_STRUCT_UCONTEXT *)process->uapVoid)->uc_mcontext; + return true; + } + + // Here's a wild trick: emulate what thread_get_state would do. It appears that + // we cannot reliably unwind out of thread_get_state. So, instead of trying, setup + // a thread context that resembles what the real thing would look like + if (FIRCLSProcessIsCurrentThread(process, thread)) { + FIRCLSSDKLog("Faking current thread\n"); + memset(context, 0, sizeof(FIRCLSThreadContext)); + + // Compute the frame address, and then base the stack value off of that. A frame pushes + // two pointers onto the stack, so we have to offset. + const uintptr_t frameAddress = (uintptr_t)__builtin_frame_address(0); + const uintptr_t stackAddress = FIRCLSUnwindStackPointerFromFramePointer(frameAddress); + +#if CLS_CPU_X86_64 + context->__ss.__rip = (uintptr_t)FIRCLSThreadGetCurrentPC(); + context->__ss.__rbp = frameAddress; + context->__ss.__rsp = stackAddress; +#elif CLS_CPU_I386 + context->__ss.__eip = (uintptr_t)FIRCLSThreadGetCurrentPC(); + context->__ss.__ebp = frameAddress; + context->__ss.__esp = stackAddress; +#elif CLS_CPU_ARM64 + FIRCLSThreadContextSetPC(context, (uintptr_t)FIRCLSThreadGetCurrentPC()); + FIRCLSThreadContextSetFramePointer(context, frameAddress); + FIRCLSThreadContextSetLinkRegister(context, (uintptr_t)__builtin_return_address(0)); + FIRCLSThreadContextSetStackPointer(context, stackAddress); +#elif CLS_CPU_ARM + context->__ss.__pc = (uintptr_t)FIRCLSThreadGetCurrentPC(); + context->__ss.__r[7] = frameAddress; + context->__ss.__lr = (uintptr_t)__builtin_return_address(0); + context->__ss.__sp = stackAddress; +#endif + + return true; + } + +#if !TARGET_OS_WATCH + // try to get the value by querying the thread state + mach_msg_type_number_t stateCount = FIRCLSThreadStateCount; + + // For unknown reasons, thread_get_state returns this value on Rosetta, + // but still succeeds. + const int ROSETTA_SUCCESS = 268435459; + kern_return_t status = thread_get_state(thread, FIRCLSThreadState, (thread_state_t)(&(context->__ss)), + &stateCount); + if (status != KERN_SUCCESS && status != ROSETTA_SUCCESS) { + FIRCLSSDKLogError("Failed to get thread state via thread_get_state for thread: %i\n", thread); + return false; + } + + return true; +#else + return false; +#endif +} + +static bool FIRCLSProcessGetThreadName(FIRCLSProcess *process, + thread_t thread, + char *buffer, + size_t length) { + pthread_t pthread; + + if (!buffer || length <= 0) { + return false; + } + + pthread = pthread_from_mach_thread_np(thread); + + return pthread_getname_np(pthread, buffer, length) == 0; +} + +static const char *FIRCLSProcessGetThreadDispatchQueueName(FIRCLSProcess *process, + thread_t thread) { + thread_identifier_info_data_t info; + mach_msg_type_number_t infoCount; + dispatch_queue_t *queueAddress; + dispatch_queue_t queue; + const char *string; + + infoCount = THREAD_IDENTIFIER_INFO_COUNT; + if (thread_info(thread, THREAD_IDENTIFIER_INFO, (thread_info_t)&info, &infoCount) != + KERN_SUCCESS) { + FIRCLSSDKLog("Unable to get thread info\n"); + return NULL; + } + + queueAddress = (dispatch_queue_t *)info.dispatch_qaddr; + if (queueAddress == NULL) { + return ""; + } + + // Sometimes a queue address is invalid. I cannot explain why this is, but + // it can cause a crash. + if (!FIRCLSReadMemory((vm_address_t)queueAddress, &queue, sizeof(void *))) { + return ""; + } + + // here, we know it is safe to de-reference this address, so attempt to get the queue name + if (!queue) { + return ""; + } + + string = dispatch_queue_get_label(queue); + + // but, we still don't if the entire string is valid, so check that too + if (!FIRCLSReadString((vm_address_t)string, (char **)&string, 128)) { + return ""; + } + + return string; +} + +#pragma mark - Data Recording +static bool FIRCLSProcessRecordThreadRegisters(FIRCLSThreadContext context, FIRCLSFile *file) { +#if CLS_CPU_ARM + FIRCLSFileWriteHashEntryUint64(file, "r0", context.__ss.__r[0]); + FIRCLSFileWriteHashEntryUint64(file, "r1", context.__ss.__r[1]); + FIRCLSFileWriteHashEntryUint64(file, "r2", context.__ss.__r[2]); + FIRCLSFileWriteHashEntryUint64(file, "r3", context.__ss.__r[3]); + FIRCLSFileWriteHashEntryUint64(file, "r4", context.__ss.__r[4]); + FIRCLSFileWriteHashEntryUint64(file, "r5", context.__ss.__r[5]); + FIRCLSFileWriteHashEntryUint64(file, "r6", context.__ss.__r[6]); + FIRCLSFileWriteHashEntryUint64(file, "r7", context.__ss.__r[7]); + FIRCLSFileWriteHashEntryUint64(file, "r8", context.__ss.__r[8]); + FIRCLSFileWriteHashEntryUint64(file, "r9", context.__ss.__r[9]); + FIRCLSFileWriteHashEntryUint64(file, "r10", context.__ss.__r[10]); + FIRCLSFileWriteHashEntryUint64(file, "r11", context.__ss.__r[11]); + FIRCLSFileWriteHashEntryUint64(file, "ip", context.__ss.__r[12]); + FIRCLSFileWriteHashEntryUint64(file, "sp", context.__ss.__sp); + FIRCLSFileWriteHashEntryUint64(file, "lr", context.__ss.__lr); + FIRCLSFileWriteHashEntryUint64(file, "pc", context.__ss.__pc); + FIRCLSFileWriteHashEntryUint64(file, "cpsr", context.__ss.__cpsr); +#elif CLS_CPU_ARM64 + FIRCLSFileWriteHashEntryUint64(file, "x0", context.__ss.__x[0]); + FIRCLSFileWriteHashEntryUint64(file, "x1", context.__ss.__x[1]); + FIRCLSFileWriteHashEntryUint64(file, "x2", context.__ss.__x[2]); + FIRCLSFileWriteHashEntryUint64(file, "x3", context.__ss.__x[3]); + FIRCLSFileWriteHashEntryUint64(file, "x4", context.__ss.__x[4]); + FIRCLSFileWriteHashEntryUint64(file, "x5", context.__ss.__x[5]); + FIRCLSFileWriteHashEntryUint64(file, "x6", context.__ss.__x[6]); + FIRCLSFileWriteHashEntryUint64(file, "x7", context.__ss.__x[7]); + FIRCLSFileWriteHashEntryUint64(file, "x8", context.__ss.__x[8]); + FIRCLSFileWriteHashEntryUint64(file, "x9", context.__ss.__x[9]); + FIRCLSFileWriteHashEntryUint64(file, "x10", context.__ss.__x[10]); + FIRCLSFileWriteHashEntryUint64(file, "x11", context.__ss.__x[11]); + FIRCLSFileWriteHashEntryUint64(file, "x12", context.__ss.__x[12]); + FIRCLSFileWriteHashEntryUint64(file, "x13", context.__ss.__x[13]); + FIRCLSFileWriteHashEntryUint64(file, "x14", context.__ss.__x[14]); + FIRCLSFileWriteHashEntryUint64(file, "x15", context.__ss.__x[15]); + FIRCLSFileWriteHashEntryUint64(file, "x16", context.__ss.__x[16]); + FIRCLSFileWriteHashEntryUint64(file, "x17", context.__ss.__x[17]); + FIRCLSFileWriteHashEntryUint64(file, "x18", context.__ss.__x[18]); + FIRCLSFileWriteHashEntryUint64(file, "x19", context.__ss.__x[19]); + FIRCLSFileWriteHashEntryUint64(file, "x20", context.__ss.__x[20]); + FIRCLSFileWriteHashEntryUint64(file, "x21", context.__ss.__x[21]); + FIRCLSFileWriteHashEntryUint64(file, "x22", context.__ss.__x[22]); + FIRCLSFileWriteHashEntryUint64(file, "x23", context.__ss.__x[23]); + FIRCLSFileWriteHashEntryUint64(file, "x24", context.__ss.__x[24]); + FIRCLSFileWriteHashEntryUint64(file, "x25", context.__ss.__x[25]); + FIRCLSFileWriteHashEntryUint64(file, "x26", context.__ss.__x[26]); + FIRCLSFileWriteHashEntryUint64(file, "x27", context.__ss.__x[27]); + FIRCLSFileWriteHashEntryUint64(file, "x28", context.__ss.__x[28]); + FIRCLSFileWriteHashEntryUint64(file, "fp", FIRCLSThreadContextGetFramePointer(&context)); + FIRCLSFileWriteHashEntryUint64(file, "sp", FIRCLSThreadContextGetStackPointer(&context)); + FIRCLSFileWriteHashEntryUint64(file, "lr", FIRCLSThreadContextGetLinkRegister(&context)); + FIRCLSFileWriteHashEntryUint64(file, "pc", FIRCLSThreadContextGetPC(&context)); + FIRCLSFileWriteHashEntryUint64(file, "cpsr", context.__ss.__cpsr); +#elif CLS_CPU_I386 + FIRCLSFileWriteHashEntryUint64(file, "eax", context.__ss.__eax); + FIRCLSFileWriteHashEntryUint64(file, "ebx", context.__ss.__ebx); + FIRCLSFileWriteHashEntryUint64(file, "ecx", context.__ss.__ecx); + FIRCLSFileWriteHashEntryUint64(file, "edx", context.__ss.__edx); + FIRCLSFileWriteHashEntryUint64(file, "edi", context.__ss.__edi); + FIRCLSFileWriteHashEntryUint64(file, "esi", context.__ss.__esi); + FIRCLSFileWriteHashEntryUint64(file, "ebp", context.__ss.__ebp); + FIRCLSFileWriteHashEntryUint64(file, "esp", context.__ss.__esp); + FIRCLSFileWriteHashEntryUint64(file, "ss", context.__ss.__ss); + FIRCLSFileWriteHashEntryUint64(file, "eflags", context.__ss.__eflags); + FIRCLSFileWriteHashEntryUint64(file, "eip", context.__ss.__eip); + FIRCLSFileWriteHashEntryUint64(file, "cs", context.__ss.__cs); + FIRCLSFileWriteHashEntryUint64(file, "ds", context.__ss.__ds); + FIRCLSFileWriteHashEntryUint64(file, "es", context.__ss.__es); + FIRCLSFileWriteHashEntryUint64(file, "fs", context.__ss.__fs); + FIRCLSFileWriteHashEntryUint64(file, "gs", context.__ss.__gs); + + // how do we get the cr2 register? +#elif CLS_CPU_X86_64 + FIRCLSFileWriteHashEntryUint64(file, "rax", context.__ss.__rax); + FIRCLSFileWriteHashEntryUint64(file, "rbx", context.__ss.__rbx); + FIRCLSFileWriteHashEntryUint64(file, "rcx", context.__ss.__rcx); + FIRCLSFileWriteHashEntryUint64(file, "rdx", context.__ss.__rdx); + FIRCLSFileWriteHashEntryUint64(file, "rdi", context.__ss.__rdi); + FIRCLSFileWriteHashEntryUint64(file, "rsi", context.__ss.__rsi); + FIRCLSFileWriteHashEntryUint64(file, "rbp", context.__ss.__rbp); + FIRCLSFileWriteHashEntryUint64(file, "rsp", context.__ss.__rsp); + FIRCLSFileWriteHashEntryUint64(file, "r8", context.__ss.__r8); + FIRCLSFileWriteHashEntryUint64(file, "r9", context.__ss.__r9); + FIRCLSFileWriteHashEntryUint64(file, "r10", context.__ss.__r10); + FIRCLSFileWriteHashEntryUint64(file, "r11", context.__ss.__r11); + FIRCLSFileWriteHashEntryUint64(file, "r12", context.__ss.__r12); + FIRCLSFileWriteHashEntryUint64(file, "r13", context.__ss.__r13); + FIRCLSFileWriteHashEntryUint64(file, "r14", context.__ss.__r14); + FIRCLSFileWriteHashEntryUint64(file, "r15", context.__ss.__r15); + FIRCLSFileWriteHashEntryUint64(file, "rip", context.__ss.__rip); + FIRCLSFileWriteHashEntryUint64(file, "rflags", context.__ss.__rflags); + FIRCLSFileWriteHashEntryUint64(file, "cs", context.__ss.__cs); + FIRCLSFileWriteHashEntryUint64(file, "fs", context.__ss.__fs); + FIRCLSFileWriteHashEntryUint64(file, "gs", context.__ss.__gs); +#endif + + return true; +} + +static bool FIRCLSProcessRecordThread(FIRCLSProcess *process, thread_t thread, FIRCLSFile *file) { + FIRCLSUnwindContext unwindContext; + FIRCLSThreadContext context; + + if (!FIRCLSProcessGetThreadState(process, thread, &context)) { + FIRCLSSDKLogError("Unable to get thread state\n"); + return false; + } + + if (!FIRCLSUnwindInit(&unwindContext, context)) { + FIRCLSSDKLog("Unable to init unwind context\n"); + + return false; + } + + FIRCLSFileWriteHashStart(file); + + // registers + FIRCLSFileWriteHashKey(file, "registers"); + FIRCLSFileWriteHashStart(file); + + FIRCLSProcessRecordThreadRegisters(context, file); + + FIRCLSFileWriteHashEnd(file); + + // stacktrace + FIRCLSFileWriteHashKey(file, "stacktrace"); + + // stacktrace is an array of integers + FIRCLSFileWriteArrayStart(file); + + uint32_t repeatedPCCount = 0; + uint64_t repeatedPC = 0; + const FIRCLSInternalLogLevel level = _firclsContext.writable->internalLogging.logLevel; + + while (FIRCLSUnwindNextFrame(&unwindContext)) { + const uintptr_t pc = FIRCLSUnwindGetPC(&unwindContext); + const uint32_t frameCount = FIRCLSUnwindGetFrameRepeatCount(&unwindContext); + + if (repeatedPC == pc && repeatedPC != 0) { + // actively counting a recursion + repeatedPCCount = frameCount; + continue; + } + + if (frameCount >= FIRCLSUnwindInfiniteRecursionCountThreshold && repeatedPC == 0) { + repeatedPC = pc; + FIRCLSSDKLogWarn("Possible infinite recursion - suppressing logging\n"); + _firclsContext.writable->internalLogging.logLevel = FIRCLSInternalLogLevelWarn; + continue; + } + + if (repeatedPC != 0) { + // at this point, we've recorded a repeated PC, but it is now no longer + // repeating, so we can restore the logging + _firclsContext.writable->internalLogging.logLevel = level; + } + + FIRCLSFileWriteArrayEntryUint64(file, pc); + } + + FIRCLSFileWriteArrayEnd(file); + + // crashed? + if (FIRCLSProcessIsCrashedThread(process, thread)) { + FIRCLSFileWriteHashEntryBoolean(file, "crashed", true); + } + + if (repeatedPC != 0) { + FIRCLSFileWriteHashEntryUint64(file, "repeated_pc", repeatedPC); + FIRCLSFileWriteHashEntryUint64(file, "repeat_count", repeatedPCCount); + } + + // Just for extra safety, restore the logging level again. The logic + // above is fairly tricky, this is cheap, and no logging is a real pain. + _firclsContext.writable->internalLogging.logLevel = level; + + // end thread info + FIRCLSFileWriteHashEnd(file); + + return true; +} + +bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file) { + uint32_t threadCount; + uint32_t i; + + threadCount = FIRCLSProcessGetThreadCount(process); + + FIRCLSFileWriteSectionStart(file, "threads"); + + FIRCLSFileWriteArrayStart(file); + + for (i = 0; i < threadCount; ++i) { + thread_t thread; + + thread = FIRCLSProcessGetThread(process, i); + + FIRCLSSDKLogInfo("recording thread %d data\n", i); + if (!FIRCLSProcessRecordThread(process, thread, file)) { + FIRCLSSDKLogError("Failed to record thread state. Closing threads JSON to prevent malformed crash report.\n"); + + FIRCLSFileWriteArrayEnd(file); + + FIRCLSFileWriteSectionEnd(file); + return false; + } + } + + FIRCLSFileWriteArrayEnd(file); + + FIRCLSFileWriteSectionEnd(file); + + FIRCLSSDKLogInfo("Completed recording all thread data\n"); + + return true; +} + +void FIRCLSProcessRecordThreadNames(FIRCLSProcess *process, FIRCLSFile *file) { + uint32_t threadCount; + uint32_t i; + + FIRCLSFileWriteSectionStart(file, "thread_names"); + + FIRCLSFileWriteArrayStart(file); + + threadCount = FIRCLSProcessGetThreadCount(process); + for (i = 0; i < threadCount; ++i) { + thread_t thread; + char name[THREAD_NAME_BUFFER_SIZE]; + + thread = FIRCLSProcessGetThread(process, i); + + name[0] = 0; // null-terminate, just in case nothing is written + + FIRCLSProcessGetThreadName(process, thread, name, THREAD_NAME_BUFFER_SIZE); + + FIRCLSFileWriteArrayEntryString(file, name); + } + + FIRCLSFileWriteArrayEnd(file); + FIRCLSFileWriteSectionEnd(file); +} + +void FIRCLSProcessRecordDispatchQueueNames(FIRCLSProcess *process, FIRCLSFile *file) { + uint32_t threadCount; + uint32_t i; + + FIRCLSFileWriteSectionStart(file, "dispatch_queue_names"); + + FIRCLSFileWriteArrayStart(file); + + threadCount = FIRCLSProcessGetThreadCount(process); + for (i = 0; i < threadCount; ++i) { + thread_t thread; + const char *name; + + thread = FIRCLSProcessGetThread(process, i); + + name = FIRCLSProcessGetThreadDispatchQueueName(process, thread); + + // Apple Report Converter will fail to parse this when "name" is null, + // so we will use an empty string instead. + if (name == NULL) { + name = ""; + } + FIRCLSFileWriteArrayEntryString(file, name); + } + + FIRCLSFileWriteArrayEnd(file); + FIRCLSFileWriteSectionEnd(file); +} + +#pragma mark - Other Process Info +bool FIRCLSProcessGetMemoryUsage(uint64_t *active, + uint64_t *inactive, + uint64_t *wired, + uint64_t *freeMem) { + mach_port_t hostPort; + mach_msg_type_number_t hostSize; + vm_size_t pageSize; + vm_statistics_data_t vmStat; + + hostPort = mach_host_self(); + + hostSize = sizeof(vm_statistics_data_t) / sizeof(integer_t); + + pageSize = _firclsContext.readonly->host.pageSize; + + if (host_statistics(hostPort, HOST_VM_INFO, (host_info_t)&vmStat, &hostSize) != KERN_SUCCESS) { + FIRCLSSDKLog("Failed to get vm statistics\n"); + return false; + } + + if (!(active && inactive && wired && freeMem)) { + FIRCLSSDKLog("Invalid pointers\n"); + return false; + } + + // compute the sizes in bytes and return the values + *active = vmStat.active_count * pageSize; + *inactive = vmStat.inactive_count * pageSize; + *wired = vmStat.wire_count * pageSize; + *freeMem = vmStat.free_count * pageSize; + + return true; +} + +bool FIRCLSProcessGetInfo(FIRCLSProcess *process, + uint64_t *virtualSize, + uint64_t *residentSize, + time_value_t *userTime, + time_value_t *systemTime) { + struct task_basic_info_64 taskInfo; + mach_msg_type_number_t count; + + count = TASK_BASIC_INFO_64_COUNT; + if (task_info(process->task, TASK_BASIC_INFO_64, (task_info_t)&taskInfo, &count) != + KERN_SUCCESS) { + FIRCLSSDKLog("Failed to get task info\n"); + return false; + } + + if (!(virtualSize && residentSize && userTime && systemTime)) { + FIRCLSSDKLog("Invalid pointers\n"); + return false; + } + + *virtualSize = taskInfo.virtual_size; + *residentSize = taskInfo.resident_size; + *userTime = taskInfo.user_time; + *systemTime = taskInfo.system_time; + + return true; +} + +void FIRCLSProcessRecordStats(FIRCLSProcess *process, FIRCLSFile *file) { + uint64_t active; + uint64_t inactive; + uint64_t virtualSize; + uint64_t residentSize; + uint64_t wired; + uint64_t freeMem; + time_value_t userTime; + time_value_t systemTime; + + if (!FIRCLSProcessGetMemoryUsage(&active, &inactive, &wired, &freeMem)) { + FIRCLSSDKLog("Unable to get process memory usage\n"); + return; + } + + if (!FIRCLSProcessGetInfo(process, &virtualSize, &residentSize, &userTime, &systemTime)) { + FIRCLSSDKLog("Unable to get process stats\n"); + return; + } + + FIRCLSFileWriteSectionStart(file, "process_stats"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryUint64(file, "active", active); + FIRCLSFileWriteHashEntryUint64(file, "inactive", inactive); + FIRCLSFileWriteHashEntryUint64(file, "wired", wired); + FIRCLSFileWriteHashEntryUint64(file, "freeMem", freeMem); // Intentionally left in, for now. Arg. + FIRCLSFileWriteHashEntryUint64(file, "free_mem", freeMem); + FIRCLSFileWriteHashEntryUint64(file, "virtual", virtualSize); + FIRCLSFileWriteHashEntryUint64(file, "resident", active); + FIRCLSFileWriteHashEntryUint64(file, "user_time", + (userTime.seconds * 1000 * 1000) + userTime.microseconds); + FIRCLSFileWriteHashEntryUint64(file, "sys_time", + (systemTime.seconds * 1000 * 1000) + systemTime.microseconds); + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); +} + +#pragma mark - Runtime Info +#define OBJC_MSG_SEND_START ((vm_address_t)objc_msgSend) +#define OBJC_MSG_SEND_SUPER_START ((vm_address_t)objc_msgSendSuper) +#define OBJC_MSG_SEND_END (OBJC_MSG_SEND_START + 66) +#define OBJC_MSG_SEND_SUPER_END (OBJC_MSG_SEND_SUPER_START + 66) + +#if !CLS_CPU_ARM64 +#define OBJC_MSG_SEND_STRET_START ((vm_address_t)objc_msgSend_stret) +#define OBJC_MSG_SEND_SUPER_STRET_START ((vm_address_t)objc_msgSendSuper_stret) +#define OBJC_MSG_SEND_STRET_END (OBJC_MSG_SEND_STRET_START + 66) +#define OBJC_MSG_SEND_SUPER_STRET_END (OBJC_MSG_SEND_SUPER_STRET_START + 66) +#endif + +#if CLS_CPU_X86 +#define OBJC_MSG_SEND_FPRET_START ((vm_address_t)objc_msgSend_fpret) +#define OBJC_MSG_SEND_FPRET_END (OBJC_MSG_SEND_FPRET_START + 66) +#endif + +static const char *FIRCLSProcessGetObjCSelectorName(FIRCLSThreadContext registers) { + void *selectorAddress; + void *selRegister; +#if !CLS_CPU_ARM64 + void *stretSelRegister; +#endif + vm_address_t pc; + + // First, did we crash in objc_msgSend? The two ways I can think + // of doing this are to use dladdr, and then comparing the strings to + // objc_msg*, or looking up the symbols, and guessing if we are "close enough". + + selectorAddress = NULL; + +#if CLS_CPU_ARM + pc = registers.__ss.__pc; + selRegister = (void *)registers.__ss.__r[1]; + stretSelRegister = (void *)registers.__ss.__r[2]; +#elif CLS_CPU_ARM64 + pc = FIRCLSThreadContextGetPC(®isters); + selRegister = (void *)registers.__ss.__x[1]; +#elif CLS_CPU_I386 + pc = registers.__ss.__eip; + selRegister = (void *)registers.__ss.__ecx; + stretSelRegister = (void *)registers.__ss.__ecx; +#elif CLS_CPU_X86_64 + pc = registers.__ss.__rip; + selRegister = (void *)registers.__ss.__rsi; + stretSelRegister = (void *)registers.__ss.__rdx; +#endif + + if ((pc >= OBJC_MSG_SEND_START) && (pc <= OBJC_MSG_SEND_END)) { + selectorAddress = selRegister; + } + +#if !CLS_CPU_ARM64 + if ((pc >= OBJC_MSG_SEND_SUPER_START) && (pc <= OBJC_MSG_SEND_SUPER_END)) { + selectorAddress = selRegister; + } + + if ((pc >= OBJC_MSG_SEND_STRET_START) && (pc <= OBJC_MSG_SEND_STRET_END)) { + selectorAddress = stretSelRegister; + } + + if ((pc >= OBJC_MSG_SEND_SUPER_STRET_START) && (pc <= OBJC_MSG_SEND_SUPER_STRET_END)) { + selectorAddress = stretSelRegister; + } + +#if CLS_CPU_X86 + if ((pc >= OBJC_MSG_SEND_FPRET_START) && (pc <= OBJC_MSG_SEND_FPRET_END)) { + selectorAddress = selRegister; + } +#endif +#endif + + if (!selectorAddress) { + return ""; + } + + if (!FIRCLSReadString((vm_address_t)selectorAddress, (char **)&selectorAddress, 128)) { + FIRCLSSDKLog("Unable to read the selector string\n"); + return ""; + } + + return selectorAddress; +} + +#define CRASH_ALIGN __attribute__((aligned(8))) +typedef struct { + unsigned version CRASH_ALIGN; + const char *message CRASH_ALIGN; + const char *signature CRASH_ALIGN; + const char *backtrace CRASH_ALIGN; + const char *message2 CRASH_ALIGN; + void *reserved CRASH_ALIGN; + void *reserved2 CRASH_ALIGN; +} crash_info_t; + +static void FIRCLSProcessRecordCrashInfo(FIRCLSFile *file) { + // TODO: this should be abstracted into binary images, if possible + FIRCLSBinaryImageRuntimeNode *nodes = _firclsContext.writable->binaryImage.nodes; + if (!nodes) { + FIRCLSSDKLogError("The node structure is NULL\n"); + return; + } + + for (uint32_t i = 0; i < CLS_BINARY_IMAGE_RUNTIME_NODE_COUNT; ++i) { + FIRCLSBinaryImageRuntimeNode *node = &nodes[i]; + + if (!node->crashInfo) { + continue; + } + + crash_info_t info; + + if (!FIRCLSReadMemory((vm_address_t)node->crashInfo, &info, sizeof(crash_info_t))) { + continue; + } + + FIRCLSSDKLogDebug("Found crash info with version %d\n", info.version); + + // Currently support versions 0 through 5. + // 4 was in use for a long time, but it appears that with iOS 9 / swift 2.0, the version has + // been bumped. + if (info.version > 5) { + continue; + } + + if (!info.message) { + continue; + } + +#if CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME + FIRCLSSDKLogInfo("Found crash info for %s\n", node->name); +#endif + + FIRCLSSDKLogDebug("attempting to read crash info string\n"); + + char *string = NULL; + + if (!FIRCLSReadString((vm_address_t)info.message, &string, 256)) { + FIRCLSSDKLogError("Failed to copy crash info string\n"); + continue; + } + + // The crash_info_t's message may contain the device's UDID, in this case, + // make sure that we do our best to redact that information before writing the + // rest of the message to disk. This also has the effect of not uploading that + // information in the subsequent crash report. + FIRCLSRedactUUID(string); + + FIRCLSFileWriteArrayEntryHexEncodedString(file, string); + } +} + +void FIRCLSProcessRecordRuntimeInfo(FIRCLSProcess *process, FIRCLSFile *file) { + FIRCLSThreadContext mcontext; + + if (!FIRCLSProcessGetThreadState(process, process->crashedThread, &mcontext)) { + FIRCLSSDKLogError("unable to get crashed thread state"); + } + + FIRCLSFileWriteSectionStart(file, "runtime"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryString(file, "objc_selector", FIRCLSProcessGetObjCSelectorName(mcontext)); + + FIRCLSFileWriteHashKey(file, "crash_info_entries"); + + FIRCLSFileWriteArrayStart(file); + FIRCLSProcessRecordCrashInfo(file); + FIRCLSFileWriteArrayEnd(file); + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.h new file mode 100644 index 0000000..165f0c8 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSProcess.h @@ -0,0 +1,44 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +typedef struct { + // task info + mach_port_t task; + + // thread stuff + thread_t thisThread; + thread_t crashedThread; + thread_act_array_t threads; + mach_msg_type_number_t threadCount; + void *uapVoid; // current thread state +} FIRCLSProcess; + +bool FIRCLSProcessInit(FIRCLSProcess *process, thread_t crashedThread, void *uapVoid); +bool FIRCLSProcessDebuggerAttached(void); + +bool FIRCLSProcessSuspendAllOtherThreads(FIRCLSProcess *process); +bool FIRCLSProcessResumeAllOtherThreads(FIRCLSProcess *process); + +void FIRCLSProcessRecordThreadNames(FIRCLSProcess *process, FIRCLSFile *file); +void FIRCLSProcessRecordDispatchQueueNames(FIRCLSProcess *process, FIRCLSFile *file); +bool FIRCLSProcessRecordAllThreads(FIRCLSProcess *process, FIRCLSFile *file); +void FIRCLSProcessRecordStats(FIRCLSProcess *process, FIRCLSFile *file); +void FIRCLSProcessRecordRuntimeInfo(FIRCLSProcess *process, FIRCLSFile *file); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h new file mode 100644 index 0000000..0b2aa39 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h @@ -0,0 +1,115 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +__BEGIN_DECLS + +#ifdef __OBJC__ +extern NSString* const FIRCLSStartTimeKey; +extern NSString* const FIRCLSFirstRunloopTurnTimeKey; +extern NSString* const FIRCLSInBackgroundKey; +#if TARGET_OS_IPHONE +extern NSString* const FIRCLSDeviceOrientationKey; +extern NSString* const FIRCLSUIOrientationKey; +#endif +extern NSString* const FIRCLSUserIdentifierKey; +extern NSString* const FIRCLSUserNameKey; +extern NSString* const FIRCLSUserEmailKey; +extern NSString* const FIRCLSDevelopmentPlatformNameKey; +extern NSString* const FIRCLSDevelopmentPlatformVersionKey; +extern NSString* const FIRCLSOnDemandRecordedExceptionsKey; +extern NSString* const FIRCLSOnDemandDroppedExceptionsKey; +#endif + +extern const uint32_t FIRCLSUserLoggingMaxKVEntries; + +typedef struct { + const char* incrementalPath; + const char* compactedPath; + + uint32_t maxIncrementalCount; + uint32_t maxCount; +} FIRCLSUserLoggingKVStorage; + +typedef struct { + const char* aPath; + const char* bPath; + uint32_t maxSize; + uint32_t maxEntries; + bool restrictBySize; + uint32_t* entryCount; +} FIRCLSUserLoggingABStorage; + +typedef struct { + FIRCLSUserLoggingKVStorage userKVStorage; + FIRCLSUserLoggingKVStorage internalKVStorage; + + FIRCLSUserLoggingABStorage logStorage; + FIRCLSUserLoggingABStorage errorStorage; + FIRCLSUserLoggingABStorage customExceptionStorage; +} FIRCLSUserLoggingReadOnlyContext; + +typedef struct { + const char* activeUserLogPath; + const char* activeErrorLogPath; + const char* activeCustomExceptionPath; + uint32_t userKVCount; + uint32_t internalKVCount; + uint32_t errorsCount; +} FIRCLSUserLoggingWritableContext; + +void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext* roContext, + FIRCLSUserLoggingWritableContext* rwContext); + +#ifdef __OBJC__ +void FIRCLSUserLoggingRecordUserKeyValue(NSString* key, id value); +void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary* keysAndValues); +void FIRCLSUserLoggingRecordInternalKeyValue(NSString* key, id value); +void FIRCLSUserLoggingWriteInternalKeyValue(NSString* key, NSString* value); + +void FIRCLSUserLoggingRecordError(NSError* error, + NSDictionary* additionalUserInfo, + NSString* rolloutsInfoJSON); + +NSDictionary* FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage* storage, + bool decodeHex); +void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage* storage); + +void FIRCLSUserLoggingRecordKeyValue(NSString* key, + id value, + FIRCLSUserLoggingKVStorage* storage, + uint32_t* counter); + +void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary* keysAndValues, + FIRCLSUserLoggingKVStorage* storage, + uint32_t* counter); + +void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage* storage, + const char** activePath, + void (^openedFileBlock)(FIRCLSFile* file)); + +NSArray* FIRCLSUserLoggingStoredKeyValues(const char* path); + +OBJC_EXTERN void FIRCLSLog(NSString* format, ...) NS_FORMAT_FUNCTION(1, 2); +OBJC_EXTERN void FIRCLSLogToStorage(FIRCLSUserLoggingABStorage* storage, + const char** activePath, + NSString* format, + ...) NS_FORMAT_FUNCTION(3, 4); + +#endif + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m new file mode 100644 index 0000000..4da93b4 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Components/FIRCLSUserLogging.m @@ -0,0 +1,612 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" + +#include + +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h" + +NSString *const FIRCLSStartTimeKey = @"com.crashlytics.kit-start-time"; +NSString *const FIRCLSFirstRunloopTurnTimeKey = @"com.crashlytics.first-run-loop-time"; +NSString *const FIRCLSInBackgroundKey = @"com.crashlytics.in-background"; +#if TARGET_OS_IPHONE +NSString *const FIRCLSDeviceOrientationKey = @"com.crashlytics.device-orientation"; +NSString *const FIRCLSUIOrientationKey = @"com.crashlytics.ui-orientation"; +#endif +NSString *const FIRCLSUserIdentifierKey = @"com.crashlytics.user-id"; +NSString *const FIRCLSDevelopmentPlatformNameKey = @"com.crashlytics.development-platform-name"; +NSString *const FIRCLSDevelopmentPlatformVersionKey = + @"com.crashlytics.development-platform-version"; +NSString *const FIRCLSOnDemandRecordedExceptionsKey = + @"com.crashlytics.on-demand.recorded-exceptions"; +NSString *const FIRCLSOnDemandDroppedExceptionsKey = + @"com.crashlytics.on-demand.dropped-exceptions"; + +// Empty string object synchronized on to prevent a race condition when accessing AB file path +NSString *const FIRCLSSynchronizedPathKey = @""; + +const uint32_t FIRCLSUserLoggingMaxKVEntries = 64; + +#pragma mark - Prototypes +static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues, + FIRCLSUserLoggingKVStorage *storage, + uint32_t *counter, + BOOL containsNullValue); +static void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + off_t fileSize); +void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + NSString *message); + +#pragma mark - Setup +void FIRCLSUserLoggingInit(FIRCLSUserLoggingReadOnlyContext *roContext, + FIRCLSUserLoggingWritableContext *rwContext) { + rwContext->activeUserLogPath = roContext->logStorage.aPath; + rwContext->activeErrorLogPath = roContext->errorStorage.aPath; + rwContext->activeCustomExceptionPath = roContext->customExceptionStorage.aPath; + + rwContext->userKVCount = 0; + rwContext->internalKVCount = 0; + rwContext->errorsCount = 0; + + roContext->userKVStorage.maxIncrementalCount = FIRCLSUserLoggingMaxKVEntries; + roContext->internalKVStorage.maxIncrementalCount = roContext->userKVStorage.maxIncrementalCount; +} + +#pragma mark - KV Logging +void FIRCLSUserLoggingRecordInternalKeyValue(NSString *key, id value) { + FIRCLSUserLoggingRecordKeyValue(key, value, &_firclsContext.readonly->logging.internalKVStorage, + &_firclsContext.writable->logging.internalKVCount); +} + +void FIRCLSUserLoggingWriteInternalKeyValue(NSString *key, NSString *value) { + // Unsynchronized - must be run on the correct queue + NSDictionary *keysAndValues = key ? @{key : value ?: [NSNull null]} : nil; + FIRCLSUserLoggingWriteKeysAndValues(keysAndValues, + &_firclsContext.readonly->logging.internalKVStorage, + &_firclsContext.writable->logging.internalKVCount, NO); +} + +void FIRCLSUserLoggingRecordUserKeyValue(NSString *key, id value) { + FIRCLSUserLoggingRecordKeyValue(key, value, &_firclsContext.readonly->logging.userKVStorage, + &_firclsContext.writable->logging.userKVCount); +} + +void FIRCLSUserLoggingRecordUserKeysAndValues(NSDictionary *keysAndValues) { + FIRCLSUserLoggingRecordKeysAndValues(keysAndValues, + &_firclsContext.readonly->logging.userKVStorage, + &_firclsContext.writable->logging.userKVCount); +} + +static id FIRCLSUserLoggingGetComponent(NSDictionary *entry, + NSString *componentName, + bool decodeHex) { + id value = [entry objectForKey:componentName]; + + return (decodeHex && value != [NSNull null]) ? FIRCLSFileHexDecodeString([value UTF8String]) + : value; +} + +static NSString *FIRCLSUserLoggingGetKey(NSDictionary *entry, bool decodeHex) { + return FIRCLSUserLoggingGetComponent(entry, @"key", decodeHex); +} + +static id FIRCLSUserLoggingGetValue(NSDictionary *entry, bool decodeHex) { + return FIRCLSUserLoggingGetComponent(entry, @"value", decodeHex); +} + +NSDictionary *FIRCLSUserLoggingGetCompactedKVEntries(FIRCLSUserLoggingKVStorage *storage, + bool decodeHex) { + if (!FIRCLSIsValidPointer(storage)) { + FIRCLSSDKLogError("storage invalid\n"); + return nil; + } + + NSArray *incrementalKVs = FIRCLSUserLoggingStoredKeyValues(storage->incrementalPath); + NSArray *compactedKVs = FIRCLSUserLoggingStoredKeyValues(storage->compactedPath); + + NSMutableDictionary *finalKVSet = [NSMutableDictionary new]; + + // These should all be unique, so there might be a more efficient way to + // do this + for (NSDictionary *entry in compactedKVs) { + NSString *key = FIRCLSUserLoggingGetKey(entry, decodeHex); + NSString *value = FIRCLSUserLoggingGetValue(entry, decodeHex); + + if (!key || !value) { + FIRCLSSDKLogError("compacted key/value contains a nil and must be dropped\n"); + continue; + } + + [finalKVSet setObject:value forKey:key]; + } + + // Now, assign the incremental values, in file order, so we overwrite any older values. + for (NSDictionary *entry in incrementalKVs) { + NSString *key = FIRCLSUserLoggingGetKey(entry, decodeHex); + NSString *value = FIRCLSUserLoggingGetValue(entry, decodeHex); + + if (!key || !value) { + FIRCLSSDKLogError("incremental key/value contains a nil and must be dropped\n"); + continue; + } + + if ([value isEqual:[NSNull null]]) { + [finalKVSet removeObjectForKey:key]; + } else { + [finalKVSet setObject:value forKey:key]; + } + } + + return finalKVSet; +} + +static void FIRCLSUserLoggingWriteKVEntriesToFile( + NSDictionary *keysAndValues, BOOL shouldHexEncode, FIRCLSFile *file) { + for (NSString *key in keysAndValues) { + NSString *valueObject = [keysAndValues objectForKey:key]; + + // map `NSNull` into nil + const char *value = (valueObject == (NSString *)[NSNull null] ? nil : [valueObject UTF8String]); + + FIRCLSFileWriteSectionStart(file, "kv"); + FIRCLSFileWriteHashStart(file); + + if (shouldHexEncode) { + FIRCLSFileWriteHashEntryHexEncodedString(file, "key", [key UTF8String]); + FIRCLSFileWriteHashEntryHexEncodedString(file, "value", value); + } else { + FIRCLSFileWriteHashEntryString(file, "key", [key UTF8String]); + FIRCLSFileWriteHashEntryString(file, "value", value); + } + + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); + } +} + +void FIRCLSUserLoggingCompactKVEntries(FIRCLSUserLoggingKVStorage *storage) { + if (!FIRCLSIsValidPointer(storage)) { + FIRCLSSDKLogError("Error: storage invalid\n"); + return; + } + + NSDictionary *finalKVs = FIRCLSUserLoggingGetCompactedKVEntries(storage, false); + + if (unlink(storage->compactedPath) != 0) { + FIRCLSSDKLog("Error: Unable to remove compacted KV store before compaction %s\n", + strerror(errno)); + } + + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, storage->compactedPath, true)) { + FIRCLSSDKLog("Error: Unable to open compacted k-v file\n"); + return; + } + + uint32_t maxCount = storage->maxCount; + if ([finalKVs count] > maxCount) { + // We need to remove keys, to avoid going over the max. + // This is just about the worst way to go about doing this. There are lots of smarter ways, + // but it's very uncommon to go down this path. + NSArray *keys = [finalKVs allKeys]; + + FIRCLSSDKLogInfo("Truncating %d keys from KV set, which is above max %d\n", + (uint32_t)(finalKVs.count - maxCount), maxCount); + + finalKVs = + [finalKVs dictionaryWithValuesForKeys:[keys subarrayWithRange:NSMakeRange(0, maxCount)]]; + } + + FIRCLSUserLoggingWriteKVEntriesToFile(finalKVs, false, &file); + FIRCLSFileClose(&file); + + if (unlink(storage->incrementalPath) != 0) { + FIRCLSSDKLog("Error: Unable to remove incremental KV store after compaction %s\n", + strerror(errno)); + } +} + +void FIRCLSUserLoggingRecordKeyValue(NSString *key, + id value, + FIRCLSUserLoggingKVStorage *storage, + uint32_t *counter) { + if (!FIRCLSIsValidPointer(key)) { + FIRCLSSDKLogWarn("User provided bad key\n"); + return; + } + + NSDictionary *keysAndValues = @{key : (value ?: [NSNull null])}; + FIRCLSUserLoggingRecordKeysAndValues(keysAndValues, storage, counter); +} + +void FIRCLSUserLoggingRecordKeysAndValues(NSDictionary *keysAndValues, + FIRCLSUserLoggingKVStorage *storage, + uint32_t *counter) { + if (!FIRCLSContextIsInitialized()) { + return; + } + + if (keysAndValues.count == 0) { + FIRCLSSDKLogWarn("User provided empty key/value dictionary\n"); + return; + } + + if (!FIRCLSIsValidPointer(keysAndValues)) { + FIRCLSSDKLogWarn("User provided bad key/value dictionary\n"); + return; + } + + NSMutableDictionary *sanitizedKeysAndValues = [keysAndValues mutableCopy]; + BOOL containsNullValue = NO; + + for (NSString *key in keysAndValues) { + if (!FIRCLSIsValidPointer(key)) { + FIRCLSSDKLogWarn("User provided bad key\n"); + return; + } + + id value = keysAndValues[key]; + + // ensure that any invalid pointer is actually set to nil + if (!FIRCLSIsValidPointer(value) && value != nil) { + FIRCLSSDKLogWarn("Bad value pointer being clamped to nil\n"); + sanitizedKeysAndValues[key] = [NSNull null]; + } + + if ([value respondsToSelector:@selector(description)] && ![value isEqual:[NSNull null]]) { + sanitizedKeysAndValues[key] = [value description]; + } else { + // passing nil will result in a JSON null being written, which is deserialized as [NSNull + // null], signaling to remove the key during compaction + sanitizedKeysAndValues[key] = [NSNull null]; + containsNullValue = YES; + } + } + + dispatch_sync(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingWriteKeysAndValues(sanitizedKeysAndValues, storage, counter, + containsNullValue); + }); +} + +static void FIRCLSUserLoggingWriteKeysAndValues(NSDictionary *keysAndValues, + FIRCLSUserLoggingKVStorage *storage, + uint32_t *counter, + BOOL containsNullValue) { + FIRCLSFile file; + + if (!FIRCLSIsValidPointer(storage) || !FIRCLSIsValidPointer(counter)) { + FIRCLSSDKLogError("Bad parameters\n"); + return; + } + + if (!FIRCLSFileInitWithPath(&file, storage->incrementalPath, true)) { + FIRCLSSDKLogError("Unable to open k-v file\n"); + return; + } + + FIRCLSUserLoggingWriteKVEntriesToFile(keysAndValues, true, &file); + FIRCLSFileClose(&file); + + *counter += keysAndValues.count; + if (*counter >= storage->maxIncrementalCount || containsNullValue) { + dispatch_async(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingCompactKVEntries(storage); + *counter = 0; + }); + } +} + +NSArray *FIRCLSUserLoggingStoredKeyValues(const char *path) { + if (!FIRCLSContextIsInitialized()) { + return nil; + } + + return FIRCLSFileReadSections(path, true, ^NSObject *(id obj) { + return [obj objectForKey:@"kv"]; + }); +} + +#pragma mark - NSError Logging +static void FIRCLSUserLoggingRecordErrorUserInfo(FIRCLSFile *file, + const char *fileKey, + NSDictionary *userInfo) { + if ([userInfo count] == 0) { + return; + } + + FIRCLSFileWriteHashKey(file, fileKey); + FIRCLSFileWriteArrayStart(file); + + for (id key in userInfo) { + id value = [userInfo objectForKey:key]; + if (![value respondsToSelector:@selector(description)]) { + continue; + } + + FIRCLSFileWriteArrayStart(file); + FIRCLSFileWriteArrayEntryHexEncodedString(file, [key UTF8String]); + FIRCLSFileWriteArrayEntryHexEncodedString(file, [[value description] UTF8String]); + FIRCLSFileWriteArrayEnd(file); + } + + FIRCLSFileWriteArrayEnd(file); +} + +static void FIRCLSUserLoggingWriteError(FIRCLSFile *file, + NSError *error, + NSDictionary *additionalUserInfo, + NSArray *addresses, + uint64_t timestamp, + NSString *rolloutsInfoJSON) { + FIRCLSFileWriteSectionStart(file, "error"); + FIRCLSFileWriteHashStart(file); + FIRCLSFileWriteHashEntryHexEncodedString(file, "domain", [[error domain] UTF8String]); + FIRCLSFileWriteHashEntryInt64(file, "code", [error code]); + FIRCLSFileWriteHashEntryUint64(file, "time", timestamp); + + // addresses + FIRCLSFileWriteHashKey(file, "stacktrace"); + FIRCLSFileWriteArrayStart(file); + for (NSNumber *address in addresses) { + FIRCLSFileWriteArrayEntryUint64(file, [address unsignedLongLongValue]); + } + FIRCLSFileWriteArrayEnd(file); + + // user-info + FIRCLSUserLoggingRecordErrorUserInfo(file, "info", [error userInfo]); + FIRCLSUserLoggingRecordErrorUserInfo(file, "extra_info", additionalUserInfo); + + // rollouts + if (rolloutsInfoJSON) { + FIRCLSFileWriteHashKey(file, "rollouts"); + FIRCLSFileWriteStringUnquoted(file, [rolloutsInfoJSON UTF8String]); + FIRCLSFileWriteHashEnd(file); + } + + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); +} + +void FIRCLSUserLoggingRecordError(NSError *error, + NSDictionary *additionalUserInfo, + NSString *rolloutsInfoJSON) { + if (!error) { + return; + } + + if (!FIRCLSContextIsInitialized()) { + return; + } + + // record the stacktrace and timestamp here, so we + // are as close as possible to the user's log statement + NSArray *addresses = [NSThread callStackReturnAddresses]; + uint64_t timestamp = time(NULL); + + FIRCLSUserLoggingWriteAndCheckABFiles( + &_firclsContext.readonly->logging.errorStorage, + &_firclsContext.writable->logging.activeErrorLogPath, ^(FIRCLSFile *file) { + FIRCLSUserLoggingWriteError(file, error, additionalUserInfo, addresses, timestamp, + rolloutsInfoJSON); + }); +} + +#pragma mark - CLSLog Support +void FIRCLSLog(NSString *format, ...) { + // If the format is nil do nothing just like NSLog. + if (!format) { + return; + } + + va_list args; + va_start(args, format); + NSString *msg = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + FIRCLSUserLoggingABStorage *currentStorage = &_firclsContext.readonly->logging.logStorage; + const char **activePath = &_firclsContext.writable->logging.activeUserLogPath; + FIRCLSLogInternal(currentStorage, activePath, msg); +} + +void FIRCLSLogToStorage(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + NSString *format, + ...) { + // If the format is nil do nothing just like NSLog. + if (!format) { + return; + } + + va_list args; + va_start(args, format); + NSString *msg = [[NSString alloc] initWithFormat:format arguments:args]; + va_end(args); + + FIRCLSLogInternal(storage, activePath, msg); +} + +#pragma mark - Properties +uint32_t FIRCLSUserLoggingMaxLogSize(void) { + // don't forget that the message encoding overhead is 2x, and we + // wrap everything in a json structure with time. So, there is + // quite a penalty + + uint32_t size = 1024 * 64; + + return size * 2; +} + +uint32_t FIRCLSUserLoggingMaxErrorSize(void) { + return FIRCLSUserLoggingMaxLogSize(); +} + +#pragma mark - AB Logging +void FIRCLSUserLoggingCheckAndSwapABFiles(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + off_t fileSize) { + if (!activePath || !storage) { + return; + } + + if (!*activePath) { + return; + } + + if (storage->restrictBySize) { + if (fileSize <= storage->maxSize) { + return; + } + } else { + if (!FIRCLSIsValidPointer(storage->entryCount)) { + FIRCLSSDKLogError("Error: storage has invalid pointer, but is restricted by entry count\n"); + return; + } + + if (*storage->entryCount < storage->maxEntries) { + return; + } + + // Here we have rolled over, so we have to reset our counter. + *storage->entryCount = 0; + } + + // if it is too big: + // - reset the other log + // - make it active + const char *otherPath = NULL; + + if (*activePath == storage->aPath) { + otherPath = storage->bPath; + } else { + // take this path if the pointer is invalid as well, to reset + otherPath = storage->aPath; + } + + // guard here against path being nil or empty + NSString *pathString = [NSString stringWithUTF8String:otherPath]; + + if ([pathString length] > 0) { + // ignore the error, because there is nothing we can do to recover here, and its likely + // any failures would be intermittent + + [[NSFileManager defaultManager] removeItemAtPath:pathString error:nil]; + } + + @synchronized(FIRCLSSynchronizedPathKey) { + *activePath = otherPath; + } +} + +void FIRCLSUserLoggingWriteAndCheckABFiles(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + void (^openedFileBlock)(FIRCLSFile *file)) { + if (!storage || !activePath || !openedFileBlock) { + return; + } + + @synchronized(FIRCLSSynchronizedPathKey) { + if (!*activePath) { + return; + } + } + + if (storage->restrictBySize) { + if (storage->maxSize == 0) { + return; + } + } else { + if (storage->maxEntries == 0) { + return; + } + } + + dispatch_sync(FIRCLSGetLoggingQueue(), ^{ + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, *activePath, true)) { + FIRCLSSDKLog("Unable to open log file\n"); + return; + } + + openedFileBlock(&file); + + off_t fileSize = 0; + FIRCLSFileCloseWithOffset(&file, &fileSize); + + // increment the count before calling FIRCLSUserLoggingCheckAndSwapABFiles, so the value + // reflects the actual amount of stuff written + if (!storage->restrictBySize && FIRCLSIsValidPointer(storage->entryCount)) { + *storage->entryCount += 1; + } + + dispatch_async(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingCheckAndSwapABFiles(storage, activePath, fileSize); + }); + }); +} + +void FIRCLSLogInternalWrite(FIRCLSFile *file, NSString *message, uint64_t time) { + FIRCLSFileWriteSectionStart(file, "log"); + FIRCLSFileWriteHashStart(file); + FIRCLSFileWriteHashEntryHexEncodedString(file, "msg", [message UTF8String]); + FIRCLSFileWriteHashEntryUint64(file, "time", time); + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteSectionEnd(file); +} + +void FIRCLSLogInternal(FIRCLSUserLoggingABStorage *storage, + const char **activePath, + NSString *message) { + if (!message) { + return; + } + + if (!FIRCLSContextIsInitialized()) { + FIRCLSWarningLog(@"WARNING: FIRCLSLog has been used before (or concurrently with) " + @"Crashlytics initialization and cannot be recorded. The message was: \n%@", + message); + return; + } + struct timeval te; + + NSUInteger messageLength = [message length]; + int maxLogSize = storage->maxSize; + + if (messageLength > maxLogSize) { + FIRCLSWarningLog( + @"WARNING: Attempted to write %zd bytes, but %d is the maximum size of the log. " + @"Truncating to %d bytes.\n", + messageLength, maxLogSize, maxLogSize); + message = [message substringToIndex:maxLogSize]; + } + + // unable to get time - abort + if (gettimeofday(&te, NULL) != 0) { + return; + } + + const uint64_t time = te.tv_sec * 1000LL + te.tv_usec / 1000; + + FIRCLSUserLoggingWriteAndCheckABFiles(storage, activePath, ^(FIRCLSFile *file) { + FIRCLSLogInternalWrite(file, message, time); + }); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h new file mode 100644 index 0000000..dce3eb3 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h @@ -0,0 +1,53 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRCLSSettings; +@protocol FIRAnalyticsInterop; +@protocol FIRAnalyticsInteropListener; + +/* + * Registers a listener for Analytics events in Crashlytics + * logs (aka. breadcrumbs), and sends events to the + * Analytics SDK for Crash Free Users. + */ +@interface FIRCLSAnalyticsManager : NSObject + +- (instancetype)initWithAnalytics:(nullable id)analytics; +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/* + * Starts listening for Analytics events for Breadcrumbs. + */ +- (void)registerAnalyticsListener; + +/* + * Logs a Crashlytics crash session to Firebase Analytics for Crash Free Users. + * @param crashTimeStamp The time stamp of the crash to be logged. + */ ++ (void)logCrashWithTimeStamp:(NSTimeInterval)crashTimeStamp + toAnalytics:(id)analytics; + +/* + * Public for testing. + */ +NSString *FIRCLSFIRAEventDictionaryToJSON(NSDictionary *eventAsDictionary); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.m new file mode 100644 index 0000000..3256dda --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.m @@ -0,0 +1,135 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h" + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" +#import "Interop/Analytics/Public/FIRAnalyticsInteropListener.h" + +static NSString *FIRCLSFirebaseAnalyticsEventLogFormat = @"$A$:%@"; + +// Origin for events and user properties generated by Crashlytics. +static NSString *const kFIREventOriginCrash = @"clx"; + +// App exception event name. +static NSString *const kFIREventAppException = @"_ae"; + +// Timestamp key for the event payload. +static NSString *const kFIRParameterTimestamp = @"timestamp"; + +// Fatal key for the event payload. +static NSString *const kFIRParameterFatal = @"fatal"; + +FOUNDATION_STATIC_INLINE NSNumber *timeIntervalInMillis(NSTimeInterval timeInterval) { + return @(llrint(timeInterval * 1000.0)); +} + +@interface FIRCLSAnalyticsManager () + +@property(nonatomic, strong) id analytics; + +@property(nonatomic, assign) BOOL registeredAnalyticsEventListener; + +@end + +@implementation FIRCLSAnalyticsManager + +- (instancetype)initWithAnalytics:(nullable id)analytics { + self = [super init]; + if (!self) { + return nil; + } + + _analytics = analytics; + + return self; +} + +- (void)registerAnalyticsListener { + if (self.registeredAnalyticsEventListener) { + return; + } + + if (self.analytics == nil) { + FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event", + "Firebase Analytics SDK not detected. Crash-free statistics and " + "breadcrumbs will not be reported"); + return; + } + + [self.analytics registerAnalyticsListener:self withOrigin:kFIREventOriginCrash]; + + FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event", + "Registered Firebase Analytics event listener to receive breadcrumb logs"); + + self.registeredAnalyticsEventListener = YES; +} + +- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters { + NSDictionary *event = @{ + @"name" : name, + @"parameters" : parameters, + }; + NSString *json = FIRCLSFIRAEventDictionaryToJSON(event); + if (json != nil) { + FIRCLSLog(FIRCLSFirebaseAnalyticsEventLogFormat, json); + } +} + ++ (void)logCrashWithTimeStamp:(NSTimeInterval)crashTimeStamp + toAnalytics:(id)analytics { + if (analytics == nil) { + return; + } + + FIRCLSDeveloperLog(@"Crashlytics:Crash:Reports:Event", + "Sending app_exception event to Firebase Analytics for crash-free statistics"); + + NSDictionary *params = @{ + kFIRParameterTimestamp : timeIntervalInMillis(crashTimeStamp), + kFIRParameterFatal : @(INT64_C(1)) + }; + + [analytics logEventWithOrigin:kFIREventOriginCrash name:kFIREventAppException parameters:params]; +} + +NSString *FIRCLSFIRAEventDictionaryToJSON(NSDictionary *eventAsDictionary) { + NSError *error = nil; + + if (eventAsDictionary == nil) { + return nil; + } + + if (![NSJSONSerialization isValidJSONObject:eventAsDictionary]) { + FIRCLSSDKLog("Firebase Analytics event is not valid JSON"); + return nil; + } + + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:eventAsDictionary + options:0 + error:&error]; + + if (error == nil) { + NSString *json = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding]; + return json; + } else { + FIRCLSSDKLog("Unable to convert Firebase Analytics event to json"); + return nil; + } +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h new file mode 100644 index 0000000..1c107dc --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h @@ -0,0 +1,43 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" + +NS_ASSUME_NONNULL_BEGIN + +/// +/// The ContextManager determines when to build the context object, +/// and write its metadata. It was created because the FIRCLSContext +/// is interacted with via functions, which makes it hard to include in tests. +/// In addition, we this class is responsible for re-writing the Metadata object +/// when the App Quality Session ID changes. +/// +@interface FIRCLSContextManager : NSObject + +/// This should be set immediately when the FirebaseSessions SDK generates +/// a new Session ID. +@property(nonatomic, copy) NSString *appQualitySessionId; + +- (BOOL)setupContextWithReport:(FIRCLSInternalReport *)report + settings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.m new file mode 100644 index 0000000..260b05f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.m @@ -0,0 +1,78 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSContext.h" + +@interface FIRCLSContextManager () + +@property(nonatomic, assign) BOOL hasInitializedContext; + +@property(nonatomic, strong) FIRCLSInternalReport *report; +@property(nonatomic, strong) FIRCLSSettings *settings; +@property(nonatomic, strong) FIRCLSFileManager *fileManager; + +@end + +@implementation FIRCLSContextManager + +- (instancetype)init { + self = [super init]; + if (!self) { + return self; + } + + _appQualitySessionId = @""; + + return self; +} + +- (BOOL)setupContextWithReport:(FIRCLSInternalReport *)report + settings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager { + _report = report; + _settings = settings; + _fileManager = fileManager; + + _hasInitializedContext = true; + + FIRCLSContextInitData *initDataObj = self.buildInitData; + return FIRCLSContextInitialize(initDataObj, self.fileManager); +} + +- (void)setAppQualitySessionId:(NSString *)appQualitySessionId { + _appQualitySessionId = appQualitySessionId; + + // This may be called before the context is originally initialized. In that case + // skip the write because it will be written as soon as the context is initialized. + // On future Session ID updates, this will be true and the context metadata will be + // rewritten. + if (!self.hasInitializedContext) { + return; + } + + FIRCLSContextInitData *initDataObj = self.buildInitData; + if (!FIRCLSContextRecordMetadata(self.report.path, initDataObj)) { + FIRCLSErrorLog(@"Failed to write context file while updating App Quality Session ID"); + } +} + +- (FIRCLSContextInitData *)buildInitData { + return FIRCLSContextBuildInitData(self.report, self.settings, self.fileManager, + self.appQualitySessionId); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h new file mode 100644 index 0000000..147ff0b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h @@ -0,0 +1,83 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRCLSManagerData; +@class FIRCLSReportUploader; +@class FIRCLSDataCollectionToken; +@class FIRCrashlyticsReport; + +FOUNDATION_EXPORT NSUInteger const FIRCLSMaxUnsentReports; + +@interface FIRCLSExistingReportManager : NSObject + +/** + * Returns the number of unsent reports on the device, ignoring empty reports in + * the active folder, and ignoring any reports in "processing" or "prepared". + * + * In the past, this would count reports in the processed or prepared + * folders. This has been changed because reports in those paths have already + * been cleared for upload, so there isn't any point in asking for permission + * or possibly spamming end-users if a report gets stuck. + * + * The tricky part is, customers will NOT be alerted in `checkForUnsentReports` + * for reports in these paths, but when they choose `sendUnsentReports` / enable data + * collection, reports in those directories will be re-managed. This should be ok and + * just an edge case because reports should only be in processing or prepared for a split second as + * they do on-device symbolication and get converted into a GDTEvent. After a report is handed off + * to GoogleDataTransport, it is uploaded regardless of Crashlytics data collection. + */ +@property(nonatomic, readonly) NSUInteger unsentReportsCount; + +/** + * This value needs to stay in sync with `numUnsentReports`, so if there is > 0 `numUnsentReports`, + * `newestUnsentReport` needs to return a value. Otherwise it needs to return nil. + * + * `FIRCLSContext` needs to be initialized before the `CrashlyticsReport` is instantiated. + */ +@property(nonatomic, readonly) FIRCrashlyticsReport *_Nullable newestUnsentReport; + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + reportUploader:(FIRCLSReportUploader *)reportUploader; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/** + * This is important to call once, early in startup, before the + * new report for this run of the app has been created. Any + * reports in `ExistingReportManager` will be uploaded or deleted + * and we don't want to do that for the current run of the app. + * + * If there are over MAX_UNSENT_REPORTS valid reports, this will delete them. + * + * This methods is slow and should be called only once. + */ +- (void)collectExistingReports; + +/** + * This is the side-effect of calling `deleteUnsentReports`, or collect_reports setting + * being false. + */ +- (void)deleteUnsentReports; + +- (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m new file mode 100644 index 0000000..e90475b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.m @@ -0,0 +1,274 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h" +#import "Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h" +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h" + +// This value should stay in sync with the Android SDK +NSUInteger const FIRCLSMaxUnsentReports = 4; + +@interface FIRCLSExistingReportManager () + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; +@property(nonatomic, strong) FIRCLSReportUploader *reportUploader; +@property(nonatomic, strong) NSOperationQueue *operationQueue; +@property(nonatomic, strong) FIRCLSSettings *settings; +@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter; +@property(nonatomic, strong) FIRCLSOnDemandModel *onDemandModel; + +// This list of active reports excludes the brand new active report that will be created this run of +// the app. +@property(nonatomic, strong) NSArray *existingUnemptyActiveReportPaths; +@property(nonatomic, strong) NSArray *processingReportPaths; +@property(nonatomic, strong) NSArray *preparedReportPaths; + +@property(nonatomic, strong) FIRCLSInternalReport *newestInternalReport; + +@end + +@implementation FIRCLSExistingReportManager + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + reportUploader:(FIRCLSReportUploader *)reportUploader { + self = [super init]; + if (!self) { + return nil; + } + + _fileManager = managerData.fileManager; + _settings = managerData.settings; + _operationQueue = managerData.operationQueue; + _dataArbiter = managerData.dataArbiter; + _reportUploader = reportUploader; + _onDemandModel = managerData.onDemandModel; + + return self; +} + +NSInteger compareNewer(FIRCLSInternalReport *reportA, + FIRCLSInternalReport *reportB, + void *context) { + // Compare naturally sorts with oldest first, so swap A and B + return [reportB.dateCreated compare:reportA.dateCreated]; +} + +- (void)collectExistingReports { + self.existingUnemptyActiveReportPaths = + [self getUnsentActiveReportsAndDeleteEmptyOrOld:self.fileManager.activePathContents]; + self.processingReportPaths = self.fileManager.processingPathContents; + self.preparedReportPaths = self.fileManager.preparedPathContents; +} + +- (FIRCrashlyticsReport *)newestUnsentReport { + if (self.unsentReportsCount <= 0) { + return nil; + } + + return [[FIRCrashlyticsReport alloc] initWithInternalReport:self.newestInternalReport]; +} + +- (NSUInteger)unsentReportsCount { + // There are nuances about why we only count active reports. + // See the header comment for more information. + return self.existingUnemptyActiveReportPaths.count; +} + +/* + * This has the side effect of deleting any reports over the max, starting with oldest reports. + */ +- (NSArray *)getUnsentActiveReportsAndDeleteEmptyOrOld:(NSArray *)reportPaths { + NSMutableArray *validReports = [NSMutableArray array]; + NSMutableArray *reports = [NSMutableArray array]; + + for (NSString *path in reportPaths) { + FIRCLSInternalReport *_Nullable report = [FIRCLSInternalReport reportWithPath:path]; + if (!report) { + continue; + } + + [reports addObject:report]; + } + + if (reports.count == 0) { + return @[]; + } + + [reports sortUsingFunction:compareNewer context:nil]; + NSString *newestReportPath = [reports firstObject].path; + + // If there was a MetricKit event recorded on the last run of the app, add it to the newest + // report. + if (self.settings.metricKitCollectionEnabled && + [self.fileManager metricKitDiagnosticFileExists]) { + [self.fileManager createEmptyMetricKitFile:newestReportPath]; + } + + for (FIRCLSInternalReport *report in reports) { + // Delete reports without any crashes or non-fatals + if (![report hasAnyEvents]) { + [self.operationQueue addOperationWithBlock:^{ + [self.fileManager removeItemAtPath:report.path]; + }]; + continue; + } + + [validReports addObject:report]; + } + + if (validReports.count == 0) { + return @[]; + } + + // Sort with the newest at the end + [validReports sortUsingFunction:compareNewer context:nil]; + + // Set our report for updating in checkAndUpdateUnsentReports + self.newestInternalReport = [validReports firstObject]; + + // Delete any reports above the limit, starting with the oldest + // which should be at the start of the array. + if (validReports.count > FIRCLSMaxUnsentReports) { + NSUInteger deletingCount = validReports.count - FIRCLSMaxUnsentReports; + FIRCLSInfoLog( + @"Automatic data collection is disabled. Deleting %lu unsent reports over the limit of %lu " + @"to prevent disk space from " + @"filling up. To take action on these reports, call send/deleteUnsentReports. To turn on " + @"automatic data collection, call setCrashlyticsCollectionEnabled with true", + deletingCount, FIRCLSMaxUnsentReports); + } + + // Not that validReports is sorted, delete any reports at indices > MAX_UNSENT_REPORTS, and + // collect the rest of the reports to return. + NSMutableArray *validReportPaths = [NSMutableArray array]; + for (int i = 0; i < validReports.count; i++) { + if (i >= FIRCLSMaxUnsentReports) { + [self.operationQueue addOperationWithBlock:^{ + NSString *path = [[validReports objectAtIndex:i] path]; + [self.fileManager removeItemAtPath:path]; + }]; + } else { + [validReportPaths addObject:[[validReports objectAtIndex:i] path]]; + } + } + + return validReportPaths; +} + +- (void)sendUnsentReportsWithToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent { + for (NSString *path in self.existingUnemptyActiveReportPaths) { + [self processExistingActiveReportPath:path + dataCollectionToken:dataCollectionToken + asUrgent:urgent]; + } + + for (NSString *path in self.onDemandModel.storedActiveReportPaths) { + [self processExistingActiveReportPath:path + dataCollectionToken:dataCollectionToken + asUrgent:urgent]; + } + [self.onDemandModel.storedActiveReportPaths removeAllObjects]; + + // deal with stuff in processing more carefully - do not process again + [self.operationQueue addOperationWithBlock:^{ + for (NSString *path in self.processingReportPaths) { + FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path]; + [self.reportUploader prepareAndSubmitReport:report + dataCollectionToken:dataCollectionToken + asUrgent:NO + withProcessing:NO]; + } + }]; + + // Because this could happen quite a bit after the initial set of files was + // captured, some could be completed (deleted). So, just double-check to make sure + // the file still exists. + [self.operationQueue addOperationWithBlock:^{ + for (NSString *path in self.preparedReportPaths) { + if (![self.fileManager fileExistsAtPath:path]) { + continue; + } + [self.reportUploader uploadPackagedReportAtPath:path + dataCollectionToken:dataCollectionToken + asUrgent:NO]; + } + }]; +} + +- (void)processExistingActiveReportPath:(NSString *)path + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent { + FIRCLSInternalReport *report = [FIRCLSInternalReport reportWithPath:path]; + + // TODO: hasAnyEvents should really be called on the background queue. + if (![report hasAnyEvents]) { + [self.operationQueue addOperationWithBlock:^{ + [self.fileManager removeItemAtPath:path]; + }]; + + return; + } + + if (urgent && [dataCollectionToken isValid]) { + // We can proceed without the delegate. + [self.reportUploader prepareAndSubmitReport:report + dataCollectionToken:dataCollectionToken + asUrgent:urgent + withProcessing:YES]; + return; + } + + [self.operationQueue addOperationWithBlock:^{ + [self.reportUploader prepareAndSubmitReport:report + dataCollectionToken:dataCollectionToken + asUrgent:NO + withProcessing:YES]; + }]; +} + +- (void)deleteUnsentReports { + NSArray *reportPaths = @[]; + reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.existingUnemptyActiveReportPaths]; + reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.processingReportPaths]; + reportPaths = [reportPaths arrayByAddingObjectsFromArray:self.preparedReportPaths]; + + [self.operationQueue addOperationWithBlock:^{ + for (NSString *path in reportPaths) { + [self.fileManager removeItemAtPath:path]; + } + }]; +} + +- (void)handleOnDemandReportUpload:(NSString *)path + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent { + dispatch_async(self.operationQueue.underlyingQueue, ^{ + [self processExistingActiveReportPath:path + dataCollectionToken:dataCollectionToken + asUrgent:YES]; + }); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h new file mode 100644 index 0000000..fbd43f0 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h @@ -0,0 +1,93 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FIRCLSFileManager; +@class FIRInstallations; +@class FIRCLSDataCollectionArbiter; +@class FIRCLSApplicationIdentifierModel; +@class FIRCLSInstallIdentifierModel; +@class FIRCLSExecutionIdentifierModel; +@class FIRCLSOnDemandModel; +@class FIRCLSSettings; +@class FIRCLSLaunchMarkerModel; +@class FIRCLSContextManager; +@class GDTCORTransport; +@protocol FIRAnalyticsInterop; + +/* + * FIRCLSManagerData's purpose is to simplify the adding and removing of + * dependencies from each of the Manager classes so that it's easier + * to inject mock classes during testing. A lot of the Manager classes + * share these dependencies, but don't use all of them. + * + * If you plan on adding interdependencies between Managers, do not add a pointer + * to the dependency here. Instead add them as a new value to the constructor of + * the Manager, and construct them in FirebaseCrashlytics. This data structure should + * be for Models and other SDKs / Interops Crashlytics depends on. + */ +@interface FIRCLSManagerData : NSObject + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + googleTransport:(GDTCORTransport *)googleTransport + installations:(FIRInstallations *)installations + analytics:(nullable id)analytics + fileManager:(FIRCLSFileManager *)fileManager + dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter + settings:(FIRCLSSettings *)settings + onDemandModel:(FIRCLSOnDemandModel *)onDemandModel NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@property(nonatomic, readonly) NSString *googleAppID; + +@property(nonatomic, strong) GDTCORTransport *googleTransport; + +@property(nonatomic, strong) FIRInstallations *installations; + +@property(nonatomic, strong) id analytics; + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; + +@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter; + +// Uniquely identifies a build / binary of the app +@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel; + +// Uniquely identifies an install of the app +@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel; + +// Uniquely identifies a run of the app +@property(nonatomic, strong) FIRCLSExecutionIdentifierModel *executionIDModel; + +// Handles storing and uploading of on-demand events +@property(nonatomic, readonly) FIRCLSOnDemandModel *onDemandModel; + +// Settings fetched from the server +@property(nonatomic, strong) FIRCLSSettings *settings; + +// Sets up the Context and writes Metadata files to the crash report +@property(nonatomic, strong) FIRCLSContextManager *contextManager; + +// These queues function together as a single startup queue +@property(nonatomic, strong) NSOperationQueue *operationQueue; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.m new file mode 100644 index 0000000..c6f1577 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.m @@ -0,0 +1,65 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h" +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" + +@implementation FIRCLSManagerData + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + googleTransport:(GDTCORTransport *)googleTransport + installations:(FIRInstallations *)installations + analytics:(nullable id)analytics + fileManager:(FIRCLSFileManager *)fileManager + dataArbiter:(FIRCLSDataCollectionArbiter *)dataArbiter + settings:(FIRCLSSettings *)settings + onDemandModel:(FIRCLSOnDemandModel *)onDemandModel { + self = [super init]; + if (!self) { + return nil; + } + + _googleAppID = googleAppID; + _googleTransport = googleTransport; + _installations = installations; + _analytics = analytics; + _fileManager = fileManager; + _dataArbiter = dataArbiter; + _settings = settings; + _onDemandModel = onDemandModel; + _contextManager = [[FIRCLSContextManager alloc] init]; + + _appIDModel = [[FIRCLSApplicationIdentifierModel alloc] init]; + _installIDModel = [[FIRCLSInstallIdentifierModel alloc] initWithInstallations:installations]; + _executionIDModel = [[FIRCLSExecutionIdentifierModel alloc] init]; + + NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID(); + _operationQueue = [NSOperationQueue new]; + [_operationQueue setMaxConcurrentOperationCount:1]; + [_operationQueue setName:[sdkBundleID stringByAppendingString:@".work-queue"]]; + + _dispatchQueue = dispatch_queue_create("com.google.firebase.crashlytics.startup", 0); + _operationQueue.underlyingQueue = _dispatchQueue; + + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.h new file mode 100644 index 0000000..ee490eb --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.h @@ -0,0 +1,47 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include +#import + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" + +#if CLS_METRICKIT_SUPPORTED +#import + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSMetricKitManager : NSObject + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + existingReportManager:(FIRCLSExistingReportManager *)existingReportManager + fileManager:(FIRCLSFileManager *)fileManager; + +- (instancetype)init NS_UNAVAILABLE; +- (void)registerMetricKitManager; +- (FBLPromise *)waitForMetricKitDataAvailable; + +@end + +NS_ASSUME_NONNULL_END +#endif // CLS_METRICKIT_SUPPORTED diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.m new file mode 100644 index 0000000..0c081df --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.m @@ -0,0 +1,449 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.h" + +#if CLS_METRICKIT_SUPPORTED + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h" +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h" + +@interface FIRCLSMetricKitManager () + +@property FBLPromise *metricKitDataAvailable; +@property FIRCLSExistingReportManager *existingReportManager; +@property FIRCLSFileManager *fileManager; +@property FIRCLSManagerData *managerData; +@property BOOL metricKitPromiseFulfilled; + +@end + +@implementation FIRCLSMetricKitManager + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + existingReportManager:(FIRCLSExistingReportManager *)existingReportManager + fileManager:(FIRCLSFileManager *)fileManager { + _existingReportManager = existingReportManager; + _fileManager = fileManager; + _managerData = managerData; + _metricKitPromiseFulfilled = NO; + return self; +} + +/* + * Registers the MetricKit manager to receive MetricKit reports by adding self to the + * MXMetricManager subscribers. Also initializes the promise that we'll use to ensure that any + * MetricKit report files are included in Crashylytics fatal reports. If no crash occurred on the + * last run of the app, this promise is immediately resolved so that the upload of any nonfatal + * events can proceed. + */ +- (void)registerMetricKitManager API_AVAILABLE(ios(14)) { + [[MXMetricManager sharedManager] addSubscriber:self]; + self.metricKitDataAvailable = [FBLPromise pendingPromise]; + + // If there was no crash on the last run of the app or there's no diagnostic report in the + // MetricKit directory, then we aren't expecting a MetricKit diagnostic report and should resolve + // the promise immediately. If MetricKit captured a fatal event and Crashlytics did not, then + // we'll still process the MetricKit crash but won't upload it until the app restarts again. + if (![self.fileManager didCrashOnPreviousExecution] || + ![self.fileManager metricKitDiagnosticFileExists]) { + @synchronized(self) { + [self fulfillMetricKitPromise]; + } + } + + // If we haven't resolved this promise within three seconds, resolve it now so that we're not + // waiting indefinitely for MetricKit payloads that won't arrive. + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC), self.managerData.dispatchQueue, + ^{ + @synchronized(self) { + if (!self.metricKitPromiseFulfilled) { + FIRCLSDebugLog(@"Resolving MetricKit promise after three seconds"); + [self fulfillMetricKitPromise]; + } + } + }); + + FIRCLSDebugLog(@"Finished registering metrickit manager"); +} + +/* + * This method receives diagnostic payloads from MetricKit whenever a fatal or nonfatal MetricKit + * event occurs. If a fatal event, this method will be called when the app restarts. Since we're + * including a MetricKit report file in the Crashlytics report to be sent to the backend, we need + * to make sure that we process the payloads and write the included information to file before + * the report is sent up. If this method is called due to a nonfatal event, it will be called + * immediately after the event. Since we send nonfatal events on the next run of the app, we can + * write out the information but won't need to resolve the promise. + */ +- (void)didReceiveDiagnosticPayloads:(NSArray *)payloads + API_AVAILABLE(ios(14)) { + BOOL processedFatalPayload = NO; + for (MXDiagnosticPayload *diagnosticPayload in payloads) { + if (!diagnosticPayload) { + continue; + } + + BOOL processedPayload = [self processMetricKitPayload:diagnosticPayload + skipCrashEvent:processedFatalPayload]; + if (processedPayload && ([diagnosticPayload.crashDiagnostics count] > 0)) { + processedFatalPayload = YES; + } + } + // Once we've processed all the payloads, resolve the promise so that reporting uploading + // continues. If there was not a crash on the previous run of the app, the promise will already + // have been resolved. + @synchronized(self) { + [self fulfillMetricKitPromise]; + } +} + +// Helper method to write a MetricKit payload's data to file. +- (BOOL)processMetricKitPayload:(MXDiagnosticPayload *)diagnosticPayload + skipCrashEvent:(BOOL)skipCrashEvent API_AVAILABLE(ios(14)) { + BOOL writeFailed = NO; + + // Write out each type of diagnostic if it exists in the report + BOOL hasCrash = [diagnosticPayload.crashDiagnostics count] > 0; + BOOL hasHang = [diagnosticPayload.hangDiagnostics count] > 0; + BOOL hasCPUException = [diagnosticPayload.cpuExceptionDiagnostics count] > 0; + BOOL hasDiskWriteException = [diagnosticPayload.diskWriteExceptionDiagnostics count] > 0; + + // If there are no diagnostics in the report, return before writing out any files. + if (!hasCrash && !hasHang && !hasCPUException && !hasDiskWriteException) { + return false; + } + + // MXDiagnosticPayload have both a timeStampBegin and timeStampEnd. Now that these events are + // real-time, both refer to the same time - record both values anyway. + NSTimeInterval beginSecondsSince1970 = [diagnosticPayload.timeStampBegin timeIntervalSince1970]; + NSTimeInterval endSecondsSince1970 = [diagnosticPayload.timeStampEnd timeIntervalSince1970]; + + // Get file path for the active reports directory. + NSString *activePath = [[self.fileManager activePath] stringByAppendingString:@"/"]; + + // If there is a crash diagnostic in the payload, then this method was called for a fatal event. + // Also ensure that there is a report from the last run of the app that we can write to. + NSString *metricKitFatalReportFile; + NSString *metricKitNonfatalReportFile; + + NSString *newestUnsentReportID = + self.existingReportManager.newestUnsentReport.reportID + ? [self.existingReportManager.newestUnsentReport.reportID stringByAppendingString:@"/"] + : nil; + NSString *currentReportID = + [_managerData.executionIDModel.executionID stringByAppendingString:@"/"]; + BOOL crashlyticsFatalReported = + ([diagnosticPayload.crashDiagnostics count] > 0) && (newestUnsentReportID != nil) && + ([self.fileManager + fileExistsAtPath:[activePath stringByAppendingString:newestUnsentReportID]]); + + // Set the MetricKit fatal path appropriately depending on whether we also captured a Crashlytics + // fatal event and whether the diagnostic report came from a fatal or nonfatal event. + if (crashlyticsFatalReported) { + metricKitFatalReportFile = [[activePath stringByAppendingString:newestUnsentReportID] + stringByAppendingString:FIRCLSMetricKitFatalReportFile]; + } else { + metricKitFatalReportFile = [[activePath stringByAppendingString:currentReportID] + stringByAppendingString:FIRCLSMetricKitFatalReportFile]; + } + metricKitNonfatalReportFile = [[activePath stringByAppendingString:currentReportID] + stringByAppendingString:FIRCLSMetricKitNonfatalReportFile]; + + if (!metricKitFatalReportFile || !metricKitNonfatalReportFile) { + FIRCLSDebugLog(@"Error finding MetricKit files"); + return NO; + } + + FIRCLSDebugLog(@"File paths for MetricKit report: %@, %@", metricKitFatalReportFile, + metricKitNonfatalReportFile); + if (hasCrash && ![_fileManager fileExistsAtPath:metricKitFatalReportFile]) { + [_fileManager createFileAtPath:metricKitFatalReportFile contents:nil attributes:nil]; + } + if ((hasHang | hasCPUException | hasDiskWriteException) && + ![_fileManager fileExistsAtPath:metricKitNonfatalReportFile]) { + [_fileManager createFileAtPath:metricKitNonfatalReportFile contents:nil attributes:nil]; + } + NSFileHandle *nonfatalFile = + [NSFileHandle fileHandleForUpdatingAtPath:metricKitNonfatalReportFile]; + if ((hasHang | hasCPUException | hasDiskWriteException) && nonfatalFile == nil) { + FIRCLSDebugLog(@"Unable to create or open nonfatal MetricKit file."); + return false; + } + NSFileHandle *fatalFile = [NSFileHandle fileHandleForUpdatingAtPath:metricKitFatalReportFile]; + if (hasCrash && fatalFile == nil) { + FIRCLSDebugLog(@"Unable to create or open fatal MetricKit file."); + return false; + } + + NSData *newLineData = [@"\n" dataUsingEncoding:NSUTF8StringEncoding]; + + // For each diagnostic type, write out a section in the MetricKit report file. This section will + // have subsections for threads, metadata, and event specific metadata. + if (hasCrash && !skipCrashEvent) { + // Write out time information to the MetricKit report file. Time needs to be a value for + // backend serialization, so we write out end_time separately. + + MXCrashDiagnostic *crashDiagnostic = [diagnosticPayload.crashDiagnostics objectAtIndex:0]; + + NSArray *threadArray = [self convertThreadsToArray:crashDiagnostic.callStackTree]; + NSDictionary *metadataDict = [self convertMetadataToDictionary:crashDiagnostic.metaData]; + + NSString *nilString = @""; + + // On the backend, we process name, code name, and address into the subtitle of an issue. + // Mach exception name and code should be preferred over signal name and code if available. + const char *signalName = NULL; + const char *signalCodeName = NULL; + FIRCLSSignalNameLookup([crashDiagnostic.signal intValue], 0, &signalName, &signalCodeName); + // signalName is the default name, so should never be NULL + if (signalName == NULL) { + signalName = "UNKNOWN"; + } + if (signalCodeName == NULL) { + signalCodeName = ""; + } + + const char *machExceptionName = NULL; + const char *machExceptionCodeName = NULL; +#if CLS_MACH_EXCEPTION_SUPPORTED + FIRCLSMachExceptionNameLookup( + [crashDiagnostic.exceptionType intValue], + (mach_exception_data_type_t)[crashDiagnostic.exceptionCode intValue], &machExceptionName, + &machExceptionCodeName); +#endif + if (machExceptionCodeName == NULL) { + machExceptionCodeName = ""; + } + + NSString *name = machExceptionName != NULL ? [NSString stringWithUTF8String:machExceptionName] + : [NSString stringWithUTF8String:signalName]; + NSString *codeName = machExceptionName != NULL + ? [NSString stringWithUTF8String:machExceptionCodeName] + : [NSString stringWithUTF8String:signalCodeName]; + + NSDictionary *crashDictionary = @{ + @"metric_kit_fatal" : @{ + @"time" : [NSNumber numberWithLong:beginSecondsSince1970], + @"end_time" : [NSNumber numberWithLong:endSecondsSince1970], + @"metadata" : metadataDict, + @"termination_reason" : + (crashDiagnostic.terminationReason) ? crashDiagnostic.terminationReason : nilString, + @"virtual_memory_region_info" : (crashDiagnostic.virtualMemoryRegionInfo) + ? crashDiagnostic.virtualMemoryRegionInfo + : nilString, + @"exception_type" : crashDiagnostic.exceptionType, + @"exception_code" : crashDiagnostic.exceptionCode, + @"signal" : crashDiagnostic.signal, + @"app_version" : crashDiagnostic.applicationVersion, + @"code_name" : codeName, + @"name" : name + } + }; + writeFailed = ![self writeDictionaryToFile:crashDictionary + file:fatalFile + newLineData:newLineData]; + writeFailed = writeFailed | ![self writeDictionaryToFile:@{@"threads" : threadArray} + file:fatalFile + newLineData:newLineData]; + } + + if (hasHang) { + MXHangDiagnostic *hangDiagnostic = [diagnosticPayload.hangDiagnostics objectAtIndex:0]; + + NSArray *threadArray = [self convertThreadsToArray:hangDiagnostic.callStackTree]; + NSDictionary *metadataDict = [self convertMetadataToDictionary:hangDiagnostic.metaData]; + + NSDictionary *hangDictionary = @{ + @"exception" : @{ + @"type" : @"metrickit_nonfatal", + @"name" : @"hang_event", + @"time" : [NSNumber numberWithLong:beginSecondsSince1970], + @"end_time" : [NSNumber numberWithLong:endSecondsSince1970], + @"threads" : threadArray, + @"metadata" : metadataDict, + @"hang_duration" : [NSNumber numberWithDouble:[hangDiagnostic.hangDuration doubleValue]], + @"app_version" : hangDiagnostic.applicationVersion + } + }; + + writeFailed = ![self writeDictionaryToFile:hangDictionary + file:nonfatalFile + newLineData:newLineData]; + } + + if (hasCPUException) { + MXCPUExceptionDiagnostic *cpuExceptionDiagnostic = + [diagnosticPayload.cpuExceptionDiagnostics objectAtIndex:0]; + + NSArray *threadArray = [self convertThreadsToArray:cpuExceptionDiagnostic.callStackTree]; + NSDictionary *metadataDict = [self convertMetadataToDictionary:cpuExceptionDiagnostic.metaData]; + + NSDictionary *cpuDictionary = @{ + @"exception" : @{ + @"type" : @"metrickit_nonfatal", + @"name" : @"cpu_exception_event", + @"time" : [NSNumber numberWithLong:beginSecondsSince1970], + @"end_time" : [NSNumber numberWithLong:endSecondsSince1970], + @"threads" : threadArray, + @"metadata" : metadataDict, + @"total_cpu_time" : + [NSNumber numberWithDouble:[cpuExceptionDiagnostic.totalCPUTime doubleValue]], + @"total_sampled_time" : + [NSNumber numberWithDouble:[cpuExceptionDiagnostic.totalSampledTime doubleValue]], + @"app_version" : cpuExceptionDiagnostic.applicationVersion + } + }; + writeFailed = ![self writeDictionaryToFile:cpuDictionary + file:nonfatalFile + newLineData:newLineData]; + } + + if (hasDiskWriteException) { + MXDiskWriteExceptionDiagnostic *diskWriteExceptionDiagnostic = + [diagnosticPayload.diskWriteExceptionDiagnostics objectAtIndex:0]; + + NSArray *threadArray = [self convertThreadsToArray:diskWriteExceptionDiagnostic.callStackTree]; + NSDictionary *metadataDict = + [self convertMetadataToDictionary:diskWriteExceptionDiagnostic.metaData]; + + NSDictionary *diskWriteDictionary = @{ + @"exception" : @{ + @"type" : @"metrickit_nonfatal", + @"name" : @"disk_write_exception_event", + @"time" : [NSNumber numberWithLong:beginSecondsSince1970], + @"end_time" : [NSNumber numberWithLong:endSecondsSince1970], + @"threads" : threadArray, + @"metadata" : metadataDict, + @"app_version" : diskWriteExceptionDiagnostic.applicationVersion, + @"total_writes_caused" : + [NSNumber numberWithDouble:[diskWriteExceptionDiagnostic.totalWritesCaused doubleValue]] + } + }; + writeFailed = ![self writeDictionaryToFile:diskWriteDictionary + file:nonfatalFile + newLineData:newLineData]; + } + + return !writeFailed; +} +/* + * Required for MXMetricManager subscribers. Since we aren't currently collecting any MetricKit + * metrics, this method is left empty. + */ +- (void)didReceiveMetricPayloads:(NSArray *)payloads API_AVAILABLE(ios(13)) { +} + +- (FBLPromise *)waitForMetricKitDataAvailable { + FBLPromise *result = nil; + @synchronized(self) { + result = self.metricKitDataAvailable; + } + return result; +} + +/* + * Helper method to convert threads for a MetricKit fatal diagnostic event to an array of threads. + */ +- (NSArray *)convertThreadsToArray:(MXCallStackTree *)mxCallStackTree API_AVAILABLE(ios(14)) { + FIRCLSCallStackTree *tree = [[FIRCLSCallStackTree alloc] initWithMXCallStackTree:mxCallStackTree]; + return [tree getArrayRepresentation]; +} + +/* + * Helper method to convert threads for a MetricKit nonfatal diagnostic event to an array of frames. + */ +- (NSArray *)convertThreadsToArrayForNonfatal:(MXCallStackTree *)mxCallStackTree + API_AVAILABLE(ios(14)) { + FIRCLSCallStackTree *tree = [[FIRCLSCallStackTree alloc] initWithMXCallStackTree:mxCallStackTree]; + return [tree getFramesOfBlamedThread]; +} + +/* + * Helper method to convert metadata for a MetricKit diagnostic event to a dictionary. MXMetadata + * has a dictionaryRepresentation method but it is deprecated. + */ +- (NSDictionary *)convertMetadataToDictionary:(MXMetaData *)metadata API_AVAILABLE(ios(14)) { + NSError *error = nil; + NSDictionary *metadataDictionary = + [NSJSONSerialization JSONObjectWithData:[metadata JSONRepresentation] options:0 error:&error]; + return metadataDictionary; +} + +/* + * Helper method to fulfill the metricKitDataAvailable promise and track that it has been fulfilled. + */ +- (void)fulfillMetricKitPromise { + if (self.metricKitPromiseFulfilled) return; + + [self.metricKitDataAvailable fulfill:nil]; + self.metricKitPromiseFulfilled = YES; +} + +/* + * Helper method to write a dictionary of event information to file. Returns whether it succeeded. + */ +- (BOOL)writeDictionaryToFile:(NSDictionary *)dictionary + file:(NSFileHandle *)file + newLineData:(NSData *)newLineData { + NSError *dataError = nil; + NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&dataError]; + if (dataError) { + FIRCLSDebugLog(@"Unable to write out dictionary."); + return NO; + } + + [file seekToEndOfFile]; + [file writeData:data]; + [file writeData:newLineData]; + + return YES; +} + +- (NSString *)getSignalName:(NSNumber *)signalCode { + int signal = [signalCode intValue]; + switch (signal) { + case SIGABRT: + return @"SIGABRT"; + case SIGBUS: + return @"SIGBUS"; + case SIGFPE: + return @"SIGFPE"; + case SIGILL: + return @"SIGILL"; + case SIGSEGV: + return @"SIGSEGV"; + case SIGSYS: + return @"SIGSYS"; + case SIGTRAP: + return @"SIGTRAP"; + default: + return @"UNKNOWN"; + } + return @"UNKNOWN"; +} + +@end + +#endif // CLS_METRICKIT_SUPPORTED diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h new file mode 100644 index 0000000..684a26b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h @@ -0,0 +1,27 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSNotificationManager : NSObject + ++ (instancetype)new NS_UNAVAILABLE; + +- (void)registerNotificationListener; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m new file mode 100644 index 0000000..9ac4e1e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m @@ -0,0 +1,113 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +@implementation FIRCLSNotificationManager + +- (void)registerNotificationListener { + [self captureInitialNotificationStates]; + +#if TARGET_OS_IOS + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(willBecomeActive:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didBecomeInactive:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; +#if !CLS_TARGET_OS_VISION + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didChangeOrientation:) + name:UIDeviceOrientationDidChangeNotification + object:nil]; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(didChangeUIOrientation:) + name:UIApplicationDidChangeStatusBarOrientationNotification + object:nil]; +#pragma clang diagnostic pop +#endif // !CLS_TARGET_OS_VISION + +#elif CLS_TARGET_OS_OSX + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(willBecomeActive:) + name:@"NSApplicationWillBecomeActiveNotification" + object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(didBecomeInactive:) + name:@"NSApplicationDidResignActiveNotification" + object:nil]; +#endif +} + +- (void)captureInitialNotificationStates { +#if TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) + UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; + UIInterfaceOrientation statusBarOrientation = + [FIRCLSApplicationSharedInstance() statusBarOrientation]; +#endif // TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) + + // It's nice to do this async, so we don't hold up the main thread while doing three + // consecutive IOs here. + dispatch_async(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSInBackgroundKey, @"0"); +#if TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) + FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSDeviceOrientationKey, + [@(orientation) description]); + FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSUIOrientationKey, + [@(statusBarOrientation) description]); +#endif // TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) + }); +} + +- (void)willBecomeActive:(NSNotification *)notification { + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @NO); +} + +- (void)didBecomeInactive:(NSNotification *)notification { + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @YES); +} + +#if TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) +- (void)didChangeOrientation:(NSNotification *)notification { + UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation]; + + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDeviceOrientationKey, @(orientation)); +} + +- (void)didChangeUIOrientation:(NSNotification *)notification { + UIInterfaceOrientation statusBarOrientation = + [FIRCLSApplicationSharedInstance() statusBarOrientation]; + + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUIOrientationKey, @(statusBarOrientation)); +} +#endif // TARGET_OS_IOS && (!CLS_TARGET_OS_VISION) + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h new file mode 100644 index 0000000..1b17edb --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h @@ -0,0 +1,47 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h" + +@class FBLPromise; +@class FIRCLSExistingReportManager; +@class FIRCLSAnalyticsManager; +@class FIRCLSManagerData; +@class FIRCLSContextManager; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSReportManager : NSObject + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + existingReportManager:(FIRCLSExistingReportManager *)existingReportManager + analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager + NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +- (FBLPromise *)startWithProfiling; + +- (FBLPromise *)checkForUnsentReports; +- (FBLPromise *)sendUnsentReports; +- (FBLPromise *)deleteUnsentReports; + +@end + +extern NSString *const FIRCLSConfigSubmitReportsKey; +extern NSString *const FIRCLSConfigPackageReportsKey; + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.m new file mode 100644 index 0000000..8d5b409 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.m @@ -0,0 +1,502 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +// The report manager has the ability to send to two different endpoints. +// +// The old legacy flow for a report goes through the following states/folders: +// 1. active - .clsrecords optimized for crash time persistence +// 2. processing - .clsrecords with attempted symbolication +// 3. prepared-legacy - .multipartmime of compressed .clsrecords +// +// The new flow for a report goes through the following states/folders: +// 1. active - .clsrecords optimized for crash time persistence +// 2. processing - .clsrecords with attempted symbolication +// 3. prepared - .clsrecords moved from processing with no changes +// +// The code was designed so the report processing workflows are not dramatically different from one +// another. The design will help avoid having a lot of conditional code blocks throughout the +// codebase. +// + +#include + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSMetricKitManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h" +#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h" +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" + +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +/** + * A FirebaseReportAction is used to indicate how to handle unsent reports. + */ +typedef NS_ENUM(NSInteger, FIRCLSReportAction) { + /** Upload the reports to Crashlytics. */ + FIRCLSReportActionSend, + /** Delete the reports without uploading them. */ + FIRCLSReportActionDelete, +}; + +/** + * This is just a helper to make code using FirebaseReportAction more readable. + */ +typedef NSNumber FIRCLSWrappedReportAction; +@implementation NSNumber (FIRCLSWrappedReportAction) +- (FIRCLSReportAction)reportActionValue { + return [self intValue]; +} +@end + +@interface FIRCLSReportManager () { + FIRCLSFileManager *_fileManager; + dispatch_queue_t _dispatchQueue; + NSOperationQueue *_operationQueue; + id _analytics; + + // A promise that will be resolved when unsent reports are found on the device, and + // processReports: can be called to decide how to deal with them. + FBLPromise *_unsentReportsAvailable; + + // A promise that will be resolved when the user has provided an action that they want to perform + // for all the unsent reports. + FBLPromise *_reportActionProvided; + + // A promise that will be resolved when all unsent reports have been "handled". They won't + // necessarily have been uploaded, but we will know whether they should be sent or deleted, and + // the initial work to make that happen will have been processed on the work queue. + // + // Currently only used for testing + FBLPromise *_unsentReportsHandled; + + // A token to make sure that checkForUnsentReports only gets called once. + atomic_bool _checkForUnsentReportsCalled; + + BOOL _registeredAnalyticsEventListener; +} + +@property(nonatomic, readonly) NSString *googleAppID; +@property(nonatomic, strong) GDTCORTransport *googleTransport; + +@property(nonatomic, strong) FIRCLSDataCollectionArbiter *dataArbiter; +@property(nonatomic, strong) FIRCLSSettings *settings; +@property(nonatomic, strong) FIRCLSLaunchMarkerModel *launchMarker; + +@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel; +@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel; +@property(nonatomic, strong) FIRCLSExecutionIdentifierModel *executionIDModel; + +@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager; +@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager; + +@property(nonatomic, strong) FIRCLSContextManager *contextManager; + +// Internal Managers +@property(nonatomic, strong) FIRCLSSettingsManager *settingsManager; +@property(nonatomic, strong) FIRCLSNotificationManager *notificationManager; +#if CLS_METRICKIT_SUPPORTED +@property(nonatomic, strong) FIRCLSMetricKitManager *metricKitManager; +#endif + +@end + +@implementation FIRCLSReportManager + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData + existingReportManager:(FIRCLSExistingReportManager *)existingReportManager + analyticsManager:(FIRCLSAnalyticsManager *)analyticsManager { + self = [super init]; + if (!self) { + return nil; + } + + _fileManager = managerData.fileManager; + _analytics = managerData.analytics; + _googleAppID = [managerData.googleAppID copy]; + _dataArbiter = managerData.dataArbiter; + _googleTransport = managerData.googleTransport; + _operationQueue = managerData.operationQueue; + _dispatchQueue = managerData.dispatchQueue; + _appIDModel = managerData.appIDModel; + _installIDModel = managerData.installIDModel; + _settings = managerData.settings; + _executionIDModel = managerData.executionIDModel; + _contextManager = managerData.contextManager; + + _existingReportManager = existingReportManager; + _analyticsManager = analyticsManager; + + _unsentReportsAvailable = [FBLPromise pendingPromise]; + _reportActionProvided = [FBLPromise pendingPromise]; + _unsentReportsHandled = [FBLPromise pendingPromise]; + + _checkForUnsentReportsCalled = NO; + + _settingsManager = [[FIRCLSSettingsManager alloc] initWithAppIDModel:self.appIDModel + installIDModel:self.installIDModel + settings:self.settings + fileManager:self.fileManager + googleAppID:self.googleAppID]; + + _notificationManager = [[FIRCLSNotificationManager alloc] init]; + + // This needs to be called before any values are read from settings + NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate]; + [self.settings reloadFromCacheWithGoogleAppID:self.googleAppID currentTimestamp:currentTimestamp]; + +#if CLS_METRICKIT_SUPPORTED + if (@available(iOS 15, *)) { + if (self.settings.metricKitCollectionEnabled) { + FIRCLSDebugLog(@"MetricKit data collection enabled."); + _metricKitManager = [[FIRCLSMetricKitManager alloc] initWithManagerData:managerData + existingReportManager:existingReportManager + fileManager:_fileManager]; + } + } +#endif + + _launchMarker = [[FIRCLSLaunchMarkerModel alloc] initWithFileManager:_fileManager]; + + return self; +} + +// This method returns a promise that is resolved with a wrapped FirebaseReportAction once the user +// has indicated whether they want to upload currently cached reports. This method should only be +// called when we have determined there is at least 1 unsent report. This method waits until either: +// 1. Data collection becomes enabled, in which case, the promise will be resolved with Send. +// 2. The developer uses the processCrashReports API to indicate whether the report +// should be sent or deleted, at which point the promise will be resolved with the action. +- (FBLPromise *)waitForReportAction { + FIRCrashlyticsReport *unsentReport = self.existingReportManager.newestUnsentReport; + [_unsentReportsAvailable fulfill:unsentReport]; + + // If data collection gets enabled while we are waiting for an action, go ahead and send the + // reports, and any subsequent explicit response will be ignored. + FBLPromise *collectionEnabled = + [[self.dataArbiter waitForCrashlyticsCollectionEnabled] + then:^id _Nullable(NSNumber *_Nullable value) { + return @(FIRCLSReportActionSend); + }]; + + // Wait for either the processReports callback to be called, or data collection to be enabled. + return [FBLPromise race:@[ collectionEnabled, _reportActionProvided ]]; +} + +/* + * This method returns a promise that is resolved once + * MetricKit diagnostic reports have been received by `metricKitManager`. + */ +- (FBLPromise *)waitForMetricKitData { + // If the platform is not iOS or the iOS version is less than 15, immediately resolve the promise + // since no MetricKit diagnostics will be available. + FBLPromise *promise = [FBLPromise resolvedWith:nil]; +#if CLS_METRICKIT_SUPPORTED + if (@available(iOS 15, *)) { + if (self.settings.metricKitCollectionEnabled) { + promise = [self.metricKitManager waitForMetricKitDataAvailable]; + } + } + return promise; +#endif + return promise; +} + +- (FBLPromise *)checkForUnsentReports { + bool expectedCalled = NO; + if (!atomic_compare_exchange_strong(&_checkForUnsentReportsCalled, &expectedCalled, YES)) { + FIRCLSErrorLog(@"Either checkForUnsentReports or checkAndUpdateUnsentReports should be called " + @"once per execution."); + return [FBLPromise resolvedWith:nil]; + } + return _unsentReportsAvailable; +} + +- (FBLPromise *)sendUnsentReports { + [_reportActionProvided fulfill:@(FIRCLSReportActionSend)]; + return _unsentReportsHandled; +} + +- (FBLPromise *)deleteUnsentReports { + [_reportActionProvided fulfill:@(FIRCLSReportActionDelete)]; + return _unsentReportsHandled; +} + +- (FBLPromise *)startWithProfiling { + NSString *executionIdentifier = self.executionIDModel.executionID; + + // This needs to be called before the new report is created for + // this run of the app. + [self.existingReportManager collectExistingReports]; + + if (![self validateAppIdentifiers]) { + return [FBLPromise resolvedWith:@NO]; + } + +#if DEBUG + FIRCLSDebugLog(@"Root: %@", [_fileManager rootPath]); +#endif + + if (![_fileManager createReportDirectories]) { + return [FBLPromise resolvedWith:@NO]; + } + + BOOL launchFailure = [self.launchMarker checkForAndCreateLaunchMarker]; + + FIRCLSInternalReport *report = [self setupCurrentReport:executionIdentifier]; + if (!report) { + FIRCLSErrorLog(@"Unable to setup a new report"); + } + + if (![self startCrashReporterWithProfilingReport:report]) { + FIRCLSErrorLog(@"Unable to start crash reporter"); + report = nil; + } + +#if CLS_METRICKIT_SUPPORTED + if (@available(iOS 15, *)) { + if (self.settings.metricKitCollectionEnabled) { + [self.metricKitManager registerMetricKitManager]; + } + } +#endif + + FBLPromise *promise; + + if ([self.dataArbiter isCrashlyticsCollectionEnabled]) { + FIRCLSDebugLog(@"Automatic data collection is enabled."); + FIRCLSDebugLog(@"Unsent reports will be uploaded at startup"); + FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken]; + + [self beginSettingsWithToken:dataCollectionToken]; + + // Wait for MetricKit data to be available, then continue to send reports and resolve promise. + promise = [[self waitForMetricKitData] + onQueue:_dispatchQueue + then:^id _Nullable(id _Nullable metricKitValue) { + [self beginReportUploadsWithToken:dataCollectionToken blockingSend:launchFailure]; + + // If data collection is enabled, the SDK will not notify the user + // when unsent reports are available, or respect Send / DeleteUnsentReports + [self->_unsentReportsAvailable fulfill:nil]; + return @(report != nil); + }]; + } else { + FIRCLSDebugLog(@"Automatic data collection is disabled."); + FIRCLSDebugLog(@"[Crashlytics:Crash] %d unsent reports are available. Waiting for " + @"send/deleteUnsentReports to be called.", + self.existingReportManager.unsentReportsCount); + + // Wait for an action to get sent, either from processReports: or automatic data collection, + // and for MetricKit data to be available. + promise = [[FBLPromise all:@[ [self waitForReportAction], [self waitForMetricKitData] ]] + onQueue:_dispatchQueue + then:^id _Nullable(NSArray *_Nullable wrappedActionAndData) { + // Process the actions for the reports on disk. + FIRCLSReportAction action = [[wrappedActionAndData firstObject] reportActionValue]; + + if (action == FIRCLSReportActionSend) { + FIRCLSDebugLog(@"Sending unsent reports."); + FIRCLSDataCollectionToken *dataCollectionToken = + [FIRCLSDataCollectionToken validToken]; + + [self beginSettingsWithToken:dataCollectionToken]; + + [self beginReportUploadsWithToken:dataCollectionToken blockingSend:NO]; + + } else if (action == FIRCLSReportActionDelete) { + FIRCLSDebugLog(@"Deleting unsent reports."); + [self.existingReportManager deleteUnsentReports]; + } else { + FIRCLSErrorLog(@"Unknown report action: %d", action); + } + return @(report != nil); + }]; + } + + if (report != nil) { + // empty for disabled start-up time + dispatch_async(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSStartTimeKey, @""); + }); + } + + // To make the code more predictable and therefore testable, don't resolve the startup promise + // until the operations that got queued up for processing reports have been processed through the + // work queue. + NSOperationQueue *__weak queue = _operationQueue; + FBLPromise *__weak unsentReportsHandled = _unsentReportsHandled; + promise = [promise then:^id _Nullable(NSNumber *_Nullable value) { + FBLPromise *allOpsFinished = [FBLPromise pendingPromise]; + [queue addOperationWithBlock:^{ + [allOpsFinished fulfill:nil]; + }]; + + return [allOpsFinished onQueue:dispatch_get_main_queue() + then:^id _Nullable(id _Nullable allOpsFinishedValue) { + // Signal that to callers of processReports that everything is + // finished. + [unsentReportsHandled fulfill:nil]; + return value; + }]; + }]; + + return promise; +} + +- (void)beginSettingsWithToken:(FIRCLSDataCollectionToken *)token { + if (self.settings.isCacheExpired) { + // This method can be called more than once if the user calls + // SendUnsentReports again, so don't repeat the settings fetch + static dispatch_once_t settingsFetchOnceToken; + dispatch_once(&settingsFetchOnceToken, ^{ + [self.settingsManager beginSettingsWithGoogleAppId:self.googleAppID token:token]; + }); + } +} + +- (void)beginReportUploadsWithToken:(FIRCLSDataCollectionToken *)token + blockingSend:(BOOL)blockingSend { + if (self.settings.collectReportsEnabled) { + [self.existingReportManager sendUnsentReportsWithToken:token asUrgent:blockingSend]; + + } else { + FIRCLSInfoLog(@"Collect crash reports is disabled"); + [self.existingReportManager deleteUnsentReports]; + } +} + +- (BOOL)startCrashReporterWithProfilingReport:(FIRCLSInternalReport *)report { + if (!report) { + return NO; + } + + if (![self.contextManager setupContextWithReport:report + settings:self.settings + fileManager:_fileManager]) { + return NO; + } + + [self.notificationManager registerNotificationListener]; + + [self.analyticsManager registerAnalyticsListener]; + + [self crashReportingSetupCompleted]; + + return YES; +} + +- (void)crashReportingSetupCompleted { + // check our handlers + FIRCLSDispatchAfter(2.0, dispatch_get_main_queue(), ^{ + FIRCLSExceptionCheckHandlers((__bridge void *)(self)); +#if CLS_SIGNAL_SUPPORTED + FIRCLSSignalCheckHandlers(); +#endif +#if CLS_MACH_EXCEPTION_SUPPORTED + FIRCLSMachExceptionCheckHandlers(); +#endif + }); + + // remove the launch failure marker and records and empty string since + // we're avoiding mach_absolute_time calls. + dispatch_async(dispatch_get_main_queue(), ^{ + [self.launchMarker removeLaunchFailureMarker]; + dispatch_async(FIRCLSGetLoggingQueue(), ^{ + FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSFirstRunloopTurnTimeKey, @""); + }); + }); +} + +- (BOOL)validateAppIdentifiers { + // When the ApplicationIdentifierModel fails to initialize, it is usually due to + // failing computeExecutableInfo. This can happen if the user sets the + // Exported Symbols File in Build Settings, and leaves off the one symbol + // that Crashlytics needs, "__mh_execute_header" (which is defined in mach-o/ldsyms.h as + // _MH_EXECUTE_SYM). From https://github.com/firebase/firebase-ios-sdk/issues/5020 + if (!self.appIDModel) { + FIRCLSErrorLog(@"Crashlytics could not find the symbol for the app's main function and cannot " + @"start up. This can be resolved 2 ways depending on your setup:\n 1. If you " + @"have Exported Symbols File set in your Build Settings, add " + @"\"__mh_execute_header\" as a newline in your Exported Symbols File.\n 2. If " + @"you have -exported_symbols_list in your linker flags, remove it."); + return NO; + } + + if (self.appIDModel.bundleID.length == 0) { + FIRCLSErrorLog(@"An application must have a valid bundle identifier in its Info.plist"); + return NO; + } + + if ([self.dataArbiter isLegacyDataCollectionKeyInPlist]) { + FIRCLSErrorLog(@"Found legacy data collection key in app's Info.plist: " + @"firebase_crashlytics_collection_enabled"); + FIRCLSErrorLog(@"Please update your Info.plist to use the new data collection key: " + @"FirebaseCrashlyticsCollectionEnabled"); + FIRCLSErrorLog(@"The legacy data collection Info.plist value could be overridden by " + @"calling: [Fabric with:...]"); + FIRCLSErrorLog(@"The new value can be overridden by calling: [[FIRCrashlytics " + @"crashlytics] setCrashlyticsCollectionEnabled:]"); + + return NO; + } + + return YES; +} + +- (FIRCLSInternalReport *)setupCurrentReport:(NSString *)executionIdentifier { + [self.launchMarker createLaunchFailureMarker]; + + NSString *reportPath = [_fileManager setupNewPathForExecutionIdentifier:executionIdentifier]; + + return [[FIRCLSInternalReport alloc] initWithPath:reportPath + executionIdentifier:executionIdentifier]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h new file mode 100644 index 0000000..5aa49dd --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h @@ -0,0 +1,32 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h" + +@class FIRCLSInstallIdentifierModel; + +@interface FIRCLSReportManager () + +@property(nonatomic, strong) NSOperationQueue *operationQueue; +@property(nonatomic, strong) FIRCLSFileManager *fileManager; + +@end + +@interface FIRCLSReportManager (PrivateMethods) + +@property(nonatomic, strong) FIRCLSLaunchMarkerModel *launchMarker; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h new file mode 100644 index 0000000..3723a50 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h @@ -0,0 +1,42 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRCLSDataCollectionToken; +@class FIRCLSInternalReport; +@class FIRCLSManagerData; +@class FIRCLSFileManager; + +@interface FIRCLSReportUploader : NSObject + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData NS_DESIGNATED_INITIALIZER; + +@property(nonatomic, readonly) NSOperationQueue *operationQueue; +@property(nonatomic, readonly) FIRCLSFileManager *fileManager; +@property(nonatomic, copy) NSString *fiid; +@property(nonatomic, copy) NSString *authToken; + +- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent + withProcessing:(BOOL)shouldProcess; + +- (void)uploadPackagedReportAtPath:(NSString *)path + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.m new file mode 100644 index 0000000..d9d6b90 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.m @@ -0,0 +1,239 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h" +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h" +#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h" + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h" + +#import + +@interface FIRCLSReportUploader () { + id _analytics; +} + +@property(nonatomic, strong) GDTCORTransport *googleTransport; +@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel; + +@property(nonatomic, readonly) NSString *googleAppID; + +@end + +@implementation FIRCLSReportUploader + +- (instancetype)initWithManagerData:(FIRCLSManagerData *)managerData { + self = [super init]; + if (!self) { + return nil; + } + + _operationQueue = managerData.operationQueue; + _googleAppID = managerData.googleAppID; + _googleTransport = managerData.googleTransport; + _installIDModel = managerData.installIDModel; + _fileManager = managerData.fileManager; + _analytics = managerData.analytics; + + return self; +} + +#pragma mark - Packaging and Submission + +/* + * For a crash report, this is the initial code path for uploading. A report + * will not repeat this code path after it's happened because this code path + * will move the report from the "active" folder into "processing" and then + * "prepared". Once in prepared, the report can be re-uploaded any number of times + * with uploadPackagedReportAtPath in the case of an upload failure. + */ +- (void)prepareAndSubmitReport:(FIRCLSInternalReport *)report + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent + withProcessing:(BOOL)shouldProcess { + if (![dataCollectionToken isValid]) { + FIRCLSErrorLog(@"Data collection disabled and report will not be submitted"); + return; + } + + // This activity is still relevant using GoogleDataTransport because the on-device + // symbolication operation may be computationally intensive. + FIRCLSApplicationActivity( + FIRCLSApplicationActivityDefault, @"Crashlytics Crash Report Processing", ^{ + // Check to see if the FID has rotated before we construct the payload + // so that the payload has an updated value. + // + // If we're in urgent mode, this will be running on the main thread. Since + // the FIID callback is run on the main thread, this call can deadlock in + // urgent mode. Since urgent mode happens when the app is in a crash loop, + // we can safely assume users aren't rotating their FIID, so this can be skipped. + if (!urgent) { + [self.installIDModel regenerateInstallIDIfNeededWithBlock:^( + NSString *_Nonnull newFIID, NSString *_Nonnull authToken) { + self.fiid = [newFIID copy]; + self.authToken = [authToken copy]; + }]; + } else { + FIRCLSWarningLog( + @"Crashlytics skipped rotating the Install ID during urgent mode because it is run " + @"on the main thread, which can't succeed. This can happen if the app crashed the " + @"last run and Crashlytics is uploading urgently."); + } + + // Run on-device symbolication before packaging if we should process + if (shouldProcess) { + if (![self.fileManager moveItemAtPath:report.path + toDirectory:self.fileManager.processingPath]) { + FIRCLSErrorLog(@"Unable to move report for processing"); + return; + } + + // adjust the report's path, and process it + [report setPath:[self.fileManager.processingPath + stringByAppendingPathComponent:report.directoryName]]; + + FIRCLSSymbolResolver *resolver = [[FIRCLSSymbolResolver alloc] init]; + + FIRCLSProcessReportOperation *processOperation = + [[FIRCLSProcessReportOperation alloc] initWithReport:report resolver:resolver]; + + [processOperation start]; + } + + // With the new report endpoint, the report is deleted once it is written to GDT + // Check if the report has a crash file before the report is moved or deleted + BOOL isCrash = report.isCrash; + + // For the new endpoint, just move the .clsrecords from "processing" -> "prepared". + // In the old endpoint this was for packaging the report as a multipartmime file, + // so this can probably be removed for GoogleDataTransport. + if (![self.fileManager moveItemAtPath:report.path + toDirectory:self.fileManager.preparedPath]) { + FIRCLSErrorLog(@"Unable to move report to prepared"); + return; + } + + NSString *packagedPath = [self.fileManager.preparedPath + stringByAppendingPathComponent:report.path.lastPathComponent]; + + FIRCLSInfoLog(@"[Firebase/Crashlytics] Packaged report with id '%@' for submission", + report.identifier); + + [self uploadPackagedReportAtPath:packagedPath + dataCollectionToken:dataCollectionToken + asUrgent:urgent]; + + // We don't check for success here for 2 reasons: + // 1) If we can't upload a crash for whatever reason, but we can upload analytics + // it's better for the customer to get accurate Crash Free Users. + // 2) In the past we did try to check for success, but it was a useless check because + // sendDataEvent is async (unless we're sending urgently). + if (isCrash) { + [FIRCLSAnalyticsManager logCrashWithTimeStamp:report.crashedOnDate.timeIntervalSince1970 + toAnalytics:self->_analytics]; + } + }); + + return; +} + +/* + * This code path can be repeated any number of times for a prepared crash report if + * the report is failing to upload. + * + * Therefore, side effects (like logging to Analytics) should not go in this method or + * else they will re-trigger when failures happen. + * + * When a crash report fails to upload, it will stay in the "prepared" folder. Upon next + * run of the app, the ReportManager will attempt to re-upload prepared reports using this + * method. + */ +- (void)uploadPackagedReportAtPath:(NSString *)path + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent { + FIRCLSDebugLog(@"Submitting report %@", urgent ? @"urgently" : @"async"); + + if (![dataCollectionToken isValid]) { + FIRCLSErrorLog(@"A report upload was requested with an invalid data collection token."); + return; + } + + FIRCLSReportAdapter *adapter = [[FIRCLSReportAdapter alloc] initWithPath:path + googleAppId:self.googleAppID + installIDModel:self.installIDModel + fiid:self.fiid + authToken:self.authToken]; + + GDTCOREvent *event = [self.googleTransport eventForTransport]; + event.dataObject = adapter; + event.qosTier = GDTCOREventQoSFast; // Bypass batching, send immediately + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + + [self.googleTransport + sendDataEvent:event + onComplete:^(BOOL wasWritten, NSError *error) { + if (!wasWritten) { + FIRCLSErrorLog( + @"Failed to send crash report due to failure writing GoogleDataTransport event"); + dispatch_semaphore_signal(semaphore); + return; + } + + if (error) { + FIRCLSErrorLog(@"Failed to send crash report due to GoogleDataTransport error: %@", + error.localizedDescription); + dispatch_semaphore_signal(semaphore); + return; + } + + FIRCLSInfoLog(@"Completed report submission with id: %@", path.lastPathComponent); + + if (urgent) { + dispatch_semaphore_signal(semaphore); + } + + [self cleanUpSubmittedReportAtPath:path]; + }]; + + if (urgent) { + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + } +} + +- (BOOL)cleanUpSubmittedReportAtPath:(NSString *)path { + if (![[self fileManager] removeItemAtPath:path]) { + FIRCLSErrorLog(@"Unable to remove packaged submission"); + return NO; + } + + return YES; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h new file mode 100644 index 0000000..020890d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader_Private.h @@ -0,0 +1,23 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h" + +@interface FIRCLSReportUploader (PrivateMethods) + +@property(nonatomic, readonly) NSURL *reportURL; + +- (NSMutableURLRequest *)mutableRequestWithURL:(NSURL *)url timeout:(NSTimeInterval)timeout; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.h new file mode 100644 index 0000000..adbac49 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.h @@ -0,0 +1,36 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SWIFT_PACKAGE +@import FirebaseCrashlyticsSwift; +#elif __has_include() +#import +#elif __has_include("FirebaseCrashlytics-Swift.h") +// If frameworks are not available, fall back to importing the header as it +// should be findable from a header search path pointing to the build +// directory. See #12611 for more context. +#import "FirebaseCrashlytics-Swift.h" +#endif + +@interface FIRCLSRolloutsPersistenceManager : NSObject + +- (instancetype _Nullable)initWithFileManager:(FIRCLSFileManager *_Nonnull)fileManager + andQueue:(dispatch_queue_t _Nonnull)queue; +- (instancetype _Nonnull)init NS_UNAVAILABLE; ++ (instancetype _Nonnull)new NS_UNAVAILABLE; + +- (void)updateRolloutsStateToPersistenceWithRollouts:(NSData *_Nonnull)rollouts + reportID:(NSString *_Nonnull)reportID; +- (void)debugLogWithMessage:(NSString *_Nonnull)message; +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.m new file mode 100644 index 0000000..3087607 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.m @@ -0,0 +1,91 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" + +#if SWIFT_PACKAGE +@import FirebaseCrashlyticsSwift; +#elif __has_include() +#import +#elif __has_include("FirebaseCrashlytics-Swift.h") +// If frameworks are not available, fall back to importing the header as it +// should be findable from a header search path pointing to the build +// directory. See #12611 for more context. +#import "FirebaseCrashlytics-Swift.h" +#endif + +@interface FIRCLSRolloutsPersistenceManager : NSObject +@property(nonatomic, readonly) FIRCLSFileManager *fileManager; +@property(nonnull, nonatomic, readonly) dispatch_queue_t rolloutsLoggingQueue; +@end + +@implementation FIRCLSRolloutsPersistenceManager +- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager + andQueue:(dispatch_queue_t)queue { + self = [super init]; + if (!self) { + return nil; + } + _fileManager = fileManager; + + if (!queue) { + FIRCLSDebugLog(@"Failed to initialize FIRCLSRolloutsPersistenceManager, logging queue is nil"); + return nil; + } + _rolloutsLoggingQueue = queue; + return self; +} + +- (void)updateRolloutsStateToPersistenceWithRollouts:(NSData *_Nonnull)rollouts + reportID:(NSString *_Nonnull)reportID { + NSString *rolloutsPath = [[[_fileManager activePath] stringByAppendingPathComponent:reportID] + stringByAppendingPathComponent:FIRCLSReportRolloutsFile]; + if (![_fileManager fileExistsAtPath:rolloutsPath]) { + if (![_fileManager createFileAtPath:rolloutsPath contents:nil attributes:nil]) { + FIRCLSDebugLog(@"Could not create rollouts.clsrecord file. Error was code: %d - message: %s", + errno, strerror(errno)); + return; + } + } + + NSFileHandle *rolloutsFile = [NSFileHandle fileHandleForUpdatingAtPath:rolloutsPath]; + + if (!_rolloutsLoggingQueue) { + FIRCLSDebugLog(@"Rollouts logging queue is dealloccated"); + return; + } + + dispatch_async(_rolloutsLoggingQueue, ^{ + @try { + [rolloutsFile seekToEndOfFile]; + NSMutableData *rolloutsWithNewLineData = [rollouts mutableCopy]; + [rolloutsWithNewLineData appendData:[@"\n" dataUsingEncoding:NSUTF8StringEncoding]]; + [rolloutsFile writeData:rolloutsWithNewLineData]; + [rolloutsFile closeFile]; + } @catch (NSException *exception) { + FIRCLSDebugLog(@"Failed to write new rollouts. Exception name: %s - message: %s", + exception.name, exception.reason); + } + }); +} + +- (void)debugLogWithMessage:(NSString *_Nonnull)message { + FIRCLSDebugLog(message); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h new file mode 100644 index 0000000..147bc7b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h @@ -0,0 +1,39 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRApp; +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSDataCollectionArbiter : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithApp:(FIRApp *)app withAppInfo:(NSDictionary *)dict; + +- (BOOL)isLegacyDataCollectionKeyInPlist; + +- (BOOL)isCrashlyticsCollectionEnabled; + +- (void)setCrashlyticsCollectionEnabled:(BOOL)enabled; + +// Returns a promise that is fulfilled once data collection is enabled. +- (FBLPromise *)waitForCrashlyticsCollectionEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.m new file mode 100644 index 0000000..834e7e8 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.m @@ -0,0 +1,147 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" + +// The legacy data collection setting allows Fabric customers to turn off auto- +// initialization, but can be overridden by calling [Fabric with:]. +// +// While we support Fabric, we must have two different versions, because +// they require these slightly different semantics. +NSString *const FIRCLSLegacyCrashlyticsCollectionKey = @"firebase_crashlytics_collection_enabled"; + +// The new data collection setting can be set by an API that is stored in FIRCLSUserDefaults +NSString *const FIRCLSDataCollectionEnabledKey = @"com.crashlytics.data_collection"; + +// The new data collection setting also allows Firebase customers to turn off data +// collection in their Info.plist, and can be overridden by setting it to true using +// the setCrashlyticsCollectionEnabled API. +NSString *const FIRCLSCrashlyticsCollectionKey = @"FirebaseCrashlyticsCollectionEnabled"; + +typedef NS_ENUM(NSInteger, FIRCLSDataCollectionSetting) { + FIRCLSDataCollectionSettingNotSet = 0, + FIRCLSDataCollectionSettingEnabled = 1, + FIRCLSDataCollectionSettingDisabled = 2, +}; + +@interface FIRCLSDataCollectionArbiter () { + NSLock *_mutex; + FBLPromise *_dataCollectionEnabled; + BOOL _promiseResolved; + FIRApp *_app; + NSDictionary *_appInfo; +} +@end + +@implementation FIRCLSDataCollectionArbiter + +- (instancetype)initWithApp:(FIRApp *)app withAppInfo:(NSDictionary *)dict { + self = [super init]; + if (self) { + _mutex = [[NSLock alloc] init]; + _appInfo = dict; + _app = app; + if ([FIRCLSDataCollectionArbiter isCrashlyticsCollectionEnabledWithApp:app withAppInfo:dict]) { + _dataCollectionEnabled = [FBLPromise resolvedWith:nil]; + _promiseResolved = YES; + } else { + _dataCollectionEnabled = [FBLPromise pendingPromise]; + _promiseResolved = NO; + } + } + + return self; +} + +/* + * Legacy collection key that we provide for customers to disable Crash reporting. + * Customers can later turn on Crashlytics using Fabric.with if they choose to do so. + * + * This flag is unsupported for the "New SDK" + */ +- (BOOL)isLegacyDataCollectionKeyInPlist { + if ([_appInfo objectForKey:FIRCLSLegacyCrashlyticsCollectionKey]) { + return true; + } + + return false; +} + +// This functionality is called in the initializer before self is fully initialized, +// so a class method is used. The instance method below allows for a consistent clean API. ++ (BOOL)isCrashlyticsCollectionEnabledWithApp:(FIRApp *)app withAppInfo:(NSDictionary *)dict { + FIRCLSDataCollectionSetting stickySetting = [FIRCLSDataCollectionArbiter stickySetting]; + if (stickySetting != FIRCLSDataCollectionSettingNotSet) { + return stickySetting == FIRCLSDataCollectionSettingEnabled; + } + + id firebaseCrashlyticsCollectionEnabled = [dict objectForKey:FIRCLSCrashlyticsCollectionKey]; + if ([firebaseCrashlyticsCollectionEnabled isKindOfClass:[NSString class]] || + [firebaseCrashlyticsCollectionEnabled isKindOfClass:[NSNumber class]]) { + return [firebaseCrashlyticsCollectionEnabled boolValue]; + } + return [app isDataCollectionDefaultEnabled]; +} + +- (BOOL)isCrashlyticsCollectionEnabled { + return [FIRCLSDataCollectionArbiter isCrashlyticsCollectionEnabledWithApp:_app + withAppInfo:_appInfo]; +} + +- (void)setCrashlyticsCollectionEnabled:(BOOL)enabled { + FIRCLSUserDefaults *userDefaults = [FIRCLSUserDefaults standardUserDefaults]; + FIRCLSDataCollectionSetting setting = + enabled ? FIRCLSDataCollectionSettingEnabled : FIRCLSDataCollectionSettingDisabled; + [userDefaults setInteger:setting forKey:FIRCLSDataCollectionEnabledKey]; + [userDefaults synchronize]; + + [_mutex lock]; + if (enabled) { + if (!_promiseResolved) { + [_dataCollectionEnabled fulfill:nil]; + _promiseResolved = YES; + } + } else { + if (_promiseResolved) { + _dataCollectionEnabled = [FBLPromise pendingPromise]; + _promiseResolved = NO; + } + } + [_mutex unlock]; +} + ++ (FIRCLSDataCollectionSetting)stickySetting { + FIRCLSUserDefaults *userDefaults = [FIRCLSUserDefaults standardUserDefaults]; + return [userDefaults integerForKey:FIRCLSDataCollectionEnabledKey]; +} + +- (FBLPromise *)waitForCrashlyticsCollectionEnabled { + FBLPromise *result = nil; + [_mutex lock]; + result = _dataCollectionEnabled; + [_mutex unlock]; + return result; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h new file mode 100644 index 0000000..769164b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h @@ -0,0 +1,46 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A FIRCLSDataCollectionToken represents having permission to upload data. A data collection token + * is either valid or nil. Every function that directly initiates a network operation that will + * result in data collection must check to make sure it has been passed a valid token. Tokens should + * only be created when either (1) automatic data collection is enabled, or (2) the user has + * explicitly given permission to collect data for a particular purpose, using the API. For all the + * functions in between, the data collection token getting passed as an argument helps to document + * and enforce the flow of data collection permission through the SDK. + */ +@interface FIRCLSDataCollectionToken : NSObject + +/** + * Creates a valid token. Only call this method when either (1) automatic data collection is + * enabled, or (2) the user has explicitly given permission to collect data for a particular + * purpose, using the API. + */ ++ (instancetype)validToken; + +/** + * Use this to verify that a token is valid. If this is called on a nil instance, it will return + * false. + * @return true. + */ +- (BOOL)isValid; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.m new file mode 100644 index 0000000..5dbde6e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.m @@ -0,0 +1,27 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" + +@implementation FIRCLSDataCollectionToken + ++ (instancetype)validToken { + return [[FIRCLSDataCollectionToken alloc] init]; +} + +- (BOOL)isValid { + return YES; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h new file mode 100644 index 0000000..6df1532 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h @@ -0,0 +1,42 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +extern NSString *const FIRCLSUserDefaultsPathComponent; + +@interface FIRCLSUserDefaults : NSObject + ++ (instancetype)standardUserDefaults; + +- (id)objectForKey:(NSString *)key; +- (NSString *)stringForKey:(NSString *)key; +- (BOOL)boolForKey:(NSString *)key; +- (NSInteger)integerForKey:(NSString *)key; + +- (void)setObject:(id)object forKey:(NSString *)key; +- (void)setString:(NSString *)string forKey:(NSString *)key; +- (void)setBool:(BOOL)boolean forKey:(NSString *)key; +- (void)setInteger:(NSInteger)integer forKey:(NSString *)key; + +- (void)removeObjectForKey:(NSString *)key; +- (void)removeAllObjects; + +- (NSDictionary *)dictionaryRepresentation; + +- (void)migrateFromNSUserDefaults:(NSArray *)keysToMigrate; +- (id)objectForKeyByMigratingFromNSUserDefaults:(NSString *)keyToMigrateOrNil; +- (void)synchronize; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.m new file mode 100644 index 0000000..a9b4577 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.m @@ -0,0 +1,372 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" + +#define CLS_USER_DEFAULTS_SERIAL_DISPATCH_QUEUE "com.crashlytics.CLSUserDefaults.access" +#define CLS_USER_DEFAULTS_SYNC_QUEUE "com.crashlytics.CLSUserDefaults.io" + +#define CLS_TARGET_CAN_WRITE_TO_DISK !TARGET_OS_TV + +// These values are required to stay the same between versions of the SDK so +// that when end users upgrade, their crashlytics data is still saved on disk. +#if !CLS_TARGET_CAN_WRITE_TO_DISK +static NSString *const FIRCLSNSUserDefaultsDataDictionaryKey = + @"com.crashlytics.CLSUserDefaults.user-default-key.data-dictionary"; +#endif + +NSString *const FIRCLSUserDefaultsPathComponent = @"CLSUserDefaults"; + +/** + * This class is an isolated re-implementation of UserDefaults which isolates our storage + * from that of our customers. This solves a number of issues we have seen in production, firstly + * that customers often delete or clear UserDefaults, unintentionally deleting our data. + * Further, we have seen thread safety issues in production with UserDefaults, as well as a number + * of bugs related to accessing UserDefaults before the device has been unlocked due to the + * FileProtection of UserDefaults. + */ +@interface FIRCLSUserDefaults () +@property(nonatomic, readwrite) BOOL synchronizeWroteToDisk; +#if CLS_TARGET_CAN_WRITE_TO_DISK +@property(nonatomic, copy, readonly) NSURL *directoryURL; +@property(nonatomic, copy, readonly) NSURL *fileURL; +#endif +@property(nonatomic, copy, readonly) + NSDictionary *persistedDataDictionary; // May only be safely accessed on the DictionaryQueue +@property(nonatomic, copy, readonly) + NSMutableDictionary *dataDictionary; // May only be safely accessed on the DictionaryQueue +@property(nonatomic, readonly) dispatch_queue_t + serialDictionaryQueue; // The queue on which all access to the dataDictionary occurs. +@property(nonatomic, readonly) + dispatch_queue_t synchronizationQueue; // The queue on which all disk access occurs. + +@end + +@implementation FIRCLSUserDefaults + +#pragma mark - singleton + ++ (instancetype)standardUserDefaults { + static FIRCLSUserDefaults *standardUserDefaults = nil; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + standardUserDefaults = [[super allocWithZone:NULL] init]; + }); + + return standardUserDefaults; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; +} + +- (id)init { + if (self = [super init]) { + _serialDictionaryQueue = + dispatch_queue_create(CLS_USER_DEFAULTS_SERIAL_DISPATCH_QUEUE, DISPATCH_QUEUE_SERIAL); + _synchronizationQueue = + dispatch_queue_create(CLS_USER_DEFAULTS_SYNC_QUEUE, DISPATCH_QUEUE_SERIAL); + + dispatch_sync(self.serialDictionaryQueue, ^{ +#if CLS_TARGET_CAN_WRITE_TO_DISK + self->_directoryURL = [self generateDirectoryURL]; + self->_fileURL = [[self->_directoryURL + URLByAppendingPathComponent:FIRCLSUserDefaultsPathComponent + isDirectory:NO] URLByAppendingPathExtension:@"plist"]; +#endif + self->_persistedDataDictionary = [self loadDefaults]; + if (!self->_persistedDataDictionary) { + self->_persistedDataDictionary = [NSDictionary dictionary]; + } + self->_dataDictionary = [self->_persistedDataDictionary mutableCopy]; + }); + } + return self; +} + +- (NSURL *)generateDirectoryURL { + NSURL *directoryBaseURL = + [[[NSFileManager defaultManager] URLsForDirectory:NSApplicationSupportDirectory + inDomains:NSUserDomainMask] lastObject]; + NSString *hostAppBundleIdentifier = [self getEscapedAppBundleIdentifier]; + return [self generateDirectoryURLForBaseURL:directoryBaseURL + hostAppBundleIdentifier:hostAppBundleIdentifier]; +} + +- (NSURL *)generateDirectoryURLForBaseURL:(NSURL *)directoryBaseURL + hostAppBundleIdentifier:(NSString *)hostAppBundleIdentifier { + NSURL *directoryURL = directoryBaseURL; + // On iOS NSApplicationSupportDirectory is contained in the app's bundle. On OSX, it is not (it is + // ~/Library/Application Support/). On OSX we create a directory + // ~/Library/Application Support//com.crashlytics/ for storing files. + // Mac App Store review process requires files to be written to + // ~/Library/Application Support//, + // so ~/Library/Application Support/com.crashlytics// cannot be used. +#if !TARGET_OS_SIMULATOR && !TARGET_OS_EMBEDDED + if (hostAppBundleIdentifier) { + directoryURL = [directoryURL URLByAppendingPathComponent:hostAppBundleIdentifier]; + } +#endif + directoryURL = [directoryURL URLByAppendingPathComponent:@"com.crashlytics"]; + return directoryURL; +} + +- (NSString *)getEscapedAppBundleIdentifier { + return FIRCLSApplicationGetBundleIdentifier(); +} + +#pragma mark - fetch object + +- (id)objectForKey:(NSString *)key { + __block id result; + + dispatch_sync(self.serialDictionaryQueue, ^{ + result = [self->_dataDictionary objectForKey:key]; + }); + + return result; +} + +- (NSString *)stringForKey:(NSString *)key { + id result = [self objectForKey:key]; + + if (result != nil && [result isKindOfClass:[NSString class]]) { + return (NSString *)result; + } else { + return nil; + } +} + +- (BOOL)boolForKey:(NSString *)key { + id result = [self objectForKey:key]; + if (result != nil && [result isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)result boolValue]; + } else { + return NO; + } +} + +// Defaults to 0 +- (NSInteger)integerForKey:(NSString *)key { + id result = [self objectForKey:key]; + if (result && [result isKindOfClass:[NSNumber class]]) { + return [(NSNumber *)result integerValue]; + } else { + return 0; + } +} + +#pragma mark - set object + +- (void)setObject:(id)object forKey:(NSString *)key { + dispatch_sync(self.serialDictionaryQueue, ^{ + [self->_dataDictionary setValue:object forKey:key]; + }); +} + +- (void)setString:(NSString *)string forKey:(NSString *)key { + [self setObject:string forKey:key]; +} + +- (void)setBool:(BOOL)boolean forKey:(NSString *)key { + [self setObject:[NSNumber numberWithBool:boolean] forKey:key]; +} + +- (void)setInteger:(NSInteger)integer forKey:(NSString *)key { + [self setObject:[NSNumber numberWithInteger:integer] forKey:key]; +} + +#pragma mark - removing objects + +- (void)removeObjectForKey:(NSString *)key { + dispatch_sync(self.serialDictionaryQueue, ^{ + [self->_dataDictionary removeObjectForKey:key]; + }); +} + +- (void)removeAllObjects { + dispatch_sync(self.serialDictionaryQueue, ^{ + [self->_dataDictionary removeAllObjects]; + }); +} + +#pragma mark - dictionary representation + +- (NSDictionary *)dictionaryRepresentation { + __block NSDictionary *result; + + dispatch_sync(self.serialDictionaryQueue, ^{ + result = [self->_dataDictionary copy]; + }); + + return result; +} + +#pragma mark - synchronization + +- (void)synchronize { + __block BOOL dirty = NO; + + // only write to the disk if the dictionaries have changed + dispatch_sync(self.serialDictionaryQueue, ^{ + dirty = ![self->_persistedDataDictionary isEqualToDictionary:self->_dataDictionary]; + }); + + _synchronizeWroteToDisk = dirty; + if (!dirty) { + return; + } + + NSDictionary *state = [self dictionaryRepresentation]; + dispatch_sync(self.synchronizationQueue, ^{ +#if CLS_TARGET_CAN_WRITE_TO_DISK + BOOL isDirectory = NO; + BOOL pathExists = [[NSFileManager defaultManager] fileExistsAtPath:[self->_directoryURL path] + isDirectory:&isDirectory]; + + if (!pathExists) { + NSError *error; + if (![[NSFileManager defaultManager] createDirectoryAtURL:self->_directoryURL + withIntermediateDirectories:YES + attributes:nil + error:&error]) { + FIRCLSErrorLog(@"Failed to create directory with error: %@", error); + } + } + + if (![state writeToURL:self->_fileURL atomically:YES]) { + FIRCLSErrorLog(@"Unable to open file for writing at path %@", [self->_fileURL path]); + } else { +#if TARGET_OS_IOS + // We disable NSFileProtection on our file in order to allow us to access it even if the + // device is locked. + NSError *error; + if (![[NSFileManager defaultManager] + setAttributes:@{NSFileProtectionKey : NSFileProtectionNone} + ofItemAtPath:[self->_fileURL path] + error:&error]) { + FIRCLSErrorLog(@"Error setting NSFileProtection: %@", error); + } +#endif + } +#else + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + [defaults setObject:state forKey:FIRCLSNSUserDefaultsDataDictionaryKey]; + [defaults synchronize]; +#endif + }); + + dispatch_sync(self.serialDictionaryQueue, ^{ + self->_persistedDataDictionary = [self->_dataDictionary copy]; + }); +} + +- (NSDictionary *)loadDefaults { + __block NSDictionary *state = nil; + dispatch_sync(self.synchronizationQueue, ^{ +#if CLS_TARGET_CAN_WRITE_TO_DISK + BOOL isDirectory = NO; + BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:[self->_fileURL path] + isDirectory:&isDirectory]; + + if (fileExists && !isDirectory) { + state = [NSDictionary dictionaryWithContentsOfURL:self->_fileURL]; + if (nil == state) { + FIRCLSErrorLog(@"Failed to read existing UserDefaults file"); + } + } else if (!fileExists) { + // No file found. This is expected on first launch. + } else if (fileExists && isDirectory) { + FIRCLSErrorLog(@"Found directory where file expected. Removing conflicting directory"); + + NSError *error; + if (![[NSFileManager defaultManager] removeItemAtURL:self->_fileURL error:&error]) { + FIRCLSErrorLog(@"Error removing conflicting directory: %@", error); + } + } +#else + state = [[NSUserDefaults standardUserDefaults] dictionaryForKey:FIRCLSNSUserDefaultsDataDictionaryKey]; +#endif + }); + return state; +} + +#pragma mark - migration + +// This method migrates all keys specified from UserDefaults to FIRCLSUserDefaults +// To do so, we copy all known key-value pairs into FIRCLSUserDefaults, synchronize it, then +// remove the keys from UserDefaults and synchronize it. +- (void)migrateFromNSUserDefaults:(NSArray *)keysToMigrate { + BOOL didFindKeys = NO; + + // First, copy all of the keysToMigrate which are stored UserDefaults + for (NSString *key in keysToMigrate) { + id oldValue = [[NSUserDefaults standardUserDefaults] objectForKey:(NSString *)key]; + if (nil != oldValue) { + didFindKeys = YES; + [self setObject:oldValue forKey:key]; + } + } + + if (didFindKeys) { + // First synchronize FIRCLSUserDefaults such that all keysToMigrate in UserDefaults are stored + // in FIRCLSUserDefaults. At this point, data is duplicated. + [[FIRCLSUserDefaults standardUserDefaults] synchronize]; + + for (NSString *key in keysToMigrate) { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:(NSString *)key]; + } + + // This should be our last interaction with UserDefaults. All data is migrated into + // FIRCLSUserDefaults + [[NSUserDefaults standardUserDefaults] synchronize]; + } +} + +// This method first queries FIRCLSUserDefaults to see if the key exist, and upon failure, +// searches for the key in UserDefaults, and migrates it if found. +- (id)objectForKeyByMigratingFromNSUserDefaults:(NSString *)keyToMigrateOrNil { + if (!keyToMigrateOrNil) { + return nil; + } + + id clsUserDefaultsValue = [self objectForKey:keyToMigrateOrNil]; + if (clsUserDefaultsValue != nil) { + return clsUserDefaultsValue; // if the value exists in FIRCLSUserDefaults, return it. + } + + id oldNSUserDefaultsValue = + [[NSUserDefaults standardUserDefaults] objectForKey:keyToMigrateOrNil]; + if (!oldNSUserDefaultsValue) { + return nil; // if the value also does not exist in UserDefaults, return nil. + } + + // Otherwise, the key exists in UserDefaults. Migrate it to FIRCLSUserDefaults + // and then return the associated value. + + // First store it in FIRCLSUserDefaults so in the event of a crash, data is not lost. + [self setObject:oldNSUserDefaultsValue forKey:keyToMigrateOrNil]; + [[FIRCLSUserDefaults standardUserDefaults] synchronize]; + + [[NSUserDefaults standardUserDefaults] removeObjectForKey:keyToMigrateOrNil]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + return oldNSUserDefaultsValue; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults_private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults_private.h new file mode 100644 index 0000000..b8415d5 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults_private.h @@ -0,0 +1,23 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" + +@interface FIRCLSUserDefaults (Private) +- (BOOL)synchronizeWroteToDisk; +- (NSDictionary *)loadDefaults; +- (NSURL *)generateDirectoryURLForBaseURL:(NSURL *)directoryBaseURL + hostAppBundleIdentifier:(NSString *)hostAppBundleIdentifier; +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlytics.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlytics.m new file mode 100644 index 0000000..1719997 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlytics.m @@ -0,0 +1,448 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Shared/FIRCLSByteUtility.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "Crashlytics/Shared/FIRCLSFABHost.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSContextManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h" +#import "Crashlytics/Crashlytics/Controllers/FIRCLSRolloutsPersistenceManager.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h" +#import "Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +#import + +@import FirebaseSessions; +@import FirebaseRemoteConfigInterop; +#if SWIFT_PACKAGE +@import FirebaseCrashlyticsSwift; +#elif __has_include() +#import +#elif __has_include("FirebaseCrashlytics-Swift.h") +// If frameworks are not available, fall back to importing the header as it +// should be findable from a header search path pointing to the build +// directory. See #12611 for more context. +#import "FirebaseCrashlytics-Swift.h" +#endif + +#if TARGET_OS_IPHONE +#import +#endif + +FIRCLSContext _firclsContext; +dispatch_queue_t _firclsLoggingQueue; +dispatch_queue_t _firclsBinaryImageQueue; +dispatch_queue_t _firclsExceptionQueue; + +static atomic_bool _hasInitializedInstance; + +NSString *const FIRCLSGoogleTransportMappingID = @"1206"; + +/// Empty protocol to register with FirebaseCore's component system. +@protocol FIRCrashlyticsInstanceProvider +@end + +@interface FIRCrashlytics () + +@property(nonatomic) BOOL didPreviouslyCrash; +@property(nonatomic, copy) NSString *googleAppID; +@property(nonatomic) FIRCLSDataCollectionArbiter *dataArbiter; +@property(nonatomic) FIRCLSFileManager *fileManager; + +@property(nonatomic) FIRCLSReportManager *reportManager; + +@property(nonatomic) FIRCLSReportUploader *reportUploader; + +@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager; + +@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager; + +@property(nonatomic, strong) FIRCLSRemoteConfigManager *remoteConfigManager; + +// Dependencies common to each of the Controllers +@property(nonatomic, strong) FIRCLSManagerData *managerData; + +@end + +@implementation FIRCrashlytics + +#pragma mark - Singleton Support + +- (instancetype)initWithApp:(FIRApp *)app + appInfo:(NSDictionary *)appInfo + installations:(FIRInstallations *)installations + analytics:(id)analytics + sessions:(id)sessions + remoteConfig:(id)remoteConfig { + self = [super init]; + + if (self) { + bool expectedCalled = NO; + if (!atomic_compare_exchange_strong(&_hasInitializedInstance, &expectedCalled, YES)) { + FIRCLSErrorLog(@"Cannot instantiate more than one instance of Crashlytics."); + return nil; + } + + NSLog(@"[Firebase/Crashlytics] Version %@", FIRCLSSDKVersion()); + + FIRCLSDeveloperLog("Crashlytics", @"Running on %@, %@ (%@)", FIRCLSHostModelInfo(), + FIRCLSHostOSDisplayVersion(), FIRCLSHostOSBuildVersion()); + + GDTCORTransport *googleTransport = + [[GDTCORTransport alloc] initWithMappingID:FIRCLSGoogleTransportMappingID + transformers:nil + target:kGDTCORTargetCSH]; + + _fileManager = [[FIRCLSFileManager alloc] init]; + _googleAppID = app.options.googleAppID; + _dataArbiter = [[FIRCLSDataCollectionArbiter alloc] initWithApp:app withAppInfo:appInfo]; + + FIRCLSApplicationIdentifierModel *appModel = [[FIRCLSApplicationIdentifierModel alloc] init]; + FIRCLSSettings *settings = [[FIRCLSSettings alloc] initWithFileManager:_fileManager + appIDModel:appModel]; + + FIRCLSOnDemandModel *onDemandModel = + [[FIRCLSOnDemandModel alloc] initWithFIRCLSSettings:settings fileManager:_fileManager]; + _managerData = [[FIRCLSManagerData alloc] initWithGoogleAppID:_googleAppID + googleTransport:googleTransport + installations:installations + analytics:analytics + fileManager:_fileManager + dataArbiter:_dataArbiter + settings:settings + onDemandModel:onDemandModel]; + + if (sessions) { + FIRCLSDebugLog(@"Registering Sessions SDK subscription for session data"); + + // Subscription should be made after the DataCollectionArbiter + // is initialized so that the Sessions SDK can immediately get + // the data collection state. + // + // It should also be made after managerData is initialized so + // that the ContextManager can accept data + [sessions registerWithSubscriber:self]; + } + + _reportUploader = [[FIRCLSReportUploader alloc] initWithManagerData:_managerData]; + + _existingReportManager = + [[FIRCLSExistingReportManager alloc] initWithManagerData:_managerData + reportUploader:_reportUploader]; + + _analyticsManager = [[FIRCLSAnalyticsManager alloc] initWithAnalytics:analytics]; + + _reportManager = [[FIRCLSReportManager alloc] initWithManagerData:_managerData + existingReportManager:_existingReportManager + analyticsManager:_analyticsManager]; + + _didPreviouslyCrash = [_fileManager didCrashOnPreviousExecution]; + // Process did crash during previous execution + if (_didPreviouslyCrash) { + // Delete the crash file marker in the background ensure start up is as fast as possible + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + NSString *crashedMarkerFileFullPath = [[self.fileManager rootPath] + stringByAppendingPathComponent:[NSString + stringWithUTF8String:FIRCLSCrashedMarkerFileName]]; + [self.fileManager removeItemAtPath:crashedMarkerFileFullPath]; + }); + } + + [[[_reportManager startWithProfiling] then:^id _Nullable(NSNumber *_Nullable value) { + if (![value boolValue]) { + FIRCLSErrorLog(@"Crash reporting could not be initialized"); + } + return value; + }] catch:^void(NSError *error) { + FIRCLSErrorLog(@"Crash reporting failed to initialize with error: %@", error); + }]; + + // RemoteConfig subscription should be made after session report directory created. + if (remoteConfig) { + FIRCLSDebugLog(@"Registering RemoteConfig SDK subscription for rollouts data"); + + FIRCLSRolloutsPersistenceManager *persistenceManager = + [[FIRCLSRolloutsPersistenceManager alloc] + initWithFileManager:_fileManager + andQueue:dispatch_queue_create( + "com.google.firebase.FIRCLSRolloutsPersistence", + DISPATCH_QUEUE_SERIAL)]; + _remoteConfigManager = + [[FIRCLSRemoteConfigManager alloc] initWithRemoteConfig:remoteConfig + persistenceDelegate:persistenceManager]; + [remoteConfig registerRolloutsStateSubscriber:self for:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform]; + } + } + return self; +} + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"firebase-crashlytics"]; + [FIRSessionsDependencies addDependencyWithName:FIRSessionsSubscriberNameCrashlytics]; +} + ++ (NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + if (!container.app.isDefaultApp) { + FIRCLSErrorLog(@"Crashlytics must be used with the default Firebase app."); + return nil; + } + + id analytics = FIR_COMPONENT(FIRAnalyticsInterop, container); + id sessions = FIR_COMPONENT(FIRSessionsProvider, container); + id remoteConfig = FIR_COMPONENT(FIRRemoteConfigInterop, container); + + FIRInstallations *installations = [FIRInstallations installationsWithApp:container.app]; + + *isCacheable = YES; + + return [[FIRCrashlytics alloc] initWithApp:container.app + appInfo:NSBundle.mainBundle.infoDictionary + installations:installations + analytics:analytics + sessions:sessions + remoteConfig:remoteConfig]; + }; + + FIRComponent *component = + [FIRComponent componentWithProtocol:@protocol(FIRCrashlyticsInstanceProvider) + instantiationTiming:FIRInstantiationTimingEagerInDefaultApp + creationBlock:creationBlock]; + return @[ component ]; +} + ++ (instancetype)crashlytics { + // The container will return the same instance since isCacheable is set + + FIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here. + + // Get the instance from the `FIRApp`'s container. This will create a new instance the + // first time it is called, and since `isCacheable` is set in the component creation + // block, it will return the existing instance on subsequent calls. + id instance = + FIR_COMPONENT(FIRCrashlyticsInstanceProvider, defaultApp.container); + + // In the component creation block, we return an instance of `FIRCrashlytics`. Cast it and + // return it. + return (FIRCrashlytics *)instance; +} + +- (void)setCrashlyticsCollectionEnabled:(BOOL)enabled { + [self.dataArbiter setCrashlyticsCollectionEnabled:enabled]; +} + +- (BOOL)isCrashlyticsCollectionEnabled { + return [self.dataArbiter isCrashlyticsCollectionEnabled]; +} + +#pragma mark - API: didCrashDuringPreviousExecution + +- (BOOL)didCrashDuringPreviousExecution { + return self.didPreviouslyCrash; +} + +- (void)processDidCrashDuringPreviousExecution { + NSString *crashedMarkerFileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName]; + NSString *crashedMarkerFileFullPath = + [[self.fileManager rootPath] stringByAppendingPathComponent:crashedMarkerFileName]; + self.didPreviouslyCrash = [self.fileManager fileExistsAtPath:crashedMarkerFileFullPath]; + + if (self.didPreviouslyCrash) { + // Delete the crash file marker in the background ensure start up is as fast as possible + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + [self.fileManager removeItemAtPath:crashedMarkerFileFullPath]; + }); + } +} + +#pragma mark - API: Logging +- (void)log:(NSString *)msg { + FIRCLSLog(@"%@", msg); +} + +- (void)logWithFormat:(NSString *)format, ... { + va_list args; + va_start(args, format); + [self logWithFormat:format arguments:args]; + va_end(args); +} + +- (void)logWithFormat:(NSString *)format arguments:(va_list)args { + [self log:[[NSString alloc] initWithFormat:format arguments:args]]; +} + +#pragma mark - API: Accessors + +- (void)checkForUnsentReportsWithCompletion:(void (^)(BOOL))completion { + [[self.reportManager checkForUnsentReports] + then:^id _Nullable(FIRCrashlyticsReport *_Nullable value) { + completion(value ? true : false); + return nil; + }]; +} + +- (void)checkAndUpdateUnsentReportsWithCompletion: + (void (^)(FIRCrashlyticsReport *_Nonnull))completion { + [[self.reportManager checkForUnsentReports] + then:^id _Nullable(FIRCrashlyticsReport *_Nullable value) { + completion(value); + return nil; + }]; +} + +- (void)sendUnsentReports { + [self.reportManager sendUnsentReports]; +} + +- (void)deleteUnsentReports { + [self.reportManager deleteUnsentReports]; +} + +#pragma mark - API: setUserID +- (void)setUserID:(nullable NSString *)userID { + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUserIdentifierKey, userID); +} + +#pragma mark - API: setCustomValue + +- (void)setCustomValue:(nullable id)value forKey:(NSString *)key { + FIRCLSUserLoggingRecordUserKeyValue(key, value); +} + +- (void)setCustomKeysAndValues:(NSDictionary *)keysAndValues { + FIRCLSUserLoggingRecordUserKeysAndValues(keysAndValues); +} + +#pragma mark - API: Development Platform +// These two methods are deprecated by our own API, so +// its ok to implement them +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-implementations" ++ (void)setDevelopmentPlatformName:(NSString *)name { + [[self crashlytics] setDevelopmentPlatformName:name]; +} + ++ (void)setDevelopmentPlatformVersion:(NSString *)version { + [[self crashlytics] setDevelopmentPlatformVersion:version]; +} +#pragma clang diagnostic pop + +- (NSString *)developmentPlatformName { + FIRCLSErrorLog(@"developmentPlatformName is write-only"); + return nil; +} + +- (void)setDevelopmentPlatformName:(NSString *)developmentPlatformName { + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDevelopmentPlatformNameKey, + developmentPlatformName); +} + +- (NSString *)developmentPlatformVersion { + FIRCLSErrorLog(@"developmentPlatformVersion is write-only"); + return nil; +} + +- (void)setDevelopmentPlatformVersion:(NSString *)developmentPlatformVersion { + FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDevelopmentPlatformVersionKey, + developmentPlatformVersion); +} + +#pragma mark - API: Errors and Exceptions +- (void)recordError:(NSError *)error { + [self recordError:error userInfo:nil]; +} + +- (void)recordError:(NSError *)error userInfo:(NSDictionary *)userInfo { + NSString *rolloutsInfoJSON = [_remoteConfigManager getRolloutAssignmentsEncodedJsonString]; + FIRCLSUserLoggingRecordError(error, userInfo, rolloutsInfoJSON); +} + +- (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel { + NSString *rolloutsInfoJSON = [_remoteConfigManager getRolloutAssignmentsEncodedJsonString]; + FIRCLSExceptionRecordModel(exceptionModel, rolloutsInfoJSON); +} + +- (void)recordOnDemandExceptionModel:(FIRExceptionModel *)exceptionModel { + [self.managerData.onDemandModel + recordOnDemandExceptionIfQuota:exceptionModel + withDataCollectionEnabled:[self.dataArbiter isCrashlyticsCollectionEnabled] + usingExistingReportManager:self.existingReportManager]; +} + +#pragma mark - FIRSessionsSubscriber + +- (void)onSessionChanged:(FIRSessionDetails *_Nonnull)session { + FIRCLSDebugLog(@"Session ID changed: %@", session.sessionId.copy); + + [self.managerData.contextManager setAppQualitySessionId:session.sessionId.copy]; +} + +- (BOOL)isDataCollectionEnabled { + return self.dataArbiter.isCrashlyticsCollectionEnabled; +} + +- (FIRSessionsSubscriberName)sessionsSubscriberName { + return FIRSessionsSubscriberNameCrashlytics; +} + +#pragma mark - FIRRolloutsStateSubscriber +- (void)rolloutsStateDidChange:(FIRRolloutsState *_Nonnull)rolloutsState { + if (!_remoteConfigManager) { + FIRCLSDebugLog(@"rolloutsStateDidChange gets called without init the rc manager."); + return; + } + NSString *currentReportID = _managerData.executionIDModel.executionID; + [_remoteConfigManager updateRolloutsStateWithRolloutsState:rolloutsState + reportID:currentReportID]; +} +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlyticsReport.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlyticsReport.m new file mode 100644 index 0000000..97e22b1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRCrashlyticsReport.m @@ -0,0 +1,197 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSContext.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" + +@interface FIRCrashlyticsReport () { + NSString *_reportID; + NSDate *_dateCreated; + BOOL _hasCrash; + + FIRCLSUserLoggingABStorage _logStorage; + const char *_activeLogPath; + + uint32_t _internalKVCounter; + FIRCLSUserLoggingKVStorage _internalKVStorage; + + uint32_t _userKVCounter; + FIRCLSUserLoggingKVStorage _userKVStorage; +} + +@property(nonatomic, strong) FIRCLSInternalReport *internalReport; + +@end + +@implementation FIRCrashlyticsReport + +- (instancetype)initWithInternalReport:(FIRCLSInternalReport *)internalReport { + self = [super init]; + if (!self) { + return nil; + } + + _internalReport = internalReport; + _reportID = [[internalReport identifier] copy]; + _dateCreated = [[internalReport dateCreated] copy]; + _hasCrash = [internalReport isCrash]; + + _logStorage.maxSize = _firclsContext.readonly->logging.logStorage.maxSize; + _logStorage.maxEntries = _firclsContext.readonly->logging.logStorage.maxEntries; + _logStorage.restrictBySize = _firclsContext.readonly->logging.logStorage.restrictBySize; + _logStorage.entryCount = _firclsContext.readonly->logging.logStorage.entryCount; + _logStorage.aPath = [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportLogAFile + inInternalReport:internalReport]; + _logStorage.bPath = [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportLogBFile + inInternalReport:internalReport]; + + _activeLogPath = _logStorage.aPath; + + // TODO: correct kv accounting + // The internal report will have non-zero compacted and incremental keys. The right thing to do + // is count them, so we can kick off compactions/pruning at the right times. By + // setting this value to zero, we're allowing more entries to be made than there really + // should be. Not the end of the world, but we should do better eventually. + _internalKVCounter = 0; + _userKVCounter = 0; + + _userKVStorage.maxCount = _firclsContext.readonly->logging.userKVStorage.maxCount; + _userKVStorage.maxIncrementalCount = + _firclsContext.readonly->logging.userKVStorage.maxIncrementalCount; + _userKVStorage.compactedPath = + [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportUserCompactedKVFile + inInternalReport:internalReport]; + _userKVStorage.incrementalPath = + [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportUserIncrementalKVFile + inInternalReport:internalReport]; + + _internalKVStorage.maxCount = _firclsContext.readonly->logging.internalKVStorage.maxCount; + _internalKVStorage.maxIncrementalCount = + _firclsContext.readonly->logging.internalKVStorage.maxIncrementalCount; + _internalKVStorage.compactedPath = + [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportInternalCompactedKVFile + inInternalReport:internalReport]; + _internalKVStorage.incrementalPath = + [FIRCrashlyticsReport filesystemPathForContentFile:FIRCLSReportInternalIncrementalKVFile + inInternalReport:internalReport]; + + return self; +} + ++ (const char *)filesystemPathForContentFile:(NSString *)contentFile + inInternalReport:(FIRCLSInternalReport *)internalReport { + if (!internalReport) { + return nil; + } + + // We need to be defensive because strdup will crash + // if given a nil. + NSString *objCString = [internalReport pathForContentFile:contentFile]; + const char *fileSystemString = [objCString fileSystemRepresentation]; + if (!objCString || !fileSystemString) { + return nil; + } + + // Paths need to be duplicated because fileSystemRepresentation returns C strings + // that are freed outside of this context. + return strdup(fileSystemString); +} + +- (BOOL)checkContextForMethod:(NSString *)methodName { + if (!FIRCLSContextIsInitialized()) { + FIRCLSErrorLog(@"%@ failed for FIRCrashlyticsReport because Crashlytics context isn't " + @"initialized.", + methodName); + return false; + } + return true; +} + +#pragma mark - API: Getters + +- (NSString *)reportID { + return _reportID; +} + +- (NSDate *)dateCreated { + return _dateCreated; +} + +- (BOOL)hasCrash { + return _hasCrash; +} + +#pragma mark - API: Logging + +- (void)log:(NSString *)msg { + if (![self checkContextForMethod:@"log:"]) { + return; + } + + FIRCLSLogToStorage(&_logStorage, &_activeLogPath, @"%@", msg); +} + +- (void)logWithFormat:(NSString *)format, ... { + if (![self checkContextForMethod:@"logWithFormat:"]) { + return; + } + + va_list args; + va_start(args, format); + [self logWithFormat:format arguments:args]; + va_end(args); +} + +- (void)logWithFormat:(NSString *)format arguments:(va_list)args { + if (![self checkContextForMethod:@"logWithFormat:arguments:"]) { + return; + } + + [self log:[[NSString alloc] initWithFormat:format arguments:args]]; +} + +#pragma mark - API: setUserID + +- (void)setUserID:(nullable NSString *)userID { + if (![self checkContextForMethod:@"setUserID:"]) { + return; + } + + FIRCLSUserLoggingRecordKeyValue(FIRCLSUserIdentifierKey, userID, &_internalKVStorage, + &_internalKVCounter); +} + +#pragma mark - API: setCustomValue + +- (void)setCustomValue:(nullable id)value forKey:(NSString *)key { + if (![self checkContextForMethod:@"setCustomValue:forKey:"]) { + return; + } + + FIRCLSUserLoggingRecordKeyValue(key, value, &_userKVStorage, &_userKVCounter); +} + +- (void)setCustomKeysAndValues:(NSDictionary *)keysAndValues { + if (![self checkContextForMethod:@"setCustomKeysAndValues:"]) { + return; + } + + FIRCLSUserLoggingRecordKeysAndValues(keysAndValues, &_userKVStorage, &_userKVCounter); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRExceptionModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRExceptionModel.m new file mode 100644 index 0000000..2bd9924 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRExceptionModel.m @@ -0,0 +1,44 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRExceptionModel.h" + +@interface FIRExceptionModel () + +@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy) NSString *reason; +@property(nonatomic) BOOL isFatal; +@property(nonatomic) BOOL onDemand; + +@end + +@implementation FIRExceptionModel + +- (instancetype)initWithName:(NSString *)name reason:(NSString *)reason { + self = [super init]; + if (!self) { + return nil; + } + + _name = [name copy]; + _reason = [reason copy]; + + return self; +} + ++ (instancetype)exceptionModelWithName:(NSString *)name reason:(NSString *)reason { + return [[FIRExceptionModel alloc] initWithName:name reason:reason]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRStackFrame.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRStackFrame.m new file mode 100644 index 0000000..ffdeb41 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/FIRStackFrame.m @@ -0,0 +1,94 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +@interface FIRStackFrame () + +@property(nonatomic, copy, nullable) NSString *symbol; +@property(nonatomic, copy, nullable) NSString *rawSymbol; +@property(nonatomic, copy, nullable) NSString *library; +@property(nonatomic, copy, nullable) NSString *fileName; +@property(nonatomic, assign) uint32_t lineNumber; +@property(nonatomic, assign) uint64_t offset; +@property(nonatomic, assign) uint64_t address; + +@property(nonatomic, assign) BOOL isSymbolicated; + +@end + +@implementation FIRStackFrame + +#pragma mark - Public Methods + +- (instancetype)initWithSymbol:(NSString *)symbol file:(NSString *)file line:(NSInteger)line { + self = [super init]; + if (!self) { + return nil; + } + + _symbol = [symbol copy]; + _fileName = [file copy]; + _lineNumber = (uint32_t)line; + + _isSymbolicated = true; + + return self; +} + ++ (instancetype)stackFrameWithAddress:(NSUInteger)address { + FIRStackFrame *frame = [self stackFrame]; + + [frame setAddress:address]; + + return frame; +} + ++ (instancetype)stackFrameWithSymbol:(NSString *)symbol file:(NSString *)file line:(NSInteger)line { + return [[FIRStackFrame alloc] initWithSymbol:symbol file:file line:line]; +} + +#pragma mark - Internal Methods + ++ (instancetype)stackFrame { + return [[self alloc] init]; +} + ++ (instancetype)stackFrameWithSymbol:(NSString *)symbol { + FIRStackFrame *frame = [self stackFrame]; + + frame.symbol = symbol; + frame.rawSymbol = symbol; + + return frame; +} + +#pragma mark - Overrides + +- (NSString *)description { + if (self.isSymbolicated) { + return [NSString + stringWithFormat:@"{%@ - %@:%u}", [self fileName], [self symbol], [self lineNumber]]; + } + + if (self.fileName) { + return [NSString stringWithFormat:@"{[0x%llx] %@ - %@:%u}", [self address], [self fileName], + [self symbol], [self lineNumber]]; + } + + return [NSString + stringWithFormat:@"{[0x%llx + %u] %@}", [self address], [self lineNumber], [self symbol]]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.h new file mode 100644 index 0000000..65aae9b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.h @@ -0,0 +1,82 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#ifdef __OBJC__ +#import +@class FIRStackFrame; +@class FIRExceptionModel; +#endif + +#define CLS_EXCEPTION_STRING_LENGTH_MAX (1024 * 16) + +typedef enum { + FIRCLSExceptionTypeUnknown = 0, + FIRCLSExceptionTypeObjectiveC = 1, + FIRCLSExceptionTypeCpp = 2, + // 3 was FIRCLSExceptionTypeJavascript + // Keeping these numbers the same just to be safe + FIRCLSExceptionTypeCustom = 4 +} FIRCLSExceptionType; + +typedef struct { + const char* path; + + void (*originalTerminateHandler)(void); + +#if !TARGET_OS_IPHONE + void* originalNSApplicationReportException; +#endif + + uint32_t maxCustomExceptions; +} FIRCLSExceptionReadOnlyContext; + +typedef struct { + uint32_t customExceptionCount; +} FIRCLSExceptionWritableContext; + +__BEGIN_DECLS + +void FIRCLSExceptionInitialize(FIRCLSExceptionReadOnlyContext* roContext, + FIRCLSExceptionWritableContext* rwContext); +void FIRCLSExceptionCheckHandlers(void* delegate); + +void FIRCLSExceptionRaiseTestObjCException(void) __attribute((noreturn)); +void FIRCLSExceptionRaiseTestCppException(void) __attribute((noreturn)); + +#ifdef __OBJC__ +void FIRCLSExceptionRecordModel(FIRExceptionModel* exceptionModel, NSString* rolloutsInfoJSON); +NSString* FIRCLSExceptionRecordOnDemandModel(FIRExceptionModel* exceptionModel, + int previousRecordedOnDemandExceptions, + int previousDroppedOnDemandExceptions); +void FIRCLSExceptionRecordNSException(NSException* exception); +void FIRCLSExceptionRecord(FIRCLSExceptionType type, + const char* name, + const char* reason, + NSArray* frames, + NSString* rolloutsInfoJSON); +NSString* FIRCLSExceptionRecordOnDemand(FIRCLSExceptionType type, + const char* name, + const char* reason, + NSArray* frames, + BOOL fatal, + int previousRecordedOnDemandExceptions, + int previousDroppedOnDemandExceptions); +#endif + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.mm b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.mm new file mode 100644 index 0000000..5a47d07 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSException.mm @@ -0,0 +1,538 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h" + +#import "Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h" +#import "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +#include "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" + +#include "Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#include "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h" + +// C++/Objective-C exception handling +#include +#include +#include +#include + +#if !TARGET_OS_IPHONE +#import +#import +#endif + +#pragma mark Prototypes +static void FIRCLSTerminateHandler(void); +#if !TARGET_OS_IPHONE +void FIRCLSNSApplicationReportException(id self, SEL cmd, NSException *exception); + +typedef void (*NSApplicationReportExceptionFunction)(id, SEL, NSException *); + +static BOOL FIRCLSIsNSApplicationCrashOnExceptionsEnabled(void); +static NSApplicationReportExceptionFunction FIRCLSOriginalNSExceptionReportExceptionFunction(void); +static Method FIRCLSGetNSApplicationReportExceptionMethod(void); + +#endif + +#pragma mark - API +void FIRCLSExceptionInitialize(FIRCLSExceptionReadOnlyContext *roContext, + FIRCLSExceptionWritableContext *rwContext) { + if (!FIRCLSUnlinkIfExists(roContext->path)) { + FIRCLSSDKLog("Unable to reset the exception file %s\n", strerror(errno)); + } + + roContext->originalTerminateHandler = std::set_terminate(FIRCLSTerminateHandler); + +#if !TARGET_OS_IPHONE + // If FIRCLSApplicationSharedInstance is null, we don't need this + if (FIRCLSIsNSApplicationCrashOnExceptionsEnabled() && FIRCLSApplicationSharedInstance()) { + Method m = FIRCLSGetNSApplicationReportExceptionMethod(); + + roContext->originalNSApplicationReportException = + (void *)method_setImplementation(m, (IMP)FIRCLSNSApplicationReportException); + } +#endif + + rwContext->customExceptionCount = 0; +} + +void FIRCLSExceptionRecordModel(FIRExceptionModel *exceptionModel, NSString *rolloutsInfoJSON) { + const char *name = [[exceptionModel.name copy] UTF8String]; + const char *reason = [[exceptionModel.reason copy] UTF8String] ?: ""; + FIRCLSExceptionRecord(FIRCLSExceptionTypeCustom, name, reason, [exceptionModel.stackTrace copy], + rolloutsInfoJSON); +} + +NSString *FIRCLSExceptionRecordOnDemandModel(FIRExceptionModel *exceptionModel, + int previousRecordedOnDemandExceptions, + int previousDroppedOnDemandExceptions) { + const char *name = [[exceptionModel.name copy] UTF8String]; + const char *reason = [[exceptionModel.reason copy] UTF8String] ?: ""; + + return FIRCLSExceptionRecordOnDemand(FIRCLSExceptionTypeCustom, name, reason, + [exceptionModel.stackTrace copy], exceptionModel.isFatal, + previousRecordedOnDemandExceptions, + previousDroppedOnDemandExceptions); +} + +void FIRCLSExceptionRecordNSException(NSException *exception) { + FIRCLSSDKLog("Recording an NSException\n"); + + NSArray *returnAddresses = [exception callStackReturnAddresses]; + + NSString *name = [exception name]; + NSString *reason = [exception reason] ?: @""; + + // It's tempting to try to make use of callStackSymbols here. But, the output + // of that function is not intended to be machine-readible. We could parse it, + // but that isn't really worthwhile, considering that address-based symbolication + // needs to work anyways. + + // package our frames up into the appropriate format + NSMutableArray *frames = [NSMutableArray new]; + + for (NSNumber *address in returnAddresses) { + [frames addObject:[FIRStackFrame stackFrameWithAddress:[address unsignedIntegerValue]]]; + } + + FIRCLSExceptionRecord(FIRCLSExceptionTypeObjectiveC, [name UTF8String], [reason UTF8String], + frames, nil); +} + +static void FIRCLSExceptionRecordFrame(FIRCLSFile *file, FIRStackFrame *frame) { + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryUint64(file, "pc", [frame address]); + + NSString *string = [frame symbol]; + if (string) { + FIRCLSFileWriteHashEntryHexEncodedString(file, "symbol", [string UTF8String]); + } + + FIRCLSFileWriteHashEntryUint64(file, "offset", [frame offset]); + + string = [frame library]; + if (string) { + FIRCLSFileWriteHashEntryHexEncodedString(file, "library", [string UTF8String]); + } + + string = [frame fileName]; + if (string) { + FIRCLSFileWriteHashEntryHexEncodedString(file, "file", [string UTF8String]); + } + + FIRCLSFileWriteHashEntryUint64(file, "line", [frame lineNumber]); + + FIRCLSFileWriteHashEnd(file); +} + +static bool FIRCLSExceptionIsNative(FIRCLSExceptionType type) { + return type == FIRCLSExceptionTypeObjectiveC || type == FIRCLSExceptionTypeCpp; +} + +static const char *FIRCLSExceptionNameForType(FIRCLSExceptionType type) { + switch (type) { + case FIRCLSExceptionTypeObjectiveC: + return "objective-c"; + case FIRCLSExceptionTypeCpp: + return "c++"; + case FIRCLSExceptionTypeCustom: + return "custom"; + default: + break; + } + + return "unknown"; +} + +void FIRCLSExceptionWrite(FIRCLSFile *file, + FIRCLSExceptionType type, + const char *name, + const char *reason, + NSArray *frames, + NSString *rolloutsInfoJSON) { + FIRCLSFileWriteSectionStart(file, "exception"); + + FIRCLSFileWriteHashStart(file); + + FIRCLSFileWriteHashEntryString(file, "type", FIRCLSExceptionNameForType(type)); + FIRCLSFileWriteHashEntryHexEncodedString(file, "name", name); + FIRCLSFileWriteHashEntryHexEncodedString(file, "reason", reason); + FIRCLSFileWriteHashEntryUint64(file, "time", time(NULL)); + + if ([frames count]) { + FIRCLSFileWriteHashKey(file, "frames"); + FIRCLSFileWriteArrayStart(file); + + for (FIRStackFrame *frame in frames) { + FIRCLSExceptionRecordFrame(file, frame); + } + + FIRCLSFileWriteArrayEnd(file); + } + + if (rolloutsInfoJSON) { + FIRCLSFileWriteHashKey(file, "rollouts"); + FIRCLSFileWriteStringUnquoted(file, [rolloutsInfoJSON UTF8String]); + FIRCLSFileWriteHashEnd(file); + } + + FIRCLSFileWriteHashEnd(file); + + FIRCLSFileWriteSectionEnd(file); +} + +void FIRCLSExceptionRecord(FIRCLSExceptionType type, + const char *name, + const char *reason, + NSArray *frames, + NSString *rolloutsInfoJSON) { + if (!FIRCLSContextIsInitialized()) { + return; + } + + bool native = FIRCLSExceptionIsNative(type); + + FIRCLSSDKLog("Recording an exception structure (%d)\n", native); + + // exceptions can happen on multiple threads at the same time + if (native) { + dispatch_sync(_firclsExceptionQueue, ^{ + const char *path = _firclsContext.readonly->exception.path; + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, path, false)) { + FIRCLSSDKLog("Unable to open exception file\n"); + return; + } + + FIRCLSExceptionWrite(&file, type, name, reason, frames, nil); + + // We only want to do this work if we have the expectation that we'll actually crash + FIRCLSHandler(&file, mach_thread_self(), NULL); + + FIRCLSFileClose(&file); + }); + } else { + FIRCLSUserLoggingWriteAndCheckABFiles( + &_firclsContext.readonly->logging.customExceptionStorage, + &_firclsContext.writable->logging.activeCustomExceptionPath, ^(FIRCLSFile *file) { + FIRCLSExceptionWrite(file, type, name, reason, frames, rolloutsInfoJSON); + }); + } + + FIRCLSSDKLog("Finished recording an exception structure\n"); +} + +// Prepares a new active report for on-demand delivery and returns the path to the report. +// Should only be used for platforms in which exceptions do not crash the app (flutter, Unity, etc). +NSString *FIRCLSExceptionRecordOnDemand(FIRCLSExceptionType type, + const char *name, + const char *reason, + NSArray *frames, + BOOL fatal, + int previousRecordedOnDemandExceptions, + int previousDroppedOnDemandExceptions) { + if (!FIRCLSContextIsInitialized()) { + return nil; + } + + FIRCLSSDKLog("Recording an exception structure on demand\n"); + + FIRCLSFileManager *fileManager = [[FIRCLSFileManager alloc] init]; + + // Create paths for new report. + NSString *currentReportPath = + [NSString stringWithUTF8String:_firclsContext.readonly->initialReportPath]; + NSString *newReportID = [[[FIRCLSExecutionIdentifierModel alloc] init] executionID]; + NSString *newReportPath = [fileManager.activePath stringByAppendingPathComponent:newReportID]; + NSString *customFatalIndicatorFilePath = + [newReportPath stringByAppendingPathComponent:FIRCLSCustomFatalIndicatorFile]; + NSString *newKVPath = + [newReportPath stringByAppendingPathComponent:FIRCLSReportInternalIncrementalKVFile]; + + // Create new report and copy into it the current state of custom keys and log and the sdk.log, + // binary_images.clsrecord, and metadata.clsrecord files. + // Also copy rollouts.clsrecord if applicable. + NSError *error = nil; + BOOL copied = [fileManager.underlyingFileManager copyItemAtPath:currentReportPath + toPath:newReportPath + error:&error]; + if (error || !copied) { + FIRCLSSDKLog("Unable to create a new report to record on-demand exeption."); + return nil; + } + + // Once the report is copied, remove non-fatal events from current report. + if ([fileManager + fileExistsAtPath:[NSString stringWithUTF8String:_firclsContext.readonly->logging + .customExceptionStorage.aPath]]) { + [fileManager + removeItemAtPath:[NSString stringWithUTF8String:_firclsContext.readonly->logging + .customExceptionStorage.aPath]]; + } + if ([fileManager + fileExistsAtPath:[NSString stringWithUTF8String:_firclsContext.readonly->logging + .customExceptionStorage.bPath]]) { + [fileManager + removeItemAtPath:[NSString stringWithUTF8String:_firclsContext.readonly->logging + .customExceptionStorage.bPath]]; + } + *_firclsContext.readonly->logging.customExceptionStorage.entryCount = 0; + _firclsContext.writable->exception.customExceptionCount = 0; + + // Record how many on-demand exceptions occurred before this one as well as how many were dropped. + FIRCLSFile kvFile; + if (!FIRCLSFileInitWithPath(&kvFile, [newKVPath UTF8String], true)) { + FIRCLSSDKLogError("Unable to open k-v file\n"); + return nil; + } + FIRCLSFileWriteSectionStart(&kvFile, "kv"); + FIRCLSFileWriteHashStart(&kvFile); + FIRCLSFileWriteHashEntryHexEncodedString(&kvFile, "key", + [FIRCLSOnDemandRecordedExceptionsKey UTF8String]); + FIRCLSFileWriteHashEntryHexEncodedString( + &kvFile, "value", + [[[NSNumber numberWithInt:previousRecordedOnDemandExceptions] stringValue] UTF8String]); + FIRCLSFileWriteHashEnd(&kvFile); + FIRCLSFileWriteSectionEnd(&kvFile); + FIRCLSFileWriteSectionStart(&kvFile, "kv"); + FIRCLSFileWriteHashStart(&kvFile); + FIRCLSFileWriteHashEntryHexEncodedString(&kvFile, "key", + [FIRCLSOnDemandDroppedExceptionsKey UTF8String]); + FIRCLSFileWriteHashEntryHexEncodedString( + &kvFile, "value", + [[[NSNumber numberWithInt:previousDroppedOnDemandExceptions] stringValue] UTF8String]); + FIRCLSFileWriteHashEnd(&kvFile); + FIRCLSFileWriteSectionEnd(&kvFile); + FIRCLSFileClose(&kvFile); + + // If the event was fatal, write out an empty file to indicate that the report contains a fatal + // event. This is used to report events to Analytics for CFU calculations. + if (fatal && ![fileManager createFileAtPath:customFatalIndicatorFilePath + contents:nil + attributes:nil]) { + FIRCLSSDKLog("Unable to create custom exception file. On demand exception will not be logged " + "with analytics."); + } + + // Write out the exception in the new report. + const char *newActiveCustomExceptionPath = + fatal ? [[newReportPath stringByAppendingPathComponent:FIRCLSReportExceptionFile] UTF8String] + : [[newReportPath stringByAppendingPathComponent:FIRCLSReportCustomExceptionAFile] + UTF8String]; + FIRCLSFile file; + if (!FIRCLSFileInitWithPath(&file, newActiveCustomExceptionPath, true)) { + FIRCLSSDKLog("Unable to open log file for on demand custom exception\n"); + return nil; + } + FIRCLSExceptionWrite(&file, type, name, reason, frames, nil); + FIRCLSHandler(&file, mach_thread_self(), NULL); + FIRCLSFileClose(&file); + + // Return the path to the new report. + FIRCLSSDKLog("Finished recording on demand exception structure\n"); + return newReportPath; +} + +// Ignore this message here, because we know that this call will not leak. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Winvalid-noreturn" +void FIRCLSExceptionRaiseTestObjCException(void) { + [NSException raise:@"CrashlyticsTestException" + format:@"This is an Objective-C exception used for testing."]; +} + +void FIRCLSExceptionRaiseTestCppException(void) { + throw "Crashlytics C++ Test Exception"; +} +#pragma clang diagnostic pop + +static const char *FIRCLSExceptionDemangle(const char *symbol) { + return [[FIRCLSDemangleOperation demangleCppSymbol:symbol] UTF8String]; +} + +static void FIRCLSCatchAndRecordActiveException(std::type_info *typeInfo) { + if (!FIRCLSIsValidPointer(typeInfo)) { + FIRCLSSDKLog("Error: invalid parameter\n"); + return; + } + + const char *name = typeInfo->name(); + FIRCLSSDKLog("Recording exception of type '%s'\n", name); + + // This is a funny technique to get the exception object. The inner @try + // has the ability to capture NSException-derived objects. It seems that + // c++ tries can do that in some cases, but I was warned by the WWDC labs + // that there are cases where that will not work (like for NSException subclasses). + try { + @try { + // This could potentially cause a call to std::terminate() if there is actually no active + // exception. + throw; + } @catch (NSException *exception) { +#if TARGET_OS_IPHONE + FIRCLSExceptionRecordNSException(exception); +#else + // There's no need to record this here, because we're going to get + // the value forward to us by AppKit + FIRCLSSDKLog("Skipping ObjC exception at this point\n"); +#endif + } + } catch (const char *exc) { + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, "const char *", exc, nil, nil); + } catch (const std::string &exc) { + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, "std::string", exc.c_str(), nil, nil); + } catch (const std::exception &exc) { + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, FIRCLSExceptionDemangle(name), exc.what(), nil, + nil); + } catch (const std::exception *exc) { + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, FIRCLSExceptionDemangle(name), exc->what(), nil, + nil); + } catch (const std::bad_alloc &exc) { + // it is especially important to avoid demangling in this case, because the expectation at this + // point is that all allocations could fail + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, "std::bad_alloc", exc.what(), nil, nil); + } catch (...) { + FIRCLSExceptionRecord(FIRCLSExceptionTypeCpp, FIRCLSExceptionDemangle(name), "", nil, nil); + } +} + +#pragma mark - Handlers +static void FIRCLSTerminateHandler(void) { + FIRCLSSDKLog("C++ terminate handler invoked\n"); + + void (*handler)(void) = _firclsContext.readonly->exception.originalTerminateHandler; + if (handler == FIRCLSTerminateHandler) { + FIRCLSSDKLog("Error: original handler was set recursively\n"); + handler = NULL; + } + + // Restore pre-existing handler, if any. Do this early, so that + // if std::terminate is called while we are executing here, we do not recurse. + if (handler) { + FIRCLSSDKLog("restoring pre-existing handler\n"); + + // To prevent infinite recursion in this function, check that we aren't resetting the terminate + // handler to the same function again, which would be this function in the event that we can't + // actually change the handler during a terminate. + if (std::set_terminate(handler) == handler) { + FIRCLSSDKLog("handler has already been restored, aborting\n"); + abort(); + } + } + + // we can use typeInfo to record the type of the exception, + // but we must use a catch to get the value + std::type_info *typeInfo = __cxxabiv1::__cxa_current_exception_type(); + if (typeInfo) { + FIRCLSCatchAndRecordActiveException(typeInfo); + } else { + FIRCLSSDKLog("no active exception\n"); + } + + // only do this if there was a pre-existing handler + if (handler) { + FIRCLSSDKLog("invoking pre-existing handler\n"); + handler(); + } + + FIRCLSSDKLog("aborting\n"); + abort(); +} + +void FIRCLSExceptionCheckHandlers(void *delegate) { +#if !TARGET_OS_IPHONE + // Check this on OS X all the time, even if the debugger is attached. This is a common + // source of errors, so we want to be extra verbose in this case. + if (FIRCLSApplicationSharedInstance()) { + if (!FIRCLSIsNSApplicationCrashOnExceptionsEnabled()) { + FIRCLSWarningLog(@"Warning: NSApplicationCrashOnExceptions is not set. This will " + @"result in poor top-level uncaught exception reporting."); + } + } +#endif + + if (_firclsContext.readonly->debuggerAttached) { + return; + } + + void *ptr = NULL; + + ptr = (void *)std::get_terminate(); + if (ptr != FIRCLSTerminateHandler) { + FIRCLSLookupFunctionPointer(ptr, ^(const char *name, const char *lib) { + FIRCLSWarningLog(@"Warning: std::get_terminate is '%s' in '%s'", name, lib); + }); + } + +#if TARGET_OS_IPHONE + ptr = (void *)NSGetUncaughtExceptionHandler(); + if (ptr) { + FIRCLSLookupFunctionPointer(ptr, ^(const char *name, const char *lib) { + FIRCLSWarningLog(@"Warning: NSUncaughtExceptionHandler is '%s' in '%s'", name, lib); + }); + } +#else + if (FIRCLSApplicationSharedInstance() && FIRCLSIsNSApplicationCrashOnExceptionsEnabled()) { + // In this case, we *might* be able to intercept exceptions. But, verify we've still + // swizzled the method. + Method m = FIRCLSGetNSApplicationReportExceptionMethod(); + + if (method_getImplementation(m) != (IMP)FIRCLSNSApplicationReportException) { + FIRCLSWarningLog( + @"Warning: top-level NSApplication-reported exceptions cannot be intercepted"); + } + } +#endif +} + +#pragma mark - AppKit Handling +#if !TARGET_OS_IPHONE +static BOOL FIRCLSIsNSApplicationCrashOnExceptionsEnabled(void) { + return [[NSUserDefaults standardUserDefaults] boolForKey:@"NSApplicationCrashOnExceptions"]; +} + +static Method FIRCLSGetNSApplicationReportExceptionMethod(void) { + return class_getInstanceMethod(NSClassFromString(@"NSApplication"), @selector(reportException:)); +} + +static NSApplicationReportExceptionFunction FIRCLSOriginalNSExceptionReportExceptionFunction(void) { + return (NSApplicationReportExceptionFunction) + _firclsContext.readonly->exception.originalNSApplicationReportException; +} + +void FIRCLSNSApplicationReportException(id self, SEL cmd, NSException *exception) { + FIRCLSExceptionRecordNSException(exception); + + // Call the original implementation + FIRCLSOriginalNSExceptionReportExceptionFunction()(self, cmd, exception); +} + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h new file mode 100644 index 0000000..04bbab7 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h @@ -0,0 +1,25 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +__BEGIN_DECLS + +void FIRCLSHandler(FIRCLSFile* file, thread_t crashedThread, void* uapVoid); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.m new file mode 100644 index 0000000..b9d027f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSHandler.m @@ -0,0 +1,49 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h" + +#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager_Private.h" + +void FIRCLSHandler(FIRCLSFile* file, thread_t crashedThread, void* uapVoid) { + FIRCLSProcess process; + + FIRCLSProcessInit(&process, crashedThread, uapVoid); + + FIRCLSProcessSuspendAllOtherThreads(&process); + + FIRCLSProcessRecordAllThreads(&process, file); + + FIRCLSProcessRecordRuntimeInfo(&process, file); + // Get dispatch queue and thread names. Note that getting the thread names + // can hang, so let's do that last + FIRCLSProcessRecordDispatchQueueNames(&process, file); + FIRCLSProcessRecordThreadNames(&process, file); + + // this stuff isn't super important, but we can try + FIRCLSProcessRecordStats(&process, file); + FIRCLSHostWriteDiskUsage(file); + + // This is the first common point where various crash handlers call into + // Store a crash file marker to indicate that a crash has occurred + FIRCLSCreateCrashedMarkerFile(); + + FIRCLSProcessResumeAllOtherThreads(&process); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c new file mode 100644 index 0000000..35fe5cb --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.c @@ -0,0 +1,534 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +#if CLS_MACH_EXCEPTION_SUPPORTED + +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSProcess.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include +#include +#include +#include + +#pragma mark Prototypes +static void* FIRCLSMachExceptionServer(void* argument); +static bool FIRCLSMachExceptionThreadStart(FIRCLSMachExceptionReadContext* context); +static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message); +static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message); +static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message, + kern_return_t result); +static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context); +static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* originalPorts, + exception_mask_t mask); +static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message); + +#pragma mark - Initialization +void FIRCLSMachExceptionInit(FIRCLSMachExceptionReadContext* context) { + if (!FIRCLSUnlinkIfExists(context->path)) { + FIRCLSSDKLog("Unable to reset the mach exception file %s\n", strerror(errno)); + } + + if (!FIRCLSMachExceptionRegister(context)) { + FIRCLSSDKLog("Unable to register mach exception handler\n"); + return; + } + + if (!FIRCLSMachExceptionThreadStart(context)) { + FIRCLSSDKLog("Unable to start thread\n"); + FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask); + } +} + +void FIRCLSMachExceptionCheckHandlers(void) { + if (_firclsContext.readonly->debuggerAttached) { + return; + } + + // It isn't really critical that this be done, as its extremely uncommon to run into + // preexisting handlers. + // Can use task_get_exception_ports for this. +} + +static exception_mask_t FIRCLSMachExceptionMask(void) { + exception_mask_t mask; + + // EXC_BAD_ACCESS + // EXC_BAD_INSTRUCTION + // EXC_ARITHMETIC + // EXC_EMULATION - non-failure + // EXC_SOFTWARE - non-failure + // EXC_BREAKPOINT - trap instructions, from the debugger and code. Needs special treatment. + // EXC_SYSCALL - non-failure + // EXC_MACH_SYSCALL - non-failure + // EXC_RPC_ALERT - non-failure + // EXC_CRASH - see below + // EXC_RESOURCE - non-failure, happens when a process exceeds a resource limit + // EXC_GUARD - see below + // + // EXC_CRASH is a special kind of exception. It is handled by launchd, and treated special by + // the kernel. Seems that we cannot safely catch it - our handler will never be called. This + // is a confirmed kernel bug. Lacking access to EXC_CRASH means we must use signal handlers to + // cover all types of crashes. + // EXC_GUARD is relatively new, and isn't available on all OS versions. You have to be careful, + // because you cannot successfully register handlers if there are any unrecognized masks. We've + // dropped support for old OS versions that didn't have EXC_GUARD (iOS 5 and below, macOS 10.6 and + // below) so we always add it now + + mask = EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION | EXC_MASK_ARITHMETIC | + EXC_MASK_BREAKPOINT | EXC_MASK_GUARD; + + return mask; +} + +static bool FIRCLSMachExceptionThreadStart(FIRCLSMachExceptionReadContext* context) { + pthread_attr_t attr; + + if (pthread_attr_init(&attr) != 0) { + FIRCLSSDKLog("pthread_attr_init %s\n", strerror(errno)); + pthread_attr_destroy(&attr); + return false; + } + + if (pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) { + FIRCLSSDKLog("pthread_attr_setdetachstate %s\n", strerror(errno)); + pthread_attr_destroy(&attr); + return false; + } + + // Use to pre-allocate a stack for this thread + // The stack must be page-aligned + if (pthread_attr_setstack(&attr, _firclsContext.readonly->machStack, + CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE) != 0) { + FIRCLSSDKLog("pthread_attr_setstack %s\n", strerror(errno)); + pthread_attr_destroy(&attr); + return false; + } + + if (pthread_create(&context->thread, &attr, FIRCLSMachExceptionServer, context) != 0) { + FIRCLSSDKLog("pthread_create %s\n", strerror(errno)); + pthread_attr_destroy(&attr); + return false; + } + + pthread_attr_destroy(&attr); + + return true; +} + +exception_mask_t FIRCLSMachExceptionMaskForSignal(int signal) { + switch (signal) { + case SIGTRAP: + return EXC_MASK_BREAKPOINT; + case SIGSEGV: + return EXC_MASK_BAD_ACCESS; + case SIGBUS: + return EXC_MASK_BAD_ACCESS; + case SIGILL: + return EXC_MASK_BAD_INSTRUCTION; + case SIGABRT: + return EXC_MASK_CRASH; + case SIGSYS: + return EXC_MASK_CRASH; + case SIGFPE: + return EXC_MASK_ARITHMETIC; + } + + return 0; +} + +#pragma mark - Message Handling +static void* FIRCLSMachExceptionServer(void* argument) { + FIRCLSMachExceptionReadContext* context = argument; + + pthread_setname_np("com.google.firebase.crashlytics.MachExceptionServer"); + + while (1) { + MachExceptionMessage message; + + // read the exception message + if (!FIRCLSMachExceptionReadMessage(context, &message)) { + break; + } + + // handle it, and possibly forward + kern_return_t result = FIRCLSMachExceptionDispatchMessage(context, &message); + + // and now, reply + if (!FIRCLSMachExceptionReply(context, &message, result)) { + break; + } + } + + FIRCLSSDKLog("Mach exception server thread exiting\n"); + + return NULL; +} + +static bool FIRCLSMachExceptionReadMessage(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message) { + mach_msg_return_t r; + + memset(message, 0, sizeof(MachExceptionMessage)); + + r = mach_msg(&message->head, MACH_RCV_MSG | MACH_RCV_LARGE, 0, sizeof(MachExceptionMessage), + context->port, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (r != MACH_MSG_SUCCESS) { + FIRCLSSDKLog("Error receiving mach_msg (%d)\n", r); + return false; + } + + FIRCLSSDKLog("Accepted mach exception message\n"); + + return true; +} + +static kern_return_t FIRCLSMachExceptionDispatchMessage(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message) { + FIRCLSSDKLog("Mach exception: 0x%x, count: %d, code: 0x%llx 0x%llx\n", message->exception, + message->codeCnt, message->codeCnt > 0 ? message->code[0] : -1, + message->codeCnt > 1 ? message->code[1] : -1); + + // This will happen if a child process raises an exception, as the exception ports are + // inherited. + if (message->task.name != mach_task_self()) { + FIRCLSSDKLog("Mach exception task mis-match, returning failure\n"); + return KERN_FAILURE; + } + + FIRCLSSDKLog("Unregistering handler\n"); + if (!FIRCLSMachExceptionUnregister(&context->originalPorts, context->mask)) { + FIRCLSSDKLog("Failed to unregister\n"); + return KERN_FAILURE; + } + + FIRCLSSDKLog("Restoring original signal handlers\n"); + if (!FIRCLSSignalSafeInstallPreexistingHandlers(& _firclsContext.readonly->signal, -1, NULL, NULL)) { + FIRCLSSDKLog("Failed to restore signal handlers\n"); + return KERN_FAILURE; + } + + FIRCLSSDKLog("Recording mach exception\n"); + if (!FIRCLSMachExceptionRecord(context, message)) { + FIRCLSSDKLog("Failed to record mach exception\n"); + return KERN_FAILURE; + } + + return KERN_SUCCESS; +} + +static bool FIRCLSMachExceptionReply(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message, + kern_return_t result) { + MachExceptionReply reply; + mach_msg_return_t r; + + // prepare the reply + reply.head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(message->head.msgh_bits), 0); + reply.head.msgh_remote_port = message->head.msgh_remote_port; + reply.head.msgh_size = (mach_msg_size_t)sizeof(MachExceptionReply); + reply.head.msgh_local_port = MACH_PORT_NULL; + reply.head.msgh_id = message->head.msgh_id + 100; + + reply.NDR = NDR_record; + + reply.retCode = result; + + FIRCLSSDKLog("Sending exception reply\n"); + + // send it + r = mach_msg(&reply.head, MACH_SEND_MSG, reply.head.msgh_size, 0, MACH_PORT_NULL, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (r != MACH_MSG_SUCCESS) { + FIRCLSSDKLog("mach_msg reply failed (%d)\n", r); + return false; + } + + FIRCLSSDKLog("Exception reply delivered\n"); + + return true; +} + +#pragma mark - Registration +static bool FIRCLSMachExceptionRegister(FIRCLSMachExceptionReadContext* context) { + mach_port_t task = mach_task_self(); + + kern_return_t kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &context->port); + if (kr != KERN_SUCCESS) { + FIRCLSSDKLog("Error: mach_port_allocate failed %d\n", kr); + return false; + } + + kr = mach_port_insert_right(task, context->port, context->port, MACH_MSG_TYPE_MAKE_SEND); + if (kr != KERN_SUCCESS) { + FIRCLSSDKLog("Error: mach_port_insert_right failed %d\n", kr); + mach_port_deallocate(task, context->port); + return false; + } + + // Get the desired mask, which covers all the mach exceptions we are capable of handling, + // but clear out any that are in our ignore list. We do this by ANDing with the bitwise + // negation. Because we are only clearing bits, there's no way to set an incorrect mask + // using ignoreMask. + context->mask = FIRCLSMachExceptionMask(); + + // ORing with MACH_EXCEPTION_CODES will produce 64-bit exception data + kr = task_swap_exception_ports(task, context->mask, context->port, + EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE, + context->originalPorts.masks, &context->originalPorts.count, + context->originalPorts.ports, context->originalPorts.behaviors, + context->originalPorts.flavors); + if (kr != KERN_SUCCESS) { + FIRCLSSDKLog("Error: task_swap_exception_ports %d\n", kr); + return false; + } + + for (int i = 0; i < context->originalPorts.count; ++i) { + FIRCLSSDKLog("original 0x%x 0x%x 0x%x 0x%x\n", context->originalPorts.ports[i], + context->originalPorts.masks[i], context->originalPorts.behaviors[i], + context->originalPorts.flavors[i]); + } + + return true; +} + +static bool FIRCLSMachExceptionUnregister(FIRCLSMachExceptionOriginalPorts* originalPorts, + exception_mask_t mask) { + kern_return_t kr; + + // Re-register all the old ports. + for (mach_msg_type_number_t i = 0; i < originalPorts->count; ++i) { + // clear the bits from this original mask + mask &= ~originalPorts->masks[i]; + + kr = + task_set_exception_ports(mach_task_self(), originalPorts->masks[i], originalPorts->ports[i], + originalPorts->behaviors[i], originalPorts->flavors[i]); + if (kr != KERN_SUCCESS) { + FIRCLSSDKLog("unable to restore original port: %d", originalPorts->ports[i]); + } + } + + // Finally, mark any masks we registered for that do not have an original port as unused. + kr = task_set_exception_ports(mach_task_self(), mask, MACH_PORT_NULL, + EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES, THREAD_STATE_NONE); + if (kr != KERN_SUCCESS) { + FIRCLSSDKLog("unable to unset unregistered mask: 0x%x", mask); + return false; + } + + return true; +} + +#pragma mark - Recording +void FIRCLSMachExceptionNameLookup(exception_type_t number, + mach_exception_data_type_t code, + const char** name, + const char** codeName) { + if (!name || !codeName) { + return; + } + + *name = NULL; + *codeName = NULL; + + switch (number) { + case EXC_BAD_ACCESS: + *name = "EXC_BAD_ACCESS"; + switch (code) { + case KERN_INVALID_ADDRESS: + *codeName = "KERN_INVALID_ADDRESS"; + break; + case KERN_PROTECTION_FAILURE: + *codeName = "KERN_PROTECTION_FAILURE"; + break; + } + + break; + case EXC_BAD_INSTRUCTION: + *name = "EXC_BAD_INSTRUCTION"; +#if CLS_CPU_X86 + *codeName = "EXC_I386_INVOP"; +#endif + break; + case EXC_ARITHMETIC: + *name = "EXC_ARITHMETIC"; +#if CLS_CPU_X86 + switch (code) { + case EXC_I386_DIV: + *codeName = "EXC_I386_DIV"; + break; + case EXC_I386_INTO: + *codeName = "EXC_I386_INTO"; + break; + case EXC_I386_NOEXT: + *codeName = "EXC_I386_NOEXT"; + break; + case EXC_I386_EXTOVR: + *codeName = "EXC_I386_EXTOVR"; + break; + case EXC_I386_EXTERR: + *codeName = "EXC_I386_EXTERR"; + break; + case EXC_I386_EMERR: + *codeName = "EXC_I386_EMERR"; + break; + case EXC_I386_BOUND: + *codeName = "EXC_I386_BOUND"; + break; + case EXC_I386_SSEEXTERR: + *codeName = "EXC_I386_SSEEXTERR"; + break; + } +#endif + break; + case EXC_BREAKPOINT: + *name = "EXC_BREAKPOINT"; +#if CLS_CPU_X86 + switch (code) { + case EXC_I386_DIVERR: + *codeName = "EXC_I386_DIVERR"; + break; + case EXC_I386_SGLSTP: + *codeName = "EXC_I386_SGLSTP"; + break; + case EXC_I386_NMIFLT: + *codeName = "EXC_I386_NMIFLT"; + break; + case EXC_I386_BPTFLT: + *codeName = "EXC_I386_BPTFLT"; + break; + case EXC_I386_INTOFLT: + *codeName = "EXC_I386_INTOFLT"; + break; + case EXC_I386_BOUNDFLT: + *codeName = "EXC_I386_BOUNDFLT"; + break; + case EXC_I386_INVOPFLT: + *codeName = "EXC_I386_INVOPFLT"; + break; + case EXC_I386_NOEXTFLT: + *codeName = "EXC_I386_NOEXTFLT"; + break; + case EXC_I386_EXTOVRFLT: + *codeName = "EXC_I386_EXTOVRFLT"; + break; + case EXC_I386_INVTSSFLT: + *codeName = "EXC_I386_INVTSSFLT"; + break; + case EXC_I386_SEGNPFLT: + *codeName = "EXC_I386_SEGNPFLT"; + break; + case EXC_I386_STKFLT: + *codeName = "EXC_I386_STKFLT"; + break; + case EXC_I386_GPFLT: + *codeName = "EXC_I386_GPFLT"; + break; + case EXC_I386_PGFLT: + *codeName = "EXC_I386_PGFLT"; + break; + case EXC_I386_EXTERRFLT: + *codeName = "EXC_I386_EXTERRFLT"; + break; + case EXC_I386_ALIGNFLT: + *codeName = "EXC_I386_ALIGNFLT"; + break; + case EXC_I386_ENDPERR: + *codeName = "EXC_I386_ENDPERR"; + break; + case EXC_I386_ENOEXTFLT: + *codeName = "EXC_I386_ENOEXTFLT"; + break; + } +#endif + break; + case EXC_GUARD: + *name = "EXC_GUARD"; + break; + } +} + +static bool FIRCLSMachExceptionRecord(FIRCLSMachExceptionReadContext* context, + MachExceptionMessage* message) { + if (!context || !message) { + return false; + } + + if (FIRCLSContextMarkAndCheckIfCrashed()) { + FIRCLSSDKLog("Error: aborting mach exception handler because crash has already occurred\n"); + exit(1); + return false; + } + + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, context->path, false)) { + FIRCLSSDKLog("Unable to open mach exception file\n"); + return false; + } + + FIRCLSFileWriteSectionStart(&file, "mach_exception"); + + FIRCLSFileWriteHashStart(&file); + + FIRCLSFileWriteHashEntryUint64(&file, "exception", message->exception); + + // record the codes + FIRCLSFileWriteHashKey(&file, "codes"); + FIRCLSFileWriteArrayStart(&file); + for (mach_msg_type_number_t i = 0; i < message->codeCnt; ++i) { + FIRCLSFileWriteArrayEntryUint64(&file, message->code[i]); + } + FIRCLSFileWriteArrayEnd(&file); + + const char* name = NULL; + const char* codeName = NULL; + + FIRCLSMachExceptionNameLookup(message->exception, message->codeCnt > 0 ? message->code[0] : 0, + &name, &codeName); + + FIRCLSFileWriteHashEntryString(&file, "name", name); + FIRCLSFileWriteHashEntryString(&file, "code_name", codeName); + + FIRCLSFileWriteHashEntryUint64(&file, "original_ports", context->originalPorts.count); + FIRCLSFileWriteHashEntryUint64(&file, "time", time(NULL)); + + FIRCLSFileWriteHashEnd(&file); + + FIRCLSFileWriteSectionEnd(&file); + + FIRCLSHandler(&file, message->thread.name, NULL); + + FIRCLSFileClose(&file); + + return true; +} + +#else + +INJECT_STRIP_SYMBOL(cls_mach_exception) + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h new file mode 100644 index 0000000..888bd4b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSMachException.h @@ -0,0 +1,81 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +#pragma once + +#if CLS_MACH_EXCEPTION_SUPPORTED + +#include +#include +#include + +// must be at least PTHREAD_STACK_MIN size +#define CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE (256 * 1024) + +#pragma mark Structures +#pragma pack(push, 4) +typedef struct { + mach_msg_header_t head; + /* start of the kernel processed data */ + mach_msg_body_t msgh_body; + mach_msg_port_descriptor_t thread; + mach_msg_port_descriptor_t task; + /* end of the kernel processed data */ + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; + mach_msg_trailer_t trailer; +} MachExceptionMessage; + +typedef struct { + mach_msg_header_t head; + NDR_record_t NDR; + kern_return_t retCode; +} MachExceptionReply; +#pragma pack(pop) + +typedef struct { + mach_msg_type_number_t count; + exception_mask_t masks[EXC_TYPES_COUNT]; + exception_handler_t ports[EXC_TYPES_COUNT]; + exception_behavior_t behaviors[EXC_TYPES_COUNT]; + thread_state_flavor_t flavors[EXC_TYPES_COUNT]; +} FIRCLSMachExceptionOriginalPorts; + +typedef struct { + mach_port_t port; + pthread_t thread; + const char* path; + + exception_mask_t mask; + FIRCLSMachExceptionOriginalPorts originalPorts; +} FIRCLSMachExceptionReadContext; + +#pragma mark - API +void FIRCLSMachExceptionInit(FIRCLSMachExceptionReadContext* context); + +void FIRCLSMachExceptionCheckHandlers(void); + +void FIRCLSMachExceptionNameLookup(exception_type_t number, + mach_exception_data_type_t code, + const char** name, + const char** codeName); +#else + +#define CLS_MACH_EXCEPTION_HANDLER_STACK_SIZE 0 + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.c new file mode 100644 index 0000000..850f58e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.c @@ -0,0 +1,334 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Handlers/FIRCLSHandler.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include +#include + +#if CLS_SIGNAL_SUPPORTED +static const int FIRCLSFatalSignals[FIRCLSSignalCount] = {SIGABRT, SIGBUS, SIGFPE, SIGILL, + SIGSEGV, SIGSYS, SIGTRAP}; + +#if CLS_USE_SIGALTSTACK +static void FIRCLSSignalInstallAltStack(FIRCLSSignalReadContext *roContext); +#endif +static void FIRCLSSignalInstallHandlers(FIRCLSSignalReadContext *roContext); +static void FIRCLSSignalHandler(int signal, siginfo_t *info, void *uapVoid); + +void FIRCLSSignalInitialize(FIRCLSSignalReadContext *roContext) { + if (!FIRCLSUnlinkIfExists(roContext->path)) { + FIRCLSSDKLog("Unable to reset the signal log file %s\n", strerror(errno)); + } + +#if CLS_USE_SIGALTSTACK + FIRCLSSignalInstallAltStack(roContext); +#endif + FIRCLSSignalInstallHandlers(roContext); +#if TARGET_IPHONE_SIMULATOR + // prevent the OpenGL stack (by way of OpenGLES.framework/libLLVMContainer.dylib) from installing + // signal handlers that do not chain back + // TODO: I don't believe this is necessary as of recent iOS releases + bool *ptr = dlsym(RTLD_DEFAULT, "_ZN4llvm23DisablePrettyStackTraceE"); + if (ptr) { + *ptr = true; + } +#endif +} + +void FIRCLSSignalEnumerateHandledSignals(void (^block)(int idx, int signal)) { + for (int i = 0; i < FIRCLSSignalCount; ++i) { + block(i, FIRCLSFatalSignals[i]); + } +} + +#if CLS_USE_SIGALTSTACK + +static void FIRCLSSignalInstallAltStack(FIRCLSSignalReadContext *roContext) { + stack_t signalStack; + stack_t originalStack; + + signalStack.ss_sp = _firclsContext.readonly->signalStack; + signalStack.ss_size = CLS_SIGNAL_HANDLER_STACK_SIZE; + signalStack.ss_flags = 0; + + if (sigaltstack(&signalStack, &originalStack) != 0) { + FIRCLSSDKLog("Unable to setup stack %s\n", strerror(errno)); + + return; + } + + roContext->originalStack.ss_sp = NULL; + roContext->originalStack = originalStack; +} + +#endif + +static void FIRCLSSignalInstallHandlers(FIRCLSSignalReadContext *roContext) { + FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) { + struct sigaction action; + struct sigaction previousAction; + + action.sa_sigaction = FIRCLSSignalHandler; + // SA_RESETHAND seems like it would be great, but it doesn't appear to + // work correctly. After taking a signal, causing another identical signal in + // the handler will *not* cause the default handler to be involved (which should + // terminate the process). I've found some evidence that others have seen this + // behavior on MAC OS X. + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + + sigemptyset(&action.sa_mask); + + previousAction.sa_sigaction = NULL; + if (sigaction(signal, &action, &previousAction) != 0) { + FIRCLSSDKLog("Unable to install handler for %d (%s)\n", signal, strerror(errno)); + } + + // store the last action, so it can be recalled + roContext->originalActions[idx].sa_sigaction = NULL; + + if (previousAction.sa_sigaction) { + roContext->originalActions[idx] = previousAction; + } + }); +} + +void FIRCLSSignalCheckHandlers(void) { + if (_firclsContext.readonly->debuggerAttached) { + // Adding this log to remind user deattachs from the debugger. Besides FIRCLSSignal, this logic is on FIRCLSMachException and FIRCLSException as well. Only log once since the check is same. + FIRCLSSDKLog("[Crashlytics] App is attached to a debugger, to see the crash reports please detach from the debugger, https://firebase.google.com/docs/crashlytics/get-started?platform=ios#force-test-crash"); + return; + } + + FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) { + struct sigaction previousAction; + Dl_info info; + void *ptr; + + if (sigaction(signal, 0, &previousAction) != 0) { + fprintf(stderr, "Unable to read signal handler\n"); + return; + } + + ptr = previousAction.__sigaction_u.__sa_handler; + const char *signalName = NULL; + const char *codeName = NULL; + + FIRCLSSignalNameLookup(signal, 0, &signalName, &codeName); + + if (ptr == FIRCLSSignalHandler) { + return; + } + + const char *name = NULL; + if (dladdr(ptr, &info) != 0) { + name = info.dli_sname; + } + + fprintf(stderr, + "[Crashlytics] The signal %s has a non-Crashlytics handler (%s). This will interfere " + "with reporting.\n", + signalName, name); + }); +} + +void FIRCLSSignalSafeRemoveHandlers(bool includingAbort) { + FIRCLSSignalEnumerateHandledSignals(^(int idx, int signal) { + struct sigaction sa; + + if (!includingAbort && (signal == SIGABRT)) { + return; + } + + sa.sa_handler = SIG_DFL; + sigemptyset(&sa.sa_mask); + + if (sigaction(signal, &sa, NULL) != 0) { + FIRCLSSDKLog("Unable to set default handler for %d (%s)\n", signal, strerror(errno)); + } + }); +} + +bool FIRCLSSignalSafeInstallPreexistingHandlers(FIRCLSSignalReadContext *roContext, + const int signal, + siginfo_t *info, + void *uapVoid) { + __block bool success = true; + + FIRCLSSignalSafeRemoveHandlers(true); + +#if CLS_USE_SIGALTSTACK + + // re-install the original stack, if needed + if (roContext->originalStack.ss_sp) { + if (sigaltstack(&roContext->originalStack, 0) != 0) { + FIRCLSSDKLog("Unable to setup stack %s\n", strerror(errno)); + + return false; + } + } + +#endif + + // re-install the original handlers, if any + FIRCLSSignalEnumerateHandledSignals(^(int idx, int currentSignal) { + if (roContext->originalActions[idx].sa_sigaction == NULL) { + return; + } + + if (sigaction(currentSignal, &roContext->originalActions[idx], 0) != 0) { + FIRCLSSDKLog("Unable to install handler for %d (%s)\n", currentSignal, strerror(errno)); + success = false; + } + + // invoke original handler for current signal + if (signal < 0) { + return; + } + if (signal == currentSignal) { + roContext->originalActions[idx].sa_sigaction(signal, info, uapVoid); + } + }); + + return success; +} + +void FIRCLSSignalNameLookup(int number, int code, const char **name, const char **codeName) { + if (!name || !codeName) { + return; + } + + *codeName = NULL; + + switch (number) { + case SIGABRT: + *name = "SIGABRT"; + *codeName = "ABORT"; + break; + case SIGBUS: + *name = "SIGBUS"; + break; + case SIGFPE: + *name = "SIGFPE"; + break; + case SIGILL: + *name = "SIGILL"; + break; + case SIGSEGV: + *name = "SIGSEGV"; + break; + case SIGSYS: + *name = "SIGSYS"; + break; + case SIGTRAP: + *name = "SIGTRAP"; + break; + default: + *name = "UNKNOWN"; + break; + } +} + +static void FIRCLSSignalRecordSignal(int savedErrno, siginfo_t *info, void *uapVoid) { + if (!_firclsContext.readonly) { + return; + } + + if (FIRCLSContextMarkAndCheckIfCrashed()) { + FIRCLSSDKLog("Error: aborting signal handler because crash has already occurred"); + exit(1); + return; + } + + FIRCLSFile file; + + if (!FIRCLSFileInitWithPath(&file, _firclsContext.readonly->signal.path, false)) { + FIRCLSSDKLog("Unable to open signal file\n"); + return; + } + + FIRCLSFileWriteSectionStart(&file, "signal"); + + FIRCLSFileWriteHashStart(&file); + + if (FIRCLSIsValidPointer(info)) { + FIRCLSFileWriteHashEntryUint64(&file, "number", info->si_signo); + FIRCLSFileWriteHashEntryUint64(&file, "code", info->si_code); + FIRCLSFileWriteHashEntryUint64(&file, "address", (uint64_t)info->si_addr); + + const char *name = NULL; + const char *codeName = NULL; + + FIRCLSSignalNameLookup(info->si_signo, info->si_code, &name, &codeName); + + FIRCLSFileWriteHashEntryString(&file, "name", name); + FIRCLSFileWriteHashEntryString(&file, "code_name", codeName); + } + + FIRCLSFileWriteHashEntryUint64(&file, "errno", savedErrno); + FIRCLSFileWriteHashEntryUint64(&file, "time", time(NULL)); + + FIRCLSFileWriteHashEnd(&file); + + FIRCLSFileWriteSectionEnd(&file); + + FIRCLSHandler(&file, mach_thread_self(), uapVoid); + + FIRCLSFileClose(&file); +} + +static void FIRCLSSignalHandler(int signal, siginfo_t *info, void *uapVoid) { + int savedErrno; + sigset_t set; + + // save errno, both because it is interesting, and so we can restore it afterwards + savedErrno = errno; + errno = 0; + + FIRCLSSDKLog("Signal: %d\n", signal); + + // it is important to do this before unmasking signals, otherwise we can get + // called in a loop + FIRCLSSignalSafeRemoveHandlers(true); + + sigfillset(&set); + if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) { + FIRCLSSDKLog("Unable to unmask signals - we risk infinite recursion here\n"); + } + + // check info and uapVoid, and set them to appropriate values if invalid. This can happen + // if we have been called without the SA_SIGINFO flag set + if (!FIRCLSIsValidPointer(info)) { + info = NULL; + } + + if (!FIRCLSIsValidPointer(uapVoid)) { + uapVoid = NULL; + } + + FIRCLSSignalRecordSignal(savedErrno, info, uapVoid); + + // re-install original handlers + if (_firclsContext.readonly) { + FIRCLSSignalSafeInstallPreexistingHandlers(&_firclsContext.readonly->signal, signal, info, + uapVoid); + } + + // restore errno + errno = savedErrno; +} +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h new file mode 100644 index 0000000..17d1481 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Handlers/FIRCLSSignal.h @@ -0,0 +1,56 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +#include +#include + +// per man sigaltstack, MINSIGSTKSZ is the minimum *overhead* needed to support +// a signal stack. The actual stack size must be larger. Let's pick the recommended +// size. +#if CLS_USE_SIGALTSTACK +#define CLS_SIGNAL_HANDLER_STACK_SIZE (SIGSTKSZ * 2) +#else +#define CLS_SIGNAL_HANDLER_STACK_SIZE 0 +#endif + +#if CLS_SIGNAL_SUPPORTED +#define FIRCLSSignalCount (7) + +typedef struct { + const char* path; + struct sigaction originalActions[FIRCLSSignalCount]; + +#if CLS_USE_SIGALTSTACK + stack_t originalStack; +#endif +} FIRCLSSignalReadContext; + +void FIRCLSSignalInitialize(FIRCLSSignalReadContext* roContext); +void FIRCLSSignalCheckHandlers(void); + +void FIRCLSSignalSafeRemoveHandlers(bool includingAbort); +bool FIRCLSSignalSafeInstallPreexistingHandlers(FIRCLSSignalReadContext* roContext, + const int signal, + siginfo_t* info, + void* uapVoid); + +void FIRCLSSignalNameLookup(int number, int code, const char** name, const char** codeName); + +void FIRCLSSignalEnumerateHandledSignals(void (^block)(int idx, int signal)); +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c new file mode 100644 index 0000000..206b9a4 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.c @@ -0,0 +1,238 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSHost.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include +#include +#include +#include +#include +#include +#include + +void* FIRCLSAllocatorSafeAllocateFromRegion(FIRCLSAllocationRegion* region, size_t size); + +FIRCLSAllocatorRef FIRCLSAllocatorCreate(size_t writableSpace, size_t readableSpace) { + FIRCLSAllocatorRef allocator; + FIRCLSAllocationRegion writableRegion; + FIRCLSAllocationRegion readableRegion; + size_t allocationSize; + vm_size_t pageSize; + void* buffer; + + // | GUARD | WRITABLE_REGION | GUARD | READABLE_REGION | GUARD | + + pageSize = FIRCLSHostGetPageSize(); + + readableSpace += sizeof(FIRCLSAllocator); // add the space for our allocator itself + + // we can only protect at the page level, so we need all of our regions to be + // exact multiples of pages. But, we don't need anything in the special-case of zero. + + writableRegion.size = 0; + if (writableSpace > 0) { + writableRegion.size = ((writableSpace / pageSize) + 1) * pageSize; + } + + readableRegion.size = 0; + if (readableSpace > 0) { + readableRegion.size = ((readableSpace / pageSize) + 1) * pageSize; + } + + // Make one big, continuous allocation, adding additional pages for our guards. Note + // that we cannot use malloc (or valloc) in this case, because we need to assert full + // ownership over these allocations. mmap is a much better choice. We also mark these + // pages as MAP_NOCACHE. + allocationSize = writableRegion.size + readableRegion.size + pageSize * 3; + buffer = + mmap(0, allocationSize, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE | MAP_NOCACHE, -1, 0); + if (buffer == MAP_FAILED) { + FIRCLSSDKLogError("Mapping failed %s\n", strerror(errno)); + return NULL; + } + + // move our cursors into position + writableRegion.cursor = (void*)((uintptr_t)buffer + pageSize); + readableRegion.cursor = (void*)((uintptr_t)buffer + pageSize + writableRegion.size + pageSize); + writableRegion.start = writableRegion.cursor; + readableRegion.start = readableRegion.cursor; + + FIRCLSSDKLogInfo("Mapping: %p %p %p, total: %zu K\n", buffer, writableRegion.start, + readableRegion.start, allocationSize / 1024); + + // protect first guard page + if (mprotect(buffer, pageSize, PROT_NONE) != 0) { + FIRCLSSDKLogError("First guard protection failed %s\n", strerror(errno)); + return NULL; + } + + // middle guard + if (mprotect((void*)((uintptr_t)buffer + pageSize + writableRegion.size), pageSize, PROT_NONE) != + 0) { + FIRCLSSDKLogError("Middle guard protection failed %s\n", strerror(errno)); + return NULL; + } + + // end guard + if (mprotect((void*)((uintptr_t)buffer + pageSize + writableRegion.size + pageSize + + readableRegion.size), + pageSize, PROT_NONE) != 0) { + FIRCLSSDKLogError("Last guard protection failed %s\n", strerror(errno)); + return NULL; + } + + // now, perform our first "allocation", which is to place our allocator into the read-only region + allocator = FIRCLSAllocatorSafeAllocateFromRegion(&readableRegion, sizeof(FIRCLSAllocator)); + + // set up its data structure + allocator->buffer = buffer; + allocator->protectionEnabled = false; + allocator->readableRegion = readableRegion; + allocator->writeableRegion = writableRegion; + + FIRCLSSDKLogDebug("Allocator successfully created %p", allocator); + + return allocator; +} + +void FIRCLSAllocatorDestroy(FIRCLSAllocatorRef allocator) { + if (allocator) { + } +} + +bool FIRCLSAllocatorProtect(FIRCLSAllocatorRef allocator) { + void* address; + + if (!FIRCLSIsValidPointer(allocator)) { + FIRCLSSDKLogError("Invalid allocator"); + return false; + } + + if (allocator->protectionEnabled) { + FIRCLSSDKLogWarn("Write protection already enabled"); + return true; + } + + // This has to be done first + allocator->protectionEnabled = true; + + vm_size_t pageSize = FIRCLSHostGetPageSize(); + + // readable region + address = + (void*)((uintptr_t)allocator->buffer + pageSize + allocator->writeableRegion.size + pageSize); + + return mprotect(address, allocator->readableRegion.size, PROT_READ) == 0; +} + +bool FIRCLSAllocatorUnprotect(FIRCLSAllocatorRef allocator) { + size_t bufferSize; + + if (!allocator) { + return false; + } + + vm_size_t pageSize = FIRCLSHostGetPageSize(); + + bufferSize = (uintptr_t)allocator->buffer + pageSize + allocator->writeableRegion.size + + pageSize + allocator->readableRegion.size + pageSize; + + allocator->protectionEnabled = + !(mprotect(allocator->buffer, bufferSize, PROT_READ | PROT_WRITE) == 0); + + return allocator->protectionEnabled; +} + +void* FIRCLSAllocatorSafeAllocateFromRegion(FIRCLSAllocationRegion* region, size_t size) { + void* newCursor; + void* originalCursor; + + // Here's the idea + // - read the current cursor + // - compute what our new cursor should be + // - attempt a swap + // if the swap fails, some other thread has modified stuff, and we have to start again + // if the swap works, everything has been updated correctly and we are done + do { + originalCursor = region->cursor; + + // this shouldn't happen unless we make a mistake with our size pre-computations + if ((uintptr_t)originalCursor - (uintptr_t)region->start + size > region->size) { + FIRCLSSDKLog("Unable to allocate sufficient memory, falling back to malloc\n"); + void* ptr = malloc(size); + if (!ptr) { + FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocateFromRegion\n"); + return NULL; + } + return ptr; + } + + newCursor = (void*)((uintptr_t)originalCursor + size); + } while (!atomic_compare_exchange_strong(®ion->cursor, &originalCursor, newCursor)); + + return originalCursor; +} + +void* FIRCLSAllocatorSafeAllocate(FIRCLSAllocatorRef allocator, + size_t size, + FIRCLSAllocationType type) { + FIRCLSAllocationRegion* region; + + if (!allocator) { + // fall back to malloc in this case + FIRCLSSDKLog("Allocator invalid, falling back to malloc\n"); + void* ptr = malloc(size); + if (!ptr) { + FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); + return NULL; + } + return ptr; + } + + if (allocator->protectionEnabled) { + FIRCLSSDKLog("Allocator already protected, falling back to malloc\n"); + void* ptr = malloc(size); + if (!ptr) { + FIRCLSSDKLog("Unable to malloc in FIRCLSAllocatorSafeAllocate\n"); + return NULL; + } + return ptr; + } + + switch (type) { + case CLS_READONLY: + region = &allocator->readableRegion; + break; + case CLS_READWRITE: + region = &allocator->writeableRegion; + break; + default: + return NULL; + } + + return FIRCLSAllocatorSafeAllocateFromRegion(region, size); +} + +void FIRCLSAllocatorFree(FIRCLSAllocatorRef allocator, void* ptr) { + if (!allocator) { + free(ptr); + } + + // how do we do deallocations? +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h new file mode 100644 index 0000000..ae7a8a4 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSAllocate.h @@ -0,0 +1,48 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +#pragma once + +#include +#include + +typedef enum { CLS_READONLY = 0, CLS_READWRITE = 1 } FIRCLSAllocationType; + +typedef struct { + size_t size; + void* start; + _Atomic(void*) volatile cursor; +} FIRCLSAllocationRegion; + +typedef struct { + void* buffer; + bool protectionEnabled; + FIRCLSAllocationRegion writeableRegion; + FIRCLSAllocationRegion readableRegion; +} FIRCLSAllocator; +typedef FIRCLSAllocator* FIRCLSAllocatorRef; + +FIRCLSAllocatorRef FIRCLSAllocatorCreate(size_t writableSpace, size_t readableSpace); +void FIRCLSAllocatorDestroy(FIRCLSAllocatorRef allocator); + +bool FIRCLSAllocatorProtect(FIRCLSAllocatorRef allocator); +bool FIRCLSAllocatorUnprotect(FIRCLSAllocatorRef allocator); + +void* FIRCLSAllocatorSafeAllocate(FIRCLSAllocatorRef allocator, + size_t size, + FIRCLSAllocationType type); +const char* FIRCLSAllocatorSafeStrdup(FIRCLSAllocatorRef allocator, const char* string); +void FIRCLSAllocatorFree(FIRCLSAllocatorRef allocator, void* ptr); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.h new file mode 100644 index 0000000..02570f1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.h @@ -0,0 +1,37 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#if defined(__IPHONE_15_0) +#define CLS_METRICKIT_SUPPORTED (__has_include() && TARGET_OS_IOS) +#else +#define CLS_METRICKIT_SUPPORTED 0 +#endif + +#if CLS_METRICKIT_SUPPORTED +#import + +/* + * Helper class for parsing the `MXCallStackTree` that we receive from MetricKit. Flattens the + * nested structure into a structure similar to what is used in Crashlytics. + */ +@interface FIRCLSCallStackTree : NSObject + +- (instancetype)initWithMXCallStackTree:(MXCallStackTree *)callStackTree API_AVAILABLE(ios(14.0)); +- (NSArray *)getArrayRepresentation; +- (NSArray *)getFramesOfBlamedThread; +- (instancetype)init NS_UNAVAILABLE; + +@end +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.m new file mode 100644 index 0000000..44aaaeb --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.m @@ -0,0 +1,147 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSCallStackTree.h" + +#if CLS_METRICKIT_SUPPORTED + +@interface FIRCLSFrame : NSObject +@property long address; +@property long sampleCount; +@property long offsetIntoBinaryTextSegment; +@property NSString *binaryName; +@property NSUUID *binaryUUID; +@end + +@implementation FIRCLSFrame +@end + +@interface FIRCLSThread : NSObject +@property NSString *threadName; +@property BOOL threadBlamed; +@property NSArray *frames; +@end + +@implementation FIRCLSThread +@end + +@interface FIRCLSCallStackTree () +@property NSArray *threads; +@property(nonatomic) BOOL callStackPerThread; + +@end + +@implementation FIRCLSCallStackTree + +- (instancetype)initWithMXCallStackTree:(MXCallStackTree *)callStackTree { + NSData *jsonCallStackTree = callStackTree.JSONRepresentation; + if ([jsonCallStackTree length] == 0) return nil; + + NSError *error = nil; + NSDictionary *jsonDictionary = [NSJSONSerialization JSONObjectWithData:jsonCallStackTree + options:0 + error:&error]; + if (error) { + NSLog(@"Crashlytics: error creating json"); + return nil; + } + self = [super init]; + if (!self) { + return nil; + } + _callStackPerThread = [[jsonDictionary objectForKey:@"callStackPerThread"] boolValue]; + + // Recurse through the frames in the callStackTree and add them all to an array + NSMutableArray *threads = [[NSMutableArray alloc] init]; + NSArray *callStacks = jsonDictionary[@"callStacks"]; + for (id object in callStacks) { + NSMutableArray *frames = [[NSMutableArray alloc] init]; + [self flattenSubFrames:object[@"callStackRootFrames"] intoFrames:frames]; + FIRCLSThread *thread = [[FIRCLSThread alloc] init]; + thread.threadBlamed = [[object objectForKey:@"threadAttributed"] boolValue]; + thread.frames = frames; + [threads addObject:thread]; + } + _threads = threads; + return self; +} + +// Flattens the nested structure we receive from MetricKit into an array of frames. +- (void)flattenSubFrames:(NSArray *)callStacks intoFrames:(NSMutableArray *)frames { + NSDictionary *rootFrames = [callStacks firstObject]; + FIRCLSFrame *frame = [[FIRCLSFrame alloc] init]; + frame.offsetIntoBinaryTextSegment = + [[rootFrames valueForKey:@"offsetIntoBinaryTextSegment"] longValue]; + frame.address = [[rootFrames valueForKey:@"address"] longValue]; + frame.sampleCount = [[rootFrames valueForKey:@"sampleCount"] longValue]; + frame.binaryUUID = [rootFrames valueForKey:@"binaryUUID"]; + frame.binaryName = [rootFrames valueForKey:@"binaryName"]; + + [frames addObject:frame]; + + // Recurse through any subframes and add them to the array. + if ([rootFrames objectForKey:@"subFrames"]) { + [self flattenSubFrames:[rootFrames objectForKey:@"subFrames"] intoFrames:frames]; + } +} + +- (NSArray *)getArrayRepresentation { + NSMutableArray *threadArray = [[NSMutableArray alloc] init]; + for (FIRCLSThread *thread in self.threads) { + [threadArray addObject:[self getDictionaryRepresentation:thread]]; + } + return threadArray; +} + +- (NSDictionary *)getDictionaryRepresentation:(FIRCLSThread *)thread { + NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; + [dictionary setObject:@{} forKey:@"registers"]; + NSMutableArray *frameArray = [[NSMutableArray alloc] init]; + for (FIRCLSFrame *frame in thread.frames) { + [frameArray addObject:[NSNumber numberWithLong:frame.address]]; + } + [dictionary setObject:frameArray forKey:@"stacktrace"]; + [dictionary setObject:[NSNumber numberWithBool:thread.threadBlamed] forKey:@"crashed"]; + return dictionary; +} + +- (NSArray *)getFramesOfBlamedThread { + for (FIRCLSThread *thread in self.threads) { + if (thread.threadBlamed) { + return [self convertFramesFor:thread]; + } + } + if ([self.threads count] > 0) { + return [self convertFramesFor:self.threads.firstObject]; + } + return [NSArray array]; +} + +- (NSArray *)convertFramesFor:(FIRCLSThread *)thread { + NSMutableArray *frames = [[NSMutableArray alloc] init]; + for (FIRCLSFrame *frame in thread.frames) { + [frames addObject:@{ + @"pc" : [NSNumber numberWithLong:frame.address], + @"offset" : [NSNumber numberWithLong:frame.offsetIntoBinaryTextSegment], + @"line" : @0 + }]; + } + return frames; +} + +@end + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h new file mode 100644 index 0000000..83807f1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h @@ -0,0 +1,38 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSContextInitData : NSObject + +@property(nonatomic, copy, nullable) NSString* customBundleId; +@property(nonatomic, copy) NSString* rootPath; +@property(nonatomic, copy) NSString* previouslyCrashedFileRootPath; +@property(nonatomic, copy) NSString* sessionId; +@property(nonatomic, copy) NSString* appQualitySessionId; +@property(nonatomic, copy) NSString* betaToken; +@property(nonatomic) BOOL errorsEnabled; +@property(nonatomic) BOOL customExceptionsEnabled; +@property(nonatomic) uint32_t maxCustomExceptions; +@property(nonatomic) uint32_t maxErrorLogSize; +@property(nonatomic) uint32_t maxLogSize; +@property(nonatomic) uint32_t maxKeyValues; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.m new file mode 100644 index 0000000..9f7d9e7 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.m @@ -0,0 +1,18 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSContextInitData.h" + +@implementation FIRCLSContextInitData +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h new file mode 100644 index 0000000..6d62483 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h @@ -0,0 +1,89 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +// macro trickiness +#define CONCAT_EXPANDED(a, b) a##b +#define CONCAT(a, b) CONCAT_EXPANDED(a, b) + +// These macros generate a function to force a symbol for the containing .o, to work around an issue +// where strip will not strip debug information without a symbol to strip. +#define DUMMY_FUNCTION_NAME(x) CONCAT(fircls_strip_this_, x) +#define INJECT_STRIP_SYMBOL(x) \ + void DUMMY_FUNCTION_NAME(x)(void) { \ + } + +// These make some target os types available to previous versions of xcode that do not yet have them +// in their SDKs +#ifndef TARGET_OS_IOS +#define TARGET_OS_IOS TARGET_OS_IPHONE +#endif + +#ifndef TARGET_OS_WATCH +#define TARGET_OS_WATCH 0 +#endif + +#ifndef TARGET_OS_TV +#define TARGET_OS_TV 0 +#endif + +// Whether MetricKit should be supported +#if defined(__IPHONE_15_0) +#define CLS_METRICKIT_SUPPORTED (__has_include() && TARGET_OS_IOS) +#else +#define CLS_METRICKIT_SUPPORTED 0 +#endif + +// These help compile based on availability of technologies/frameworks. +#define CLS_TARGET_OS_OSX (TARGET_OS_MAC && !TARGET_OS_IPHONE) +#define CLS_TARGET_OS_HAS_UIKIT (TARGET_OS_IOS || TARGET_OS_TV) + +// arch definitions +#if defined(__arm__) || defined(__arm64__) || defined(__arm64e__) +#include +#endif + +// VisionOS support +#if defined(TARGET_OS_VISION) && TARGET_OS_VISION +#define CLS_TARGET_OS_VISION 1 +#else +#define CLS_TARGET_OS_VISION 0 +#endif + +#if defined(__arm__) +#define CLS_CPU_ARM 1 +#endif +#if defined(__arm64__) || defined(__arm64e__) +#define CLS_CPU_ARM64 1 +#endif +#if defined(__ARM_ARCH_7S__) +#define CLS_CPU_ARMV7S 1 +#endif +#if defined(_ARM_ARCH_7) +#define CLS_CPU_ARMV7 1 +#endif +#if defined(_ARM_ARCH_6) +#define CLS_CPU_ARMV6 1 +#endif +#if defined(__i386__) +#define CLS_CPU_I386 1 +#endif +#if defined(__x86_64__) +#define CLS_CPU_X86_64 1 +#endif +#define CLS_CPU_X86 (CLS_CPU_I386 || CLS_CPU_X86_64) +#define CLS_CPU_64BIT (CLS_CPU_X86_64 || CLS_CPU_ARM64) diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h new file mode 100644 index 0000000..fc90eea --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h @@ -0,0 +1,32 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" + +#define CLS_MEMORY_PROTECTION_ENABLED 1 +#define CLS_COMPACT_UNWINDED_ENABLED 1 +#define CLS_DWARF_UNWINDING_ENABLED 1 + +#define CLS_USE_SIGALTSTACK (!TARGET_OS_WATCH && !TARGET_OS_TV) +#define CLS_CAN_SUSPEND_THREADS !TARGET_OS_WATCH +#define CLS_MACH_EXCEPTION_SUPPORTED (!TARGET_OS_WATCH && !TARGET_OS_TV) +#define CLS_SIGNAL_SUPPORTED !TARGET_OS_WATCH // As of WatchOS 3, Signal crashes are not supported + +#define CLS_COMPACT_UNWINDING_SUPPORTED \ + ((CLS_CPU_I386 || CLS_CPU_X86_64 || CLS_CPU_ARM64) && CLS_COMPACT_UNWINDED_ENABLED) + +#define CLS_DWARF_UNWINDING_SUPPORTED \ + (CLS_COMPACT_UNWINDING_SUPPORTED && CLS_DWARF_UNWINDING_ENABLED) diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.h new file mode 100644 index 0000000..0b8c90c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.h @@ -0,0 +1,110 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +// Required for 1P builds +#include +#include +#include + +#if defined(__OBJC__) +#import +#endif + +__BEGIN_DECLS + +typedef struct { + int fd; + int collectionDepth; + bool needComma; + + bool bufferWrites; + char* writeBuffer; + size_t writeBufferLength; + + off_t writtenLength; +} FIRCLSFile; +typedef FIRCLSFile* FIRCLSFileRef; + +#define CLS_FILE_MAX_STRING_LENGTH (10240) +#define CLS_FILE_HEX_BUFFER \ + (32) // must be at least 2, and should be even (to account for 2 chars per hex value) +#define CLS_FILE_MAX_WRITE_ATTEMPTS (50) + +extern const size_t FIRCLSWriteBufferLength; + +// make sure to stop work if either FIRCLSFileInit... method returns false, because the FIRCLSFile +// struct will contain garbage data! +bool FIRCLSFileInitWithPath(FIRCLSFile* file, const char* path, bool bufferWrites); +bool FIRCLSFileInitWithPathMode(FIRCLSFile* file, + const char* path, + bool appendMode, + bool bufferWrites); + +void FIRCLSFileFlushWriteBuffer(FIRCLSFile* file); +bool FIRCLSFileClose(FIRCLSFile* file); +bool FIRCLSFileCloseWithOffset(FIRCLSFile* file, off_t* finalSize); +bool FIRCLSFileIsOpen(FIRCLSFile* file); + +bool FIRCLSFileLoopWithWriteBlock(const void* buffer, + size_t length, + ssize_t (^writeBlock)(const void* partialBuffer, + size_t partialLength)); +bool FIRCLSFileWriteWithRetries(int fd, const void* buffer, size_t length); + +// writing +void FIRCLSFileWriteSectionStart(FIRCLSFile* file, const char* name); +void FIRCLSFileWriteSectionEnd(FIRCLSFile* file); + +void FIRCLSFileWriteHashStart(FIRCLSFile* file); +void FIRCLSFileWriteHashEnd(FIRCLSFile* file); +void FIRCLSFileWriteHashKey(FIRCLSFile* file, const char* key); +void FIRCLSFileWriteHashEntryUint64(FIRCLSFile* file, const char* key, uint64_t value); +void FIRCLSFileWriteHashEntryInt64(FIRCLSFile* file, const char* key, int64_t value); +void FIRCLSFileWriteHashEntryString(FIRCLSFile* file, const char* key, const char* value); +void FIRCLSFileWriteStringUnquoted(FIRCLSFile* file, const char* string); +#if defined(__OBJC__) +void FIRCLSFileWriteHashEntryNSString(FIRCLSFile* file, const char* key, NSString* string); +void FIRCLSFileWriteHashEntryNSStringUnlessNilOrEmpty(FIRCLSFile* file, + const char* key, + NSString* string); +#endif +void FIRCLSFileWriteHashEntryHexEncodedString(FIRCLSFile* file, const char* key, const char* value); +void FIRCLSFileWriteHashEntryBoolean(FIRCLSFile* file, const char* key, bool value); + +void FIRCLSFileWriteArrayStart(FIRCLSFile* file); +void FIRCLSFileWriteArrayEnd(FIRCLSFile* file); +void FIRCLSFileWriteArrayEntryUint64(FIRCLSFile* file, uint64_t value); +void FIRCLSFileWriteArrayEntryString(FIRCLSFile* file, const char* value); +void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* value); + +void FIRCLSFileFDWriteUInt64(int fd, uint64_t number, bool hex); +void FIRCLSFileFDWriteInt64(int fd, int64_t number); +void FIRCLSFileWriteUInt64(FIRCLSFile* file, uint64_t number, bool hex); +void FIRCLSFileWriteInt64(FIRCLSFile* file, int64_t number); + +#if defined(__OBJC__) && TARGET_OS_MAC +NSArray* FIRCLSFileReadSections(const char* path, + bool deleteOnFailure, + NSObject* (^transformer)(id obj)); +NSString* FIRCLSFileHexEncodeString(const char* string); +NSString* FIRCLSFileHexDecodeString(const char* string); +#endif + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m new file mode 100644 index 0000000..204782a --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSFile.m @@ -0,0 +1,723 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#include "Crashlytics/Shared/FIRCLSByteUtility.h" + +#if TARGET_OS_MAC +#include +#endif + +#include + +#include +#include + +#include + +// uint64_t should only have max 19 chars in base 10, and less in base 16 +static const size_t FIRCLSUInt64StringBufferLength = 21; +static const size_t FIRCLSStringBufferLength = 16; +const size_t FIRCLSWriteBufferLength = 1000; + +static bool FIRCLSFileInit( + FIRCLSFile* file, const char* path, int fdm, bool appendMode, bool bufferWrites); + +static void FIRCLSFileWriteToFileDescriptorOrBuffer(FIRCLSFile* file, + const char* string, + size_t length); +static void FIRCLSFileWriteToBuffer(FIRCLSFile* file, const char* string, size_t length); +static void FIRCLSFileWriteToFileDescriptor(FIRCLSFile* file, const char* string, size_t length); + +short FIRCLSFilePrepareUInt64(char* buffer, uint64_t number, bool hex); + +static void FIRCLSFileWriteString(FIRCLSFile* file, const char* string); +static void FIRCLSFileWriteHexEncodedString(FIRCLSFile* file, const char* string); +static void FIRCLSFileWriteBool(FIRCLSFile* file, bool value); + +static void FIRCLSFileWriteCollectionStart(FIRCLSFile* file, const char openingChar); +static void FIRCLSFileWriteCollectionEnd(FIRCLSFile* file, const char closingChar); +static void FIRCLSFileWriteCollectionEntryProlog(FIRCLSFile* file); +static void FIRCLSFileWriteCollectionEntryEpilog(FIRCLSFile* file); + +#define CLS_FILE_DEBUG_LOGGING 0 + +#pragma mark - File Structure +static bool FIRCLSFileInit( + FIRCLSFile* file, const char* path, int fd, bool appendMode, bool bufferWrites) { + if (!file) { + FIRCLSSDKLog("Error: file is null\n"); + return false; + } + + if (fd < 0) { + FIRCLSSDKLog("Error: file descriptor invalid\n"); + return false; + } + + memset(file, 0, sizeof(FIRCLSFile)); + + file->fd = fd; + + file->bufferWrites = bufferWrites; + if (bufferWrites) { + file->writeBuffer = malloc(FIRCLSWriteBufferLength * sizeof(char)); + if (!file->writeBuffer) { + FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileInit"); + return false; + } + + file->writeBufferLength = 0; + } + + file->writtenLength = 0; + if (appendMode) { + NSError* attributesError; + NSString* objCPath = [NSString stringWithCString:path encoding:NSUTF8StringEncoding]; + NSDictionary* fileAttributes = + [[NSFileManager defaultManager] attributesOfItemAtPath:objCPath error:&attributesError]; + if (attributesError != nil) { + FIRCLSErrorLog(@"Failed to read filesize from %@ with error %@", objCPath, attributesError); + return false; + } + NSNumber* fileSizeNumber = [fileAttributes objectForKey:NSFileSize]; + long long currentFileSize = [fileSizeNumber longLongValue]; + if (currentFileSize > 0) { + file->writtenLength += currentFileSize; + } + } + + return true; +} + +bool FIRCLSFileInitWithPath(FIRCLSFile* file, const char* path, bool bufferWrites) { + return FIRCLSFileInitWithPathMode(file, path, true, bufferWrites); +} + +bool FIRCLSFileInitWithPathMode(FIRCLSFile* file, + const char* path, + bool appendMode, + bool bufferWrites) { + if (!file) { + FIRCLSSDKLog("Error: file is null\n"); + return false; + } + + int mask = O_WRONLY | O_CREAT; + + if (appendMode) { + mask |= O_APPEND; + } else { + mask |= O_TRUNC; + } + + // make sure to call FIRCLSFileInit no matter what + int fd = -1; + if (path) { +#if TARGET_OS_IPHONE + /* + * data-protected non-portable open(2) : + * int open_dprotected_np(user_addr_t path, int flags, int class, int dpflags, int mode) + */ + fd = open_dprotected_np(path, mask, 4, 0, 0644); +#else + fd = open(path, mask, 0644); +#endif + + if (fd < 0) { + FIRCLSSDKLog("Error: Unable to open file %s\n", strerror(errno)); + } + } + + return FIRCLSFileInit(file, path, fd, appendMode, bufferWrites); +} + +bool FIRCLSFileClose(FIRCLSFile* file) { + return FIRCLSFileCloseWithOffset(file, NULL); +} + +bool FIRCLSFileCloseWithOffset(FIRCLSFile* file, off_t* finalSize) { + if (!FIRCLSIsValidPointer(file)) { + return false; + } + + if (file->bufferWrites && FIRCLSIsValidPointer(file->writeBuffer)) { + if (file->writeBufferLength > 0) { + FIRCLSFileFlushWriteBuffer(file); + } + free(file->writeBuffer); + } + + if (FIRCLSIsValidPointer(finalSize)) { + *finalSize = file->writtenLength; + } + + if (close(file->fd) != 0) { + FIRCLSSDKLog("Error: Unable to close file %s\n", strerror(errno)); + return false; + } + + memset(file, 0, sizeof(FIRCLSFile)); + file->fd = -1; + + return true; +} + +bool FIRCLSFileIsOpen(FIRCLSFile* file) { + if (!FIRCLSIsValidPointer(file)) { + return false; + } + + return file->fd > -1; +} + +#pragma mark - Core Writing API +void FIRCLSFileFlushWriteBuffer(FIRCLSFile* file) { + if (!FIRCLSIsValidPointer(file)) { + return; + } + + if (!file->bufferWrites) { + return; + } + + FIRCLSFileWriteToFileDescriptor(file, file->writeBuffer, file->writeBufferLength); + file->writeBufferLength = 0; +} + +static void FIRCLSFileWriteToFileDescriptorOrBuffer(FIRCLSFile* file, + const char* string, + size_t length) { + if (file->bufferWrites) { + if (file->writeBufferLength + length > FIRCLSWriteBufferLength - 1) { + // fill remaining space in buffer + size_t remainingSpace = FIRCLSWriteBufferLength - file->writeBufferLength - 1; + FIRCLSFileWriteToBuffer(file, string, remainingSpace); + FIRCLSFileFlushWriteBuffer(file); + + // write remainder of string to newly-emptied buffer + size_t remainingLength = length - remainingSpace; + FIRCLSFileWriteToFileDescriptorOrBuffer(file, string + remainingSpace, remainingLength); + } else { + FIRCLSFileWriteToBuffer(file, string, length); + } + } else { + FIRCLSFileWriteToFileDescriptor(file, string, length); + } +} + +void FIRCLSFileWriteStringUnquoted(FIRCLSFile* file, const char* string) { + size_t length = strlen(string); + FIRCLSFileWriteToFileDescriptorOrBuffer(file, string, length); +} + +static void FIRCLSFileWriteToFileDescriptor(FIRCLSFile* file, const char* string, size_t length) { + if (!FIRCLSFileWriteWithRetries(file->fd, string, length)) { + return; + } + + file->writtenLength += length; +} + +// Beware calling this method directly: it will truncate the input string if it's longer +// than the remaining space in the buffer. It's safer to call through +// FIRCLSFileWriteToFileDescriptorOrBuffer. +static void FIRCLSFileWriteToBuffer(FIRCLSFile* file, const char* string, size_t length) { + size_t writeLength = length; + if (file->writeBufferLength + writeLength > FIRCLSWriteBufferLength - 1) { + writeLength = FIRCLSWriteBufferLength - file->writeBufferLength - 1; + } + strncpy(file->writeBuffer + file->writeBufferLength, string, writeLength); + file->writeBufferLength += writeLength; + file->writeBuffer[file->writeBufferLength] = '\0'; +} + +bool FIRCLSFileLoopWithWriteBlock(const void* buffer, + size_t length, + ssize_t (^writeBlock)(const void* buf, size_t len)) { + for (size_t count = 0; length > 0 && count < CLS_FILE_MAX_WRITE_ATTEMPTS; ++count) { + // try to write all that is left + ssize_t ret = writeBlock(buffer, length); + + if (length > SIZE_MAX) { + // if this happens we can't convert it to a signed version due to overflow + return false; + } + const ssize_t signedLength = (ssize_t)length; + + if (ret >= 0 && ret == signedLength) { + return true; + } + + // Write was unsuccessful (out of space, etc) + if (ret < 0) { + return false; + } + + // We wrote more bytes than we expected, abort + if (ret > signedLength) { + return false; + } + + // wrote a portion of the data, adjust and keep trying + if (ret > 0) { + length -= ret; + buffer += ret; + continue; + } + + // return value is <= 0, which is an error + break; + } + + return false; +} + +bool FIRCLSFileWriteWithRetries(int fd, const void* buffer, size_t length) { + return FIRCLSFileLoopWithWriteBlock(buffer, length, + ^ssize_t(const void* partialBuffer, size_t partialLength) { + return write(fd, partialBuffer, partialLength); + }); +} + +#pragma mark - Strings + +static void FIRCLSFileWriteUnbufferedStringWithSuffix(FIRCLSFile* file, + const char* string, + size_t length, + char suffix) { + char suffixBuffer[2]; + + // collapse the quote + suffix into one single write call, for a small performance win + suffixBuffer[0] = '"'; + suffixBuffer[1] = suffix; + + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "\"", 1); + FIRCLSFileWriteToFileDescriptorOrBuffer(file, string, length); + FIRCLSFileWriteToFileDescriptorOrBuffer(file, suffixBuffer, suffix == 0 ? 1 : 2); +} + +static void FIRCLSFileWriteStringWithSuffix(FIRCLSFile* file, + const char* string, + size_t length, + char suffix) { + // 2 for quotes, 1 for suffix (if present) and 1 more for null character + const size_t maxStringSize = FIRCLSStringBufferLength - (suffix == 0 ? 3 : 4); + + if (length >= maxStringSize) { + FIRCLSFileWriteUnbufferedStringWithSuffix(file, string, length, suffix); + return; + } + + // we are trying to achieve this in one write call + // <"><"> + + char buffer[FIRCLSStringBufferLength]; + + buffer[0] = '"'; + + strncpy(buffer + 1, string, length); + + buffer[length + 1] = '"'; + length += 2; + + if (suffix) { + buffer[length] = suffix; + length += 1; + } + + // Always add the terminator. strncpy above would copy the terminator, if we supplied length + 1, + // but since we do this suffix adjustment here, it's easier to just fix it up in both cases. + buffer[length + 1] = 0; + + FIRCLSFileWriteToFileDescriptorOrBuffer(file, buffer, length); +} + +void FIRCLSFileWriteString(FIRCLSFile* file, const char* string) { + if (!string) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "null", 4); + return; + } + + FIRCLSFileWriteStringWithSuffix(file, string, strlen(string), 0); +} + +void FIRCLSFileWriteHexEncodedString(FIRCLSFile* file, const char* string) { + if (!file) { + return; + } + + if (!string) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "null", 4); + return; + } + + char buffer[CLS_FILE_HEX_BUFFER]; + + memset(buffer, 0, sizeof(buffer)); + + size_t length = strlen(string); + + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "\"", 1); + + int bufferIndex = 0; + for (int i = 0; i < length; ++i) { + FIRCLSHexFromByte(string[i], &buffer[bufferIndex]); + + bufferIndex += 2; // 1 char => 2 hex values at a time + + // we can continue only if we have enough space for two more hex + // characters *and* a terminator. So, we need three total chars + // of space + if (bufferIndex >= CLS_FILE_HEX_BUFFER) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, buffer, CLS_FILE_HEX_BUFFER); + bufferIndex = 0; + } + } + + // Copy the remainder, which could even be the entire string, if it + // fit into the buffer completely. Be careful with bounds checking here. + // The string needs to be non-empty, and we have to have copied at least + // one pair of hex characters in. + if (bufferIndex > 0 && length > 0) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, buffer, bufferIndex); + } + + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "\"", 1); +} + +#pragma mark - Integers +void FIRCLSFileWriteUInt64(FIRCLSFile* file, uint64_t number, bool hex) { + char buffer[FIRCLSUInt64StringBufferLength]; + short i = FIRCLSFilePrepareUInt64(buffer, number, hex); + char* beginning = &buffer[i]; // Write from a pointer to the beginning of the string. + FIRCLSFileWriteToFileDescriptorOrBuffer(file, beginning, strlen(beginning)); +} + +void FIRCLSFileFDWriteUInt64(int fd, uint64_t number, bool hex) { + char buffer[FIRCLSUInt64StringBufferLength]; + short i = FIRCLSFilePrepareUInt64(buffer, number, hex); + char* beginning = &buffer[i]; // Write from a pointer to the beginning of the string. + FIRCLSFileWriteWithRetries(fd, beginning, strlen(beginning)); +} + +void FIRCLSFileWriteInt64(FIRCLSFile* file, int64_t number) { + if (number < 0) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "-", 1); + number *= -1; // make it positive + } + + FIRCLSFileWriteUInt64(file, number, false); +} + +void FIRCLSFileFDWriteInt64(int fd, int64_t number) { + if (number < 0) { + FIRCLSFileWriteWithRetries(fd, "-", 1); + number *= -1; // make it positive + } + + FIRCLSFileFDWriteUInt64(fd, number, false); +} + +short FIRCLSFilePrepareUInt64(char* buffer, uint64_t number, bool hex) { + uint32_t base = hex ? 16 : 10; + + // zero it out, which will add a terminator + memset(buffer, 0, FIRCLSUInt64StringBufferLength); + + // TODO: look at this closer + // I'm pretty sure there is a bug in this code that + // can result in numbers with leading zeros. Technically, + // those are not valid json. + + // Set current index. + short i = FIRCLSUInt64StringBufferLength - 1; + + // Loop through filling in the chars from the end. + do { + char value = number % base + '0'; + if (value > '9') { + value += 'a' - '9' - 1; + } + + buffer[--i] = value; + } while ((number /= base) > 0 && i > 0); + + // returns index pointing to the beginning of the string. + return i; +} + +void FIRCLSFileWriteBool(FIRCLSFile* file, bool value) { + if (value) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "true", 4); + } else { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "false", 5); + } +} + +void FIRCLSFileWriteSectionStart(FIRCLSFile* file, const char* name) { + FIRCLSFileWriteHashStart(file); + FIRCLSFileWriteHashKey(file, name); +} + +void FIRCLSFileWriteSectionEnd(FIRCLSFile* file) { + FIRCLSFileWriteHashEnd(file); + FIRCLSFileWriteToFileDescriptorOrBuffer(file, "\n", 1); +} + +void FIRCLSFileWriteCollectionStart(FIRCLSFile* file, const char openingChar) { + char string[2]; + + string[0] = ','; + string[1] = openingChar; + + if (file->needComma) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, string, 2); // write the separator + opening char + } else { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, &string[1], 1); // write only the opening char + } + + file->collectionDepth++; + + file->needComma = false; +} + +void FIRCLSFileWriteCollectionEnd(FIRCLSFile* file, const char closingChar) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, &closingChar, 1); + + if (file->collectionDepth <= 0) { + // FIRCLSSafeLog("Collection depth invariant violated\n"); + return; + } + + file->collectionDepth--; + + file->needComma = file->collectionDepth > 0; +} + +void FIRCLSFileWriteCollectionEntryProlog(FIRCLSFile* file) { + if (file->needComma) { + FIRCLSFileWriteToFileDescriptorOrBuffer(file, ",", 1); + } +} + +void FIRCLSFileWriteCollectionEntryEpilog(FIRCLSFile* file) { + file->needComma = true; +} + +void FIRCLSFileWriteHashStart(FIRCLSFile* file) { + FIRCLSFileWriteCollectionStart(file, '{'); +} + +void FIRCLSFileWriteHashEnd(FIRCLSFile* file) { + FIRCLSFileWriteCollectionEnd(file, '}'); +} + +void FIRCLSFileWriteHashKey(FIRCLSFile* file, const char* key) { + FIRCLSFileWriteCollectionEntryProlog(file); + + FIRCLSFileWriteStringWithSuffix(file, key, strlen(key), ':'); + + file->needComma = false; +} + +void FIRCLSFileWriteHashEntryUint64(FIRCLSFile* file, const char* key, uint64_t value) { + // no prolog needed because it comes from the key + + FIRCLSFileWriteHashKey(file, key); + FIRCLSFileWriteUInt64(file, value, false); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteHashEntryInt64(FIRCLSFile* file, const char* key, int64_t value) { + // prolog from key + FIRCLSFileWriteHashKey(file, key); + FIRCLSFileWriteInt64(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteHashEntryString(FIRCLSFile* file, const char* key, const char* value) { + FIRCLSFileWriteHashKey(file, key); + FIRCLSFileWriteString(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteHashEntryNSString(FIRCLSFile* file, const char* key, NSString* string) { + FIRCLSFileWriteHashEntryString(file, key, [string UTF8String]); +} + +void FIRCLSFileWriteHashEntryNSStringUnlessNilOrEmpty(FIRCLSFile* file, + const char* key, + NSString* string) { + if ([string length] > 0) { + FIRCLSFileWriteHashEntryString(file, key, [string UTF8String]); + } +} + +void FIRCLSFileWriteHashEntryHexEncodedString(FIRCLSFile* file, + const char* key, + const char* value) { + FIRCLSFileWriteHashKey(file, key); + FIRCLSFileWriteHexEncodedString(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteHashEntryBoolean(FIRCLSFile* file, const char* key, bool value) { + FIRCLSFileWriteHashKey(file, key); + FIRCLSFileWriteBool(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteArrayStart(FIRCLSFile* file) { + FIRCLSFileWriteCollectionStart(file, '['); +} + +void FIRCLSFileWriteArrayEnd(FIRCLSFile* file) { + FIRCLSFileWriteCollectionEnd(file, ']'); +} + +void FIRCLSFileWriteArrayEntryUint64(FIRCLSFile* file, uint64_t value) { + FIRCLSFileWriteCollectionEntryProlog(file); + + FIRCLSFileWriteUInt64(file, value, false); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteArrayEntryString(FIRCLSFile* file, const char* value) { + FIRCLSFileWriteCollectionEntryProlog(file); + + FIRCLSFileWriteString(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +void FIRCLSFileWriteArrayEntryHexEncodedString(FIRCLSFile* file, const char* value) { + FIRCLSFileWriteCollectionEntryProlog(file); + + FIRCLSFileWriteHexEncodedString(file, value); + + FIRCLSFileWriteCollectionEntryEpilog(file); +} + +NSArray* FIRCLSFileReadSections(const char* path, + bool deleteOnFailure, + NSObject* (^transformer)(id obj)) { + if (!FIRCLSIsValidPointer(path)) { + FIRCLSSDKLogError("Error: input path is invalid\n"); + return nil; + } + + NSString* pathString = [NSString stringWithUTF8String:path]; + NSString* contents = [NSString stringWithContentsOfFile:pathString + encoding:NSUTF8StringEncoding + error:nil]; + NSArray* components = [contents componentsSeparatedByString:@"\n"]; + + if (!components) { + if (deleteOnFailure) { + unlink(path); + } + + FIRCLSSDKLog("Unable to read file %s\n", path); + return nil; + } + + NSMutableArray* array = [NSMutableArray array]; + + // loop through all the entries, and + for (NSString* component in components) { + NSData* data = [component dataUsingEncoding:NSUTF8StringEncoding]; + + id obj = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; + if (!obj) { + continue; + } + + if (transformer) { + obj = transformer(obj); + } + + if (!obj) { + continue; + } + + [array addObject:obj]; + } + + return array; +} + +NSString* FIRCLSFileHexEncodeString(const char* string) { + size_t length = strlen(string); + char* encodedBuffer = malloc(length * 2 + 1); + + if (!encodedBuffer) { + FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexEncodeString"); + return nil; + } + + memset(encodedBuffer, 0, length * 2 + 1); + + int bufferIndex = 0; + for (int i = 0; i < length; ++i) { + FIRCLSHexFromByte(string[i], &encodedBuffer[bufferIndex]); + + bufferIndex += 2; // 1 char => 2 hex values at a time + } + + NSString* stringObject = [NSString stringWithUTF8String:encodedBuffer]; + + free(encodedBuffer); + + return stringObject; +} + +NSString* FIRCLSFileHexDecodeString(const char* string) { + size_t length = strlen(string); + char* decodedBuffer = malloc(length); // too long, but safe + if (!decodedBuffer) { + FIRCLSErrorLog(@"Unable to malloc in FIRCLSFileHexDecodeString"); + return nil; + } + + memset(decodedBuffer, 0, length); + + for (int i = 0; i < length / 2; ++i) { + size_t index = i * 2; + + uint8_t hiNybble = FIRCLSNybbleFromChar(string[index]); + uint8_t lowNybble = FIRCLSNybbleFromChar(string[index + 1]); + + if (hiNybble == FIRCLSInvalidCharNybble || lowNybble == FIRCLSInvalidCharNybble) { + // char is invalid, abort loop + break; + } + + decodedBuffer[i] = (hiNybble << 4) | lowNybble; + } + + NSString* strObject = [NSString stringWithUTF8String:decodedBuffer]; + + free(decodedBuffer); + + return strObject; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.c new file mode 100644 index 0000000..93d5071 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.c @@ -0,0 +1,101 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSContext.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +void FIRCLSSDKFileLog(FIRCLSInternalLogLevel level, const char* format, ...) { + if (!_firclsContext.readonly || !_firclsContext.writable) { + return; + } + + const char* path = _firclsContext.readonly->logPath; + if (!FIRCLSIsValidPointer(path)) { + return; + } + + if (_firclsContext.writable->internalLogging.logLevel > level) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (_firclsContext.writable->internalLogging.logFd == -1) { + _firclsContext.writable->internalLogging.logFd = open(path, O_WRONLY | O_CREAT | O_APPEND, 0644); + } + }); + + const int fd = _firclsContext.writable->internalLogging.logFd; + if (fd < 0) { + return; + } + + va_list args; + va_start(args, format); + +#if DEBUG && 0 + // It's nice to use printf here, so all the formatting works. However, its possible to hit a + // deadlock if you call vfprintf in a crash handler. So, this code is handy to keep, just in case, + // if there's a really tough thing to debug. + FILE* file = fopen(path, "a+"); + vfprintf(file, format, args); + fclose(file); +#else + size_t formatLength = strlen(format); + for (size_t idx = 0; idx < formatLength; ++idx) { + if (format[idx] != '%') { + write(fd, &format[idx], 1); + continue; + } + + idx++; // move to the format char + switch (format[idx]) { + case 'd': { + int value = va_arg(args, int); + FIRCLSFileFDWriteInt64(fd, value); + } break; + case 'u': { + uint32_t value = va_arg(args, uint32_t); + FIRCLSFileFDWriteUInt64(fd, value, false); + } break; + case 'p': { + uintptr_t value = va_arg(args, uintptr_t); + write(fd, "0x", 2); + FIRCLSFileFDWriteUInt64(fd, value, true); + } break; + case 's': { + const char* string = va_arg(args, const char*); + if (!string) { + string = "(null)"; + } + + write(fd, string, strlen(string)); + } break; + case 'x': { + unsigned int value = va_arg(args, unsigned int); + FIRCLSFileFDWriteUInt64(fd, value, true); + } break; + default: + // unhandled, back up to write out the percent + the format char + write(fd, &format[idx - 1], 2); + break; + } + } +#endif + va_end(args); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h new file mode 100644 index 0000000..3869889 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h @@ -0,0 +1,57 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#if __OBJC__ +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#define FIRCLSDeveloperLog(label, __FORMAT__, ...) \ + FIRCLSDebugLog(@"[" label "] " __FORMAT__, ##__VA_ARGS__); +#endif + +typedef enum { + FIRCLSInternalLogLevelUnknown = 0, + FIRCLSInternalLogLevelDebug = 1, + FIRCLSInternalLogLevelInfo = 2, + FIRCLSInternalLogLevelWarn = 3, + FIRCLSInternalLogLevelError = 4 +} FIRCLSInternalLogLevel; + +typedef struct { + int logFd; + FIRCLSInternalLogLevel logLevel; +} FIRCLSInternalLoggingWritableContext; + +#define FIRCLSSDKLogDebug(__FORMAT__, ...) \ + FIRCLSSDKFileLog(FIRCLSInternalLogLevelDebug, "DEBUG [%s:%d] " __FORMAT__, __FUNCTION__, \ + __LINE__, ##__VA_ARGS__) +#define FIRCLSSDKLogInfo(__FORMAT__, ...) \ + FIRCLSSDKFileLog(FIRCLSInternalLogLevelInfo, "INFO [%s:%d] " __FORMAT__, __FUNCTION__, \ + __LINE__, ##__VA_ARGS__) +#define FIRCLSSDKLogWarn(__FORMAT__, ...) \ + FIRCLSSDKFileLog(FIRCLSInternalLogLevelWarn, "WARN [%s:%d] " __FORMAT__, __FUNCTION__, \ + __LINE__, ##__VA_ARGS__) +#define FIRCLSSDKLogError(__FORMAT__, ...) \ + FIRCLSSDKFileLog(FIRCLSInternalLogLevelError, "ERROR [%s:%d] " __FORMAT__, __FUNCTION__, \ + __LINE__, ##__VA_ARGS__) + +#define FIRCLSSDKLog FIRCLSSDKLogWarn + +__BEGIN_DECLS + +void FIRCLSSDKFileLog(FIRCLSInternalLogLevel level, const char* format, ...) __printflike(2, 3); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h new file mode 100644 index 0000000..e03d99a --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h @@ -0,0 +1,24 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +__BEGIN_DECLS + +void FIRCLSDebugLog(NSString *message, ...); +void FIRCLSInfoLog(NSString *message, ...); +void FIRCLSWarningLog(NSString *message, ...); +void FIRCLSErrorLog(NSString *message, ...); + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.m new file mode 100644 index 0000000..e8cac73 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSLogger.m @@ -0,0 +1,52 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +FIRLoggerService kFIRLoggerCrashlytics = @"[FirebaseCrashlytics]"; + +NSString *const CrashlyticsMessageCode = @"I-CLS000000"; + +void FIRCLSDebugLog(NSString *message, ...) { + va_list args_ptr; + va_start(args_ptr, message); + FIRLogBasic(FIRLoggerLevelDebug, kFIRLoggerCrashlytics, CrashlyticsMessageCode, message, + args_ptr); + va_end(args_ptr); +} + +void FIRCLSInfoLog(NSString *message, ...) { + va_list args_ptr; + va_start(args_ptr, message); + FIRLogBasic(FIRLoggerLevelInfo, kFIRLoggerCrashlytics, CrashlyticsMessageCode, message, args_ptr); + va_end(args_ptr); +} + +void FIRCLSWarningLog(NSString *message, ...) { + va_list args_ptr; + va_start(args_ptr, message); + FIRLogBasic(FIRLoggerLevelWarning, kFIRLoggerCrashlytics, CrashlyticsMessageCode, message, + args_ptr); + va_end(args_ptr); +} + +void FIRCLSErrorLog(NSString *message, ...) { + va_list args_ptr; + va_start(args_ptr, message); + FIRLogBasic(FIRLoggerLevelError, kFIRLoggerCrashlytics, CrashlyticsMessageCode, message, + args_ptr); + va_end(args_ptr); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.c new file mode 100644 index 0000000..c25e0c9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.c @@ -0,0 +1,147 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#if defined(__arm__) || defined(__arm64__) +#include +#include +#endif + +#if CLS_CPU_X86_64 +#define GET_IP_REGISTER(r) (r->__ss.__rip) +#define GET_FP_REGISTER(r) (r->__ss.__rbp) +#define GET_SP_REGISTER(r) (r->__ss.__rsp) +#define GET_LR_REGISTER(r) 0 +#define SET_IP_REGISTER(r, v) (r->__ss.__rip = v) +#define SET_FP_REGISTER(r, v) (r->__ss.__rbp = v) +#define SET_SP_REGISTER(r, v) (r->__ss.__rsp = v) +#define SET_LR_REGISTER(r, v) +#elif CLS_CPU_I386 +#define GET_IP_REGISTER(r) (r->__ss.__eip) +#define GET_FP_REGISTER(r) (r->__ss.__ebp) +#define GET_SP_REGISTER(r) (r->__ss.__esp) +#define GET_LR_REGISTER(r) 0 +#define SET_IP_REGISTER(r, v) (r->__ss.__eip = v) +#define SET_FP_REGISTER(r, v) (r->__ss.__ebp = v) +#define SET_SP_REGISTER(r, v) (r->__ss.__esp = v) +#define SET_LR_REGISTER(r, v) +#elif CLS_CPU_ARM64 +// The arm_thread_state64_get_* macros translate down to the AUTIA and AUTIB instructions which +// authenticate the address, but don't clear the upper bits. From the docs: +// "If the authentication passes, the upper bits of the address are restored to enable +// subsequent use of the address. the authentication fails, the upper bits are corrupted and +// any subsequent use of the address results in a Translation fault." +// Since we only want the address (with the metadata in the upper bits masked out), we used the +// ptrauth_strip macro to clear the upper bits. +// +// We found later that ptrauth_strip doesn't seem to do anything. In many cases, the upper bits were +// already stripped, so for most non-system-library code, Crashlytics would still symbolicate. But +// for system libraries, the upper bits were being left in even when we called ptrauth_strip. +// Instead, we're bit masking and only allowing the latter 36 bits. +#define CLS_PTRAUTH_STRIP(pointer) ((uintptr_t)pointer & 0x0000000FFFFFFFFF) +#define GET_IP_REGISTER(r) (CLS_PTRAUTH_STRIP(arm_thread_state64_get_pc(r->__ss))) +#define GET_FP_REGISTER(r) (CLS_PTRAUTH_STRIP(arm_thread_state64_get_fp(r->__ss))) +#define GET_SP_REGISTER(r) (CLS_PTRAUTH_STRIP(arm_thread_state64_get_sp(r->__ss))) +#define GET_LR_REGISTER(r) (CLS_PTRAUTH_STRIP(arm_thread_state64_get_lr(r->__ss))) +#define SET_IP_REGISTER(r, v) arm_thread_state64_set_pc_fptr(r->__ss, (void*)v) +#define SET_FP_REGISTER(r, v) arm_thread_state64_set_fp(r->__ss, v) +#define SET_SP_REGISTER(r, v) arm_thread_state64_set_sp(r->__ss, v) +#define SET_LR_REGISTER(r, v) arm_thread_state64_set_lr_fptr(r->__ss, (void*)v) +#elif CLS_CPU_ARM +#define GET_IP_REGISTER(r) (r->__ss.__pc) +#define GET_FP_REGISTER(r) (r->__ss.__r[7]) +#define GET_SP_REGISTER(r) (r->__ss.__sp) +#define GET_LR_REGISTER(r) (r->__ss.__lr) +#define SET_IP_REGISTER(r, v) (r->__ss.__pc = v) +#define SET_FP_REGISTER(r, v) (r->__ss.__r[7] = v) +#define SET_SP_REGISTER(r, v) (r->__ss.__sp = v) +#define SET_LR_REGISTER(r, v) (r->__ss.__lr = v) +#else +#error "Architecture Unsupported" +#endif + +uintptr_t FIRCLSThreadContextGetPC(FIRCLSThreadContext* registers) { + if (!registers) { + return 0; + } + + return GET_IP_REGISTER(registers); +} + +uintptr_t FIRCLSThreadContextGetStackPointer(const FIRCLSThreadContext* registers) { + if (!registers) { + return 0; + } + + return GET_SP_REGISTER(registers); +} + +bool FIRCLSThreadContextSetStackPointer(FIRCLSThreadContext* registers, uintptr_t value) { + if (!FIRCLSIsValidPointer(registers)) { + return false; + } + + SET_SP_REGISTER(registers, value); + + return true; +} + +uintptr_t FIRCLSThreadContextGetLinkRegister(const FIRCLSThreadContext* registers) { + if (!FIRCLSIsValidPointer(registers)) { + return 0; + } + + return GET_LR_REGISTER(registers); +} + +bool FIRCLSThreadContextSetLinkRegister(FIRCLSThreadContext* registers, uintptr_t value) { + if (!FIRCLSIsValidPointer(registers)) { + return false; + } + + SET_LR_REGISTER(registers, value); + + return true; +} + +bool FIRCLSThreadContextSetPC(FIRCLSThreadContext* registers, uintptr_t value) { + if (!registers) { + return false; + } + + SET_IP_REGISTER(registers, value); + + return true; +} + +uintptr_t FIRCLSThreadContextGetFramePointer(const FIRCLSThreadContext* registers) { + if (!FIRCLSIsValidPointer(registers)) { + return 0; + } + + return GET_FP_REGISTER(registers); +} + +bool FIRCLSThreadContextSetFramePointer(FIRCLSThreadContext* registers, uintptr_t value) { + if (!FIRCLSIsValidPointer(registers)) { + return false; + } + + SET_FP_REGISTER(registers, value); + + return true; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h new file mode 100644 index 0000000..f281f66 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h @@ -0,0 +1,57 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#if CLS_CPU_ARM +#define FIRCLSThreadStateCount ARM_THREAD_STATE_COUNT +#define FIRCLSThreadState ARM_THREAD_STATE +#elif CLS_CPU_ARM64 +#define FIRCLSThreadStateCount ARM_THREAD_STATE64_COUNT +#define FIRCLSThreadState ARM_THREAD_STATE64 +#elif CLS_CPU_I386 +#define FIRCLSThreadStateCount x86_THREAD_STATE32_COUNT +#define FIRCLSThreadState x86_THREAD_STATE32 +#elif CLS_CPU_X86_64 +#define FIRCLSThreadStateCount x86_THREAD_STATE64_COUNT +#define FIRCLSThreadState x86_THREAD_STATE64 +#endif + +// _STRUCT_MCONTEXT was fixed to point to the right thing on ARM in the iOS 7.1 SDK +typedef _STRUCT_MCONTEXT FIRCLSThreadContext; + +// I'm not entirely sure what happened when, but this appears to have disappeared from +// the SDKs... +#if !defined(_STRUCT_UCONTEXT64) +typedef _STRUCT_UCONTEXT _STRUCT_UCONTEXT64; +#endif + +#pragma mark Register Access + +uintptr_t FIRCLSThreadContextGetPC(FIRCLSThreadContext* registers); +uintptr_t FIRCLSThreadContextGetStackPointer(const FIRCLSThreadContext* registers); +uintptr_t FIRCLSThreadContextGetFramePointer(const FIRCLSThreadContext* registers); + +bool FIRCLSThreadContextSetPC(FIRCLSThreadContext* registers, uintptr_t value); +bool FIRCLSThreadContextSetStackPointer(FIRCLSThreadContext* registers, uintptr_t value); +bool FIRCLSThreadContextSetFramePointer(FIRCLSThreadContext* registers, uintptr_t value); + +// The link register only exists on ARM platforms. +#if CLS_CPU_ARM || CLS_CPU_ARM64 +uintptr_t FIRCLSThreadContextGetLinkRegister(const FIRCLSThreadContext* registers); +bool FIRCLSThreadContextSetLinkRegister(FIRCLSThreadContext* registers, uintptr_t value); +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h new file mode 100644 index 0000000..0f3e84a --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h @@ -0,0 +1,55 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" + +#define FIRCLSIsValidPointer(x) ((uintptr_t)x >= 4096) +#define FIRCLSInvalidCharNybble (255) + +__BEGIN_DECLS + +void FIRCLSLookupFunctionPointer(void* ptr, void (^block)(const char* name, const char* lib)); + +void FIRCLSHexFromByte(uint8_t c, char output[]); +uint8_t FIRCLSNybbleFromChar(char c); + +bool FIRCLSReadMemory(vm_address_t src, void* dest, size_t len); +bool FIRCLSReadString(vm_address_t src, char** dest, size_t maxlen); + +const char* FIRCLSDupString(const char* string); + +bool FIRCLSUnlinkIfExists(const char* path); +void FIRCLSRedactUUID(char* value); + +#if __OBJC__ +void FIRCLSDispatchAfter(float timeInSeconds, dispatch_queue_t queue, dispatch_block_t block); + +NSString* FIRCLSNormalizeUUID(NSString* value); +NSString* FIRCLSGenerateNormalizedUUID(void); + +NSString* FIRCLSNSDataToNSString(NSData* data); + +void FIRCLSAddOperationAfter(float timeInSeconds, NSOperationQueue* queue, void (^block)(void)); +#endif + +#if DEBUG +void FIRCLSPrintAUUID(const uint8_t* value); +#endif + +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m new file mode 100644 index 0000000..7592aa0 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Helpers/FIRCLSUtility.m @@ -0,0 +1,222 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include + +#include + +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" + +#import "Crashlytics/Shared/FIRCLSByteUtility.h" +#import "Crashlytics/Shared/FIRCLSUUID.h" + +#import + +void FIRCLSLookupFunctionPointer(void* ptr, void (^block)(const char* name, const char* lib)) { + Dl_info info; + + if (dladdr(ptr, &info) == 0) { + block(NULL, NULL); + return; + } + + const char* name = "unknown"; + const char* lib = "unknown"; + + if (info.dli_sname) { + name = info.dli_sname; + } + + if (info.dli_fname) { + lib = info.dli_fname; + } + + block(name, lib); +} + +uint8_t FIRCLSNybbleFromChar(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } + + if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } + + if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + + return FIRCLSInvalidCharNybble; +} + +bool FIRCLSReadMemory(vm_address_t src, void* dest, size_t len) { + if (!FIRCLSIsValidPointer(src)) { + return false; + } + + vm_size_t readSize = len; + + return vm_read_overwrite(mach_task_self(), src, len, (pointer_t)dest, &readSize) == KERN_SUCCESS; +} + +bool FIRCLSReadString(vm_address_t src, char** dest, size_t maxlen) { + char c; + vm_address_t address; + + if (!dest) { + return false; + } + + // Walk the entire string. Not certain this is perfect... + for (address = src; address < src + maxlen; ++address) { + if (!FIRCLSReadMemory(address, &c, 1)) { + return false; + } + + if (c == 0) { + break; + } + } + + *dest = (char*)src; + + return true; +} + +const char* FIRCLSDupString(const char* string) { +#if CLS_MEMORY_PROTECTION_ENABLED + char* buffer; + size_t length; + + if (!string) { + return NULL; + } + + length = strlen(string); + buffer = FIRCLSAllocatorSafeAllocate(_firclsContext.allocator, length + 1, CLS_READONLY); + + memcpy(buffer, string, length); + + buffer[length] = 0; // null-terminate + + return buffer; +#else + return strdup(string); +#endif +} + +void FIRCLSDispatchAfter(float timeInSeconds, dispatch_queue_t queue, dispatch_block_t block) { + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(timeInSeconds * NSEC_PER_SEC)), queue, + block); +} + +bool FIRCLSUnlinkIfExists(const char* path) { + if (unlink(path) != 0) { + if (errno != ENOENT) { + return false; + } + } + + return true; +} + +NSString* FIRCLSNormalizeUUID(NSString* value) { + return [[value stringByReplacingOccurrencesOfString:@"-" withString:@""] lowercaseString]; +} + +NSString* FIRCLSGenerateNormalizedUUID(void) { + return FIRCLSNormalizeUUID(FIRCLSGenerateUUID()); +} + +// Redacts a UUID wrapped in parenthesis from a char* using strchr, which is async safe. +// Ex. +// "foo (bar) (45D62CC2-CFB5-4E33-AB61-B0684627F1B6) baz" +// becomes +// "foo (bar) (********-****-****-****-************) baz" +void FIRCLSRedactUUID(char* value) { + if (value == NULL) { + return; + } + char* openParen = value; + // find the index of the first paren + while ((openParen = strchr(openParen, '(')) != NULL) { + // find index of the matching close paren + const char* closeParen = strchr(openParen, ')'); + if (closeParen == NULL) { + break; + } + // if the distance between them is 37, traverse the characters + // and replace anything that is not a '-' with '*' + if (closeParen - openParen == 37) { + for (int i = 1; i < 37; ++i) { + if (*(openParen + i) != '-') { + *(openParen + i) = '*'; + } + } + break; + } + openParen++; + } +} + +NSString* FIRCLSNSDataToNSString(NSData* data) { + NSString* string; + char* buffer; + size_t size; + NSUInteger length; + + // we need 2 hex char for every byte of data, plus one more spot for a + // null terminator + length = [data length]; + size = (length * 2) + 1; + buffer = malloc(sizeof(char) * size); + + if (!buffer) { + FIRCLSErrorLog(@"Unable to malloc in FIRCLSNSDataToNSString"); + return nil; + } + + FIRCLSSafeHexToString([data bytes], length, buffer); + + string = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return string; +} + +void FIRCLSAddOperationAfter(float timeInSeconds, NSOperationQueue* queue, void (^block)(void)) { + dispatch_queue_t afterQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + FIRCLSDispatchAfter(timeInSeconds, afterQueue, ^{ + [queue addOperationWithBlock:block]; + }); +} + +#if DEBUG +void FIRCLSPrintAUUID(const uint8_t* value) { + CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *(CFUUIDBytes*)value); + + NSString* string = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)); + + CFRelease(uuid); + + FIRCLSDebugLog(@"%@", [[string stringByReplacingOccurrencesOfString:@"-" + withString:@""] lowercaseString]); +} +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h new file mode 100644 index 0000000..41a4896 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h @@ -0,0 +1,33 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class is a model to identify a single execution of the app + */ +@interface FIRCLSExecutionIdentifierModel : NSObject + +/** + * Returns the launch identifier. This is a unique id that will remain constant until this process + * is relaunched. This value is useful for correlating events across kits and/or across reports at + * the process-lifecycle level. + */ +@property(nonatomic, readonly) NSString *executionID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.m new file mode 100644 index 0000000..163b337 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.m @@ -0,0 +1,33 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSExecutionIdentifierModel.h" + +#import "Crashlytics/Shared/FIRCLSUUID.h" + +@implementation FIRCLSExecutionIdentifierModel + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _executionID = [[FIRCLSGenerateUUID() stringByReplacingOccurrencesOfString:@"-" + withString:@""] lowercaseString]; + + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.h new file mode 100644 index 0000000..6de9eaf --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.h @@ -0,0 +1,75 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRCLSInternalReport; + +@interface FIRCLSFileManager : NSObject + +- (instancetype)init NS_DESIGNATED_INITIALIZER; + +@property(nonatomic, readonly) NSFileManager *underlyingFileManager; + +/** + * Returns the folder containing the settings file + */ +@property(nonatomic, readonly) NSString *settingsDirectoryPath; + +/** + * Returns the path to the settings file + */ +@property(nonatomic, readonly) NSString *settingsFilePath; + +/** + * Path to the file that holds the ttl and keys that invalidate settings + */ +@property(nonatomic, readonly) NSString *settingsCacheKeyPath; + +@property(nonatomic, readonly) NSString *rootPath; +@property(nonatomic, readonly) NSString *cachesPath; +@property(nonatomic, readonly) NSString *structurePath; +@property(nonatomic, readonly) NSString *activePath; +@property(nonatomic, readonly) NSString *processingPath; +@property(nonatomic, readonly) NSString *pendingPath; +@property(nonatomic, readonly) NSString *preparedPath; +@property(nonatomic, readonly) NSArray *activePathContents; +@property(nonatomic, readonly) NSArray *preparedPathContents; +@property(nonatomic, readonly) NSArray *processingPathContents; + +- (BOOL)fileExistsAtPath:(NSString *)path; +- (BOOL)createFileAtPath:(NSString *)path + contents:(NSData *)data + attributes:(NSDictionary *)attr; +- (BOOL)createDirectoryAtPath:(NSString *)path; +- (BOOL)removeItemAtPath:(NSString *)path; +- (BOOL)removeContentsOfDirectoryAtPath:(NSString *)path; +- (BOOL)moveItemAtPath:(NSString *)path toDirectory:(NSString *)destDir; +- (BOOL)didCrashOnPreviousExecution; +- (BOOL)metricKitDiagnosticFileExists; +- (void)createEmptyMetricKitFile:(NSString *)reportPath; +- (void)enumerateFilesInDirectory:(NSString *)directory + usingBlock:(void (^)(NSString *filePath, NSString *extension))block; +- (NSNumber *)fileSizeAtPath:(NSString *)path; +- (NSArray *)contentsOfDirectory:(NSString *)path; + +// logic of managing files/directories +- (BOOL)createReportDirectories; +- (NSString *)setupNewPathForExecutionIdentifier:(NSString *)identifier; + +- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error; + +- (NSData *)dataWithContentsOfFile:(NSString *)path; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.m new file mode 100644 index 0000000..8b310b3 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSFileManager.m @@ -0,0 +1,296 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" + +NSString *const FIRCLSCacheDirectoryName = @"com.crashlytics.data"; +NSString *const FIRCLSCacheVersion = @"v5"; +NSString *const FIRCLSMetricKitDiagnosticPath = @"/MetricKit/Diagnostics/"; + +@interface FIRCLSFileManager () { + NSString *_rootPath; + NSString *_cachesPath; +} +@property(nonatomic) BOOL crashFileMarkerExists; + +@end + +@implementation FIRCLSFileManager + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _underlyingFileManager = [NSFileManager defaultManager]; + + NSString *path = + [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; + _cachesPath = [path copy]; + path = [path stringByAppendingPathComponent:FIRCLSCacheDirectoryName]; + path = [path stringByAppendingPathComponent:[self pathNamespace]]; + _rootPath = [path copy]; + + _crashFileMarkerExists = NO; + return self; +} + +#pragma mark - Core API + +- (BOOL)fileExistsAtPath:(NSString *)path { + return [_underlyingFileManager fileExistsAtPath:path]; +} + +- (BOOL)createFileAtPath:(NSString *)path + contents:(nullable NSData *)data + attributes:(nullable NSDictionary *)attr { + return [_underlyingFileManager createFileAtPath:path contents:data attributes:attr]; +} + +- (BOOL)createDirectoryAtPath:(NSString *)path { + NSDictionary *attributes; + NSError *error; + + attributes = @{NSFilePosixPermissions : [NSNumber numberWithShort:0755]}; + error = nil; + + if (![[self underlyingFileManager] createDirectoryAtPath:path + withIntermediateDirectories:YES + attributes:attributes + error:&error]) { + FIRCLSErrorLog(@"Unable to create directory %@", error); + return NO; + } + + return YES; +} + +- (BOOL)removeItemAtPath:(NSString *)path { + NSError *error; + + error = nil; + if (![[self underlyingFileManager] removeItemAtPath:path error:&error] || !path) { + FIRCLSErrorLog(@"Failed to remove file %@: %@", path, error); + + return NO; + } + + return YES; +} + +- (BOOL)removeContentsOfDirectoryAtPath:(NSString *)path { + __block BOOL success = YES; + + // only return true if we were able to remove every item in the directory (or it was empty) + + [self enumerateFilesInDirectory:path + usingBlock:^(NSString *filePath, NSString *extension) { + success = [self removeItemAtPath:filePath] && success; + }]; + + return success; +} + +- (BOOL)moveItemAtPath:(NSString *)path toDirectory:(NSString *)destDir { + NSString *destPath; + NSError *error; + + destPath = [destDir stringByAppendingPathComponent:[path lastPathComponent]]; + error = nil; + + if (!path || !destPath) { + FIRCLSErrorLog(@"Failed to move file, inputs invalid"); + + return NO; + } + + if (![[self underlyingFileManager] moveItemAtPath:path toPath:destPath error:&error]) { + FIRCLSErrorLog(@"Failed to move file: %@", error); + + return NO; + } + + return YES; +} + +- (BOOL)didCrashOnPreviousExecution { + static dispatch_once_t checkCrashFileMarketExistsOnceToken; + dispatch_once(&checkCrashFileMarketExistsOnceToken, ^{ + NSString *crashedMarkerFileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName]; + NSString *crashedMarkerFileFullPath = + [[self rootPath] stringByAppendingPathComponent:crashedMarkerFileName]; + self.crashFileMarkerExists = [self fileExistsAtPath:crashedMarkerFileFullPath]; + }); + return self.crashFileMarkerExists; +} + +- (BOOL)metricKitDiagnosticFileExists { + NSArray *contentsOfMetricKitDirectory = [self + contentsOfDirectory:[_cachesPath stringByAppendingString:FIRCLSMetricKitDiagnosticPath]]; + return ([contentsOfMetricKitDirectory count] > 0); +} + +- (void)createEmptyMetricKitFile:(NSString *)reportPath { + NSString *metricKitFile = + [reportPath stringByAppendingPathComponent:FIRCLSMetricKitFatalReportFile]; + [self createFileAtPath:metricKitFile contents:nil attributes:nil]; +} + +- (void)enumerateFilesInDirectory:(NSString *)directory + usingBlock:(void (^)(NSString *filePath, NSString *extension))block { + for (NSString *path in [[self underlyingFileManager] contentsOfDirectoryAtPath:directory + error:nil]) { + NSString *extension; + NSString *fullPath; + + // Skip files that start with a dot. This is important, because if you try to move a .DS_Store + // file, it will fail if the target directory also has a .DS_Store file in it. Plus, its + // wasteful, because we don't care about dot files. + if ([path hasPrefix:@"."]) { + continue; + } + + extension = [path pathExtension]; + fullPath = [directory stringByAppendingPathComponent:path]; + if (block) { + block(fullPath, extension); + } + } +} + +- (NSNumber *)fileSizeAtPath:(NSString *)path { + NSError *error = nil; + NSDictionary *attrs = [[self underlyingFileManager] attributesOfItemAtPath:path error:&error]; + + if (!attrs) { + FIRCLSErrorLog(@"Unable to read file size: %@", error); + return nil; + } + + return [attrs objectForKey:NSFileSize]; +} + +- (NSArray *)contentsOfDirectory:(NSString *)path { + NSMutableArray *array = [NSMutableArray array]; + + [self enumerateFilesInDirectory:path + usingBlock:^(NSString *filePath, NSString *extension) { + [array addObject:filePath]; + }]; + + return [array copy]; +} + +#pragma - Properties +- (NSString *)pathNamespace { + return FIRCLSApplicationGetBundleIdentifier(); +} + +- (NSString *)versionedPath { + return [[self rootPath] stringByAppendingPathComponent:FIRCLSCacheVersion]; +} + +#pragma - Settings Paths + +// This path should be different than the structurePath because the +// settings download operations will delete the settings directory, +// which would delete crash reports if these were the same +- (NSString *)settingsDirectoryPath { + return [[self versionedPath] stringByAppendingPathComponent:@"settings"]; +} + +- (NSString *)settingsFilePath { + return [[self settingsDirectoryPath] stringByAppendingPathComponent:@"settings.json"]; +} + +- (NSString *)settingsCacheKeyPath { + return [[self settingsDirectoryPath] stringByAppendingPathComponent:@"cache-key.json"]; +} + +#pragma - Report Paths +- (NSString *)structurePath { + return [[self versionedPath] stringByAppendingPathComponent:@"reports"]; +} + +- (NSString *)activePath { + return [[self structurePath] stringByAppendingPathComponent:@"active"]; +} + +- (NSString *)pendingPath { + return [[self structurePath] stringByAppendingPathComponent:@"pending"]; +} + +- (NSString *)processingPath { + return [[self structurePath] stringByAppendingPathComponent:@"processing"]; +} + +- (NSString *)preparedPath { + return [[self structurePath] stringByAppendingPathComponent:@"prepared"]; +} + +- (NSArray *)activePathContents { + return [self contentsOfDirectory:[self activePath]]; +} + +- (NSArray *)preparedPathContents { + return [self contentsOfDirectory:[self preparedPath]]; +} + +- (NSArray *)processingPathContents { + return [self contentsOfDirectory:[self processingPath]]; +} + +#pragma mark - Logic +- (BOOL)createReportDirectories { + if (![self createDirectoryAtPath:[self activePath]]) { + return NO; + } + + if (![self createDirectoryAtPath:[self processingPath]]) { + return NO; + } + + if (![self createDirectoryAtPath:[self preparedPath]]) { + return NO; + } + + return YES; +} + +- (NSString *)setupNewPathForExecutionIdentifier:(NSString *)identifier { + NSString *path = [[self activePath] stringByAppendingPathComponent:identifier]; + + if (![self createDirectoryAtPath:path]) { + return nil; + } + + return path; +} + +- (BOOL)moveItemAtPath:(NSString *)srcPath toPath:(NSString *)dstPath error:(NSError **)error { + return [self.underlyingFileManager moveItemAtPath:srcPath toPath:dstPath error:error]; +} + +// Wrapper over NSData so the method can be mocked for unit tests +- (NSData *)dataWithContentsOfFile:(NSString *)path { + return [NSData dataWithContentsOfFile:path]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h new file mode 100644 index 0000000..4e0f483 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h @@ -0,0 +1,51 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRInstallations; + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class is a model for identifying an installation of an app + */ +@interface FIRCLSInstallIdentifierModel : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithInstallations:(FIRInstallations *)instanceID NS_DESIGNATED_INITIALIZER; + +/** + * Returns the backwards compatible Crashlytics Installation UUID + */ +@property(nonatomic, readonly) NSString *installID; + +/** + * To support end-users rotating Install IDs, this will check and rotate the Install ID, + * which can be a slow operation. This should be run in an Activity or + * background thread. + * + * This method has 2 concerns: + * - Concern 1: We have the old Crashlytics Install ID that needs to regenerate when the FIID + * changes. If we get a null FIID, we don't want to rotate because we don't know if it changed or + * not. + * - Concern 2: Whatever the FIID is, we should send it with the Crash report so we're in sync with + * Sessions and other Firebase SDKs + */ +- (BOOL)regenerateInstallIDIfNeededWithBlock:(void (^)(NSString *fiid, NSString *authToken))block; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.m new file mode 100644 index 0000000..96e96e6 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.m @@ -0,0 +1,189 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" + +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" + +#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Shared/FIRCLSByteUtility.h" +#import "Crashlytics/Shared/FIRCLSUUID.h" + +static NSString *const FIRCLSInstallationUUIDKey = @"com.crashlytics.iuuid"; +static NSString *const FIRCLSInstallationIIDHashKey = @"com.crashlytics.install.iid"; + +// Legacy key that is automatically removed +static NSString *const FIRCLSInstallationADIDKey = @"com.crashlytics.install.adid"; + +static unsigned long long FIRCLSInstallationsWaitTime = 10 * NSEC_PER_SEC; + +@interface FIRCLSInstallIdentifierModel () + +@property(nonatomic, copy) NSString *installID; + +@property(nonatomic, readonly) FIRInstallations *installations; + +@end + +@implementation FIRCLSInstallIdentifierModel + +// This needs to be synthesized so we can set without using the setter in the constructor and +// overridden setters and getters +@synthesize installID = _installID; + +- (instancetype)initWithInstallations:(FIRInstallations *)installations { + self = [super init]; + if (!self) { + return nil; + } + + // capture the install ID information + _installID = [self readInstallationUUID].copy; + _installations = installations; + + if (!_installID) { + FIRCLSDebugLog(@"Generating Install ID"); + _installID = [self generateInstallationUUID].copy; + + FIRCLSUserDefaults *defaults = [FIRCLSUserDefaults standardUserDefaults]; + [defaults synchronize]; + } + + return self; +} + +- (NSString *)installID { + @synchronized(self) { + return _installID; + } +} + +- (void)setInstallID:(NSString *)installID { + @synchronized(self) { + _installID = installID; + } +} + +/** + * Reads installation UUID stored in persistent storage. + * If the installation UUID is stored in legacy key, migrates it over to the new key. + */ +- (NSString *)readInstallationUUID { + return [[FIRCLSUserDefaults standardUserDefaults] objectForKey:FIRCLSInstallationUUIDKey]; +} + +/** + * Generates a new UUID and saves it in persistent storage. + * Does not synchronize the user defaults (to allow optimized + * batching of user default synchronizing) + */ +- (NSString *)generateInstallationUUID { + NSString *UUID = FIRCLSGenerateUUID(); + FIRCLSUserDefaults *userDefaults = [FIRCLSUserDefaults standardUserDefaults]; + [userDefaults setObject:UUID forKey:FIRCLSInstallationUUIDKey]; + return UUID; +} + +#pragma mark Privacy Shield + +- (BOOL)regenerateInstallIDIfNeededWithBlock:(void (^)(NSString *fiid, NSString *authToken))block { + BOOL __block didRotate = false; + NSString __block *authTokenComplete = @""; + NSString __block *currentIIDComplete = @""; + + // Installations Completions run async, so wait a reasonable amount of time for it to finish. + dispatch_group_t workingGroup = dispatch_group_create(); + + dispatch_group_enter(workingGroup); + [self.installations + authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error) { + authTokenComplete = tokenResult.authToken; + dispatch_group_leave(workingGroup); + }]; + + dispatch_group_enter(workingGroup); + [self.installations + installationIDWithCompletion:^(NSString *_Nullable currentIID, NSError *_Nullable error) { + currentIIDComplete = currentIID; + didRotate = [self rotateCrashlyticsInstallUUIDWithIID:currentIID error:error]; + + if (didRotate) { + FIRCLSInfoLog(@"Rotated Crashlytics Install UUID because Firebase Install ID changed"); + } + dispatch_group_leave(workingGroup); + }]; + + intptr_t result = dispatch_group_wait( + workingGroup, dispatch_time(DISPATCH_TIME_NOW, FIRCLSInstallationsWaitTime)); + + if (result != 0) { + FIRCLSErrorLog(@"Crashlytics timed out while checking for Firebase Installation ID"); + } + + // Provide the IID to the callback. For this case we don't care + // if the FIID is null because it's the best we can do - we just want + // to send up the same FIID that is sent by other SDKs (eg. the Sessions SDK). + block(currentIIDComplete, authTokenComplete); + return didRotate; +} + +- (BOOL)rotateCrashlyticsInstallUUIDWithIID:(NSString *_Nullable)currentIID + error:(NSError *_Nullable)error { + BOOL didRotate = NO; + + FIRCLSUserDefaults *defaults = [FIRCLSUserDefaults standardUserDefaults]; + + // Remove the legacy ID + NSString *adID = [defaults objectForKey:FIRCLSInstallationADIDKey]; + if (adID.length != 0) { + [defaults removeObjectForKey:FIRCLSInstallationADIDKey]; + [defaults synchronize]; + } + + if (error != nil) { + FIRCLSErrorLog(@"Failed to get Firebase Instance ID: %@", error); + return didRotate; + } + + if (currentIID.length == 0) { + FIRCLSErrorLog(@"Firebase Instance ID was empty when checked for changes"); + return didRotate; + } + + NSString *currentIIDHash = + FIRCLS256HashNSData([currentIID dataUsingEncoding:NSUTF8StringEncoding]); + NSString *lastIIDHash = [defaults objectForKey:FIRCLSInstallationIIDHashKey]; + + // If the IDs are the same, we never regenerate + if ([lastIIDHash isEqualToString:currentIIDHash]) { + return didRotate; + } + + // If we had an FIID saved, we know it's not an upgrade scenario, so we can regenerate + if (lastIIDHash.length != 0) { + FIRCLSDebugLog(@"Regenerating Install ID"); + self.installID = [self generateInstallationUUID].copy; + didRotate = YES; + } + + // Write the new FIID to UserDefaults + [defaults setObject:currentIIDHash forKey:FIRCLSInstallationIIDHashKey]; + [defaults synchronize]; + + return didRotate; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h new file mode 100644 index 0000000..624c199 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h @@ -0,0 +1,121 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +extern NSString *const FIRCLSCustomFatalIndicatorFile; +extern NSString *const FIRCLSReportBinaryImageFile; +extern NSString *const FIRCLSReportExceptionFile; +extern NSString *const FIRCLSReportCustomExceptionAFile; +extern NSString *const FIRCLSReportCustomExceptionBFile; +extern NSString *const FIRCLSReportSignalFile; +extern NSString *const FIRCLSMetricKitFatalReportFile; +extern NSString *const FIRCLSMetricKitNonfatalReportFile; +#if CLS_MACH_EXCEPTION_SUPPORTED +extern NSString *const FIRCLSReportMachExceptionFile; +#endif +extern NSString *const FIRCLSReportErrorAFile; +extern NSString *const FIRCLSReportErrorBFile; +extern NSString *const FIRCLSReportLogAFile; +extern NSString *const FIRCLSReportLogBFile; +extern NSString *const FIRCLSReportMetadataFile; +extern NSString *const FIRCLSReportInternalIncrementalKVFile; +extern NSString *const FIRCLSReportInternalCompactedKVFile; +extern NSString *const FIRCLSReportUserIncrementalKVFile; +extern NSString *const FIRCLSReportUserCompactedKVFile; +extern NSString *const FIRCLSReportRolloutsFile; + +@class FIRCLSFileManager; + +@interface FIRCLSInternalReport : NSObject + ++ (instancetype)reportWithPath:(NSString *)path; +- (instancetype)initWithPath:(NSString *)path + executionIdentifier:(NSString *)identifier NS_DESIGNATED_INITIALIZER; +- (instancetype)initWithPath:(NSString *)path; +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + ++ (NSArray *)crashFileNames; + +@property(nonatomic, copy, readonly) NSString *directoryName; +@property(nonatomic, copy) NSString *path; +@property(nonatomic, assign, readonly) BOOL hasAnyEvents; + +// content paths +@property(nonatomic, copy, readonly) NSString *binaryImagePath; +@property(nonatomic, copy, readonly) NSString *metadataPath; + +- (void)enumerateSymbolicatableFilesInContent:(void (^)(NSString *path))block; + +- (NSString *)pathForContentFile:(NSString *)name; + +// Metadata Helpers + +/** + * Returns the org id for the report. + **/ +@property(nonatomic, copy, readonly) NSString *orgID; + +/** + * Returns the Install UUID for the report. + **/ +@property(nonatomic, copy, readonly) NSString *installID; + +/** + * Returns true if report contains a signal, mach exception or unhandled exception record, false + * otherwise. + **/ +@property(nonatomic, assign, readonly) BOOL isCrash; + +/** + * Returns the session identifier for the report. + **/ +@property(nonatomic, copy, readonly) NSString *identifier; + +/** + * Returns the custom key value data for the report. + **/ +@property(nonatomic, copy, readonly) NSDictionary *customKeys; + +/** + * Returns the CFBundleVersion of the application that generated the report. + **/ +@property(nonatomic, copy, readonly) NSString *bundleVersion; + +/** + * Returns the CFBundleShortVersionString of the application that generated the report. + **/ +@property(nonatomic, copy, readonly) NSString *bundleShortVersionString; + +/** + * Returns the date that the report was created. + **/ +@property(nonatomic, copy, readonly) NSDate *dateCreated; + +@property(nonatomic, copy, readonly) NSDate *crashedOnDate; + +/** + * Returns the os version that the application crashed on. + **/ +@property(nonatomic, copy, readonly) NSString *OSVersion; + +/** + * Returns the os build version that the application crashed on. + **/ +@property(nonatomic, copy, readonly) NSString *OSBuildVersion; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.m new file mode 100644 index 0000000..35160d1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSInternalReport.m @@ -0,0 +1,258 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// TODO: Remove this class after the uploading of reports via GoogleDataTransport is no longer an +// experiment + +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" + +NSString *const FIRCLSCustomFatalIndicatorFile = @"custom_fatal.clsrecord"; +NSString *const FIRCLSReportBinaryImageFile = @"binary_images.clsrecord"; +NSString *const FIRCLSReportExceptionFile = @"exception.clsrecord"; +NSString *const FIRCLSReportCustomExceptionAFile = @"custom_exception_a.clsrecord"; +NSString *const FIRCLSReportCustomExceptionBFile = @"custom_exception_b.clsrecord"; +NSString *const FIRCLSReportSignalFile = @"signal.clsrecord"; +NSString *const FIRCLSMetricKitFatalReportFile = @"metric_kit_fatal.clsrecord"; +NSString *const FIRCLSMetricKitNonfatalReportFile = @"metric_kit_nonfatal.clsrecord"; +#if CLS_MACH_EXCEPTION_SUPPORTED +NSString *const FIRCLSReportMachExceptionFile = @"mach_exception.clsrecord"; +#endif +NSString *const FIRCLSReportMetadataFile = @"metadata.clsrecord"; +NSString *const FIRCLSReportErrorAFile = @"errors_a.clsrecord"; +NSString *const FIRCLSReportErrorBFile = @"errors_b.clsrecord"; +NSString *const FIRCLSReportLogAFile = @"log_a.clsrecord"; +NSString *const FIRCLSReportLogBFile = @"log_b.clsrecord"; +NSString *const FIRCLSReportInternalIncrementalKVFile = @"internal_incremental_kv.clsrecord"; +NSString *const FIRCLSReportInternalCompactedKVFile = @"internal_compacted_kv.clsrecord"; +NSString *const FIRCLSReportUserIncrementalKVFile = @"user_incremental_kv.clsrecord"; +NSString *const FIRCLSReportUserCompactedKVFile = @"user_compacted_kv.clsrecord"; +NSString *const FIRCLSReportRolloutsFile = @"rollouts.clsrecord"; + +@interface FIRCLSInternalReport () { + NSString *_identifier; + NSString *_path; + NSArray *_metadataSections; +} + +@end + +@implementation FIRCLSInternalReport + ++ (instancetype)reportWithPath:(NSString *)path { + return [[self alloc] initWithPath:path]; +} + +#pragma mark - Initialization +/** + * Initializes a new report, i.e. one without metadata on the file system yet. + */ +- (instancetype)initWithPath:(NSString *)path executionIdentifier:(NSString *)identifier { + self = [super init]; + if (!self) { + return self; + } + + if (!path || !identifier) { + return nil; + } + + [self setPath:path]; + + _identifier = [identifier copy]; + + return self; +} + +/** + * Initializes a pre-existing report, i.e. one with metadata on the file system. + */ +- (instancetype)initWithPath:(NSString *)path { + NSString *metadataPath = [path stringByAppendingPathComponent:FIRCLSReportMetadataFile]; + NSString *identifier = [[[[self.class readFIRCLSFileAtPath:metadataPath] objectAtIndex:0] + objectForKey:@"identity"] objectForKey:@"session_id"]; + if (!identifier) { + FIRCLSErrorLog(@"Unable to read identifier at path %@", path); + } + return [self initWithPath:path executionIdentifier:identifier]; +} + +#pragma mark - Path Helpers +- (NSString *)directoryName { + return self.path.lastPathComponent; +} + +- (NSString *)pathForContentFile:(NSString *)name { + return [[self path] stringByAppendingPathComponent:name]; +} + +- (NSString *)metadataPath { + return [[self path] stringByAppendingPathComponent:FIRCLSReportMetadataFile]; +} + +- (NSString *)binaryImagePath { + return [self pathForContentFile:FIRCLSReportBinaryImageFile]; +} + +#pragma mark - Processing Methods +- (BOOL)hasAnyEvents { + NSArray *reportFiles = @[ + FIRCLSReportExceptionFile, FIRCLSReportSignalFile, FIRCLSReportCustomExceptionAFile, + FIRCLSReportCustomExceptionBFile, FIRCLSMetricKitFatalReportFile, + FIRCLSMetricKitNonfatalReportFile, +#if CLS_MACH_EXCEPTION_SUPPORTED + FIRCLSReportMachExceptionFile, +#endif + FIRCLSReportErrorAFile, FIRCLSReportErrorBFile + ]; + return [self checkExistenceOfAtLeastOneFileInArray:reportFiles]; +} + +// These are purposefully in order of precedence. If duplicate data exists +// in any crash file, the exception file's contents take precedence over the +// rest, for example +// +// Do not change the order of this. +// ++ (NSArray *)crashFileNames { + static NSArray *files; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + files = @[ + FIRCLSReportExceptionFile, +#if CLS_MACH_EXCEPTION_SUPPORTED + FIRCLSReportMachExceptionFile, +#endif + FIRCLSReportSignalFile, FIRCLSMetricKitFatalReportFile, FIRCLSCustomFatalIndicatorFile + ]; + }); + return files; +} + +- (BOOL)isCrash { + NSArray *crashFiles = [FIRCLSInternalReport crashFileNames]; + return [self checkExistenceOfAtLeastOneFileInArray:crashFiles]; +} + +- (BOOL)checkExistenceOfAtLeastOneFileInArray:(NSArray *)files { + NSFileManager *manager = [NSFileManager defaultManager]; + + for (NSString *fileName in files) { + NSString *path = [self pathForContentFile:fileName]; + + if ([manager fileExistsAtPath:path]) { + return YES; + } + } + + return NO; +} + +- (void)enumerateSymbolicatableFilesInContent:(void (^)(NSString *path))block { + for (NSString *fileName in [FIRCLSInternalReport crashFileNames]) { + NSString *path = [self pathForContentFile:fileName]; + + block(path); + } +} + +#pragma mark - Metadata helpers ++ (NSArray *)readFIRCLSFileAtPath:(NSString *)path { + NSArray *sections = FIRCLSFileReadSections([path fileSystemRepresentation], false, nil); + + if ([sections count] == 0) { + return nil; + } + + return sections; +} + +- (NSArray *)metadataSections { + if (!_metadataSections) { + _metadataSections = [self.class readFIRCLSFileAtPath:self.metadataPath]; + } + return _metadataSections; +} + +- (NSString *)orgID { + return + [[[self.metadataSections objectAtIndex:0] objectForKey:@"identity"] objectForKey:@"org_id"]; +} + +- (NSDictionary *)customKeys { + return nil; +} + +- (NSString *)bundleVersion { + return [[[self.metadataSections objectAtIndex:2] objectForKey:@"application"] + objectForKey:@"build_version"]; +} + +- (NSString *)bundleShortVersionString { + return [[[self.metadataSections objectAtIndex:2] objectForKey:@"application"] + objectForKey:@"display_version"]; +} + +- (NSDate *)dateCreated { + NSUInteger unixtime = [[[[self.metadataSections objectAtIndex:0] objectForKey:@"identity"] + objectForKey:@"started_at"] unsignedIntegerValue]; + + return [NSDate dateWithTimeIntervalSince1970:unixtime]; +} + +- (NSDate *)crashedOnDate { + if (!self.isCrash) { + return nil; + } + +#if CLS_MACH_EXCEPTION_SUPPORTED + // try the mach exception first, because it is more common + NSDate *date = [self timeFromCrashContentFile:FIRCLSReportMachExceptionFile + sectionName:@"mach_exception"]; + if (date) { + return date; + } +#endif + + return [self timeFromCrashContentFile:FIRCLSReportSignalFile sectionName:@"signal"]; +} + +- (NSDate *)timeFromCrashContentFile:(NSString *)fileName sectionName:(NSString *)sectionName { + // This works because both signal and mach exception files have the same structure to extract + // the "time" component + NSString *path = [self pathForContentFile:fileName]; + + NSNumber *timeValue = [[[[self.class readFIRCLSFileAtPath:path] objectAtIndex:0] + objectForKey:sectionName] objectForKey:@"time"]; + if (timeValue == nil) { + return nil; + } + + return [NSDate dateWithTimeIntervalSince1970:[timeValue unsignedIntegerValue]]; +} + +- (NSString *)OSVersion { + return [[[self.metadataSections objectAtIndex:1] objectForKey:@"host"] + objectForKey:@"os_display_version"]; +} + +- (NSString *)OSBuildVersion { + return [[[self.metadataSections objectAtIndex:1] objectForKey:@"host"] + objectForKey:@"os_build_version"]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h new file mode 100644 index 0000000..269a1c9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h @@ -0,0 +1,40 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/* + * Writes a file during startup, and deletes it at the end. Existence + * of this file on the next run means there was a crash at launch, + * because the file wasn't deleted. This is used to make Crashlytics + * block startup on uploading the crash. + */ +@interface FIRCLSLaunchMarkerModel : NSObject + +- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +- (BOOL)checkForAndCreateLaunchMarker; +- (BOOL)createLaunchFailureMarker; +- (BOOL)removeLaunchFailureMarker; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.m new file mode 100644 index 0000000..ed5ee88 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.m @@ -0,0 +1,84 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSLaunchMarkerModel.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h" + +@interface FIRCLSLaunchMarkerModel () + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; + +@end + +@implementation FIRCLSLaunchMarkerModel + +- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager { + self = [super init]; + if (!self) { + return nil; + } + + _fileManager = fileManager; + + return self; +} + +- (BOOL)checkForAndCreateLaunchMarker { + BOOL launchFailure = [self launchFailureMarkerPresent]; + if (launchFailure) { + FIRCLSDeveloperLog("Crashlytics:Crash", + @"Last launch failed: this may indicate a crash shortly after app launch."); + } else { + [self createLaunchFailureMarker]; + } + + return launchFailure; +} + +- (NSString *)launchFailureMarkerPath { + return [[_fileManager structurePath] stringByAppendingPathComponent:@"launchmarker"]; +} + +- (BOOL)createLaunchFailureMarker { + // It's tempting to use - [NSFileManger createFileAtPath:contents:attributes:] here. But that + // operation, even with empty/nil contents does a ton of work to write out nothing via a + // temporarly file. This is a much faster implementation. + const char *path = [[self launchFailureMarkerPath] fileSystemRepresentation]; + +#if TARGET_OS_IPHONE + /* + * data-protected non-portable open(2) : + * int open_dprotected_np(user_addr_t path, int flags, int class, int dpflags, int mode) + */ + int fd = open_dprotected_np(path, O_WRONLY | O_CREAT | O_TRUNC, 4, 0, 0644); +#else + int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644); +#endif + if (fd == -1) { + return NO; + } + + return close(fd) == 0; +} + +- (BOOL)launchFailureMarkerPresent { + return [[_fileManager underlyingFileManager] fileExistsAtPath:[self launchFailureMarkerPath]]; +} + +- (BOOL)removeLaunchFailureMarker { + return [_fileManager removeItemAtPath:[self launchFailureMarkerPath]]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h new file mode 100644 index 0000000..78721ee --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h @@ -0,0 +1,22 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_SWIFT_NAME(OnDemandModel) +@interface FIRCLSOnDemandModel : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.m new file mode 100644 index 0000000..6283d9e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.m @@ -0,0 +1,267 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Handlers/FIRCLSException.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h" + +#include + +@interface FIRCLSOnDemandModel () + +@property(nonatomic, readonly) int recordedOnDemandExceptionCount; +@property(nonatomic, readonly) int droppedOnDemandExceptionCount; +@property(nonatomic, readonly) int queuedOperationsCount; + +@property(nonatomic, strong) FIRCLSSettings *settings; +@property(nonatomic, strong) NSOperationQueue *operationQueue; +@property(nonatomic, strong) dispatch_queue_t dispatchQueue; + +@property(nonatomic) double lastUpdated; +@property(nonatomic) double currentStep; + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; +@property(nonatomic, strong) NSMutableArray *storedActiveReportPaths; + +@end + +@implementation FIRCLSOnDemandModel + +@synthesize recordedOnDemandExceptionCount = _recordedOnDemandExceptionCount; +@synthesize droppedOnDemandExceptionCount = _droppedOnDemandExceptionCount; +@synthesize queuedOperationsCount = _queuedOperationsCount; + +static const double MAX_DELAY_SEC = 3600; +static const double SEC_PER_MINUTE = 60; + +- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager { + self = [super init]; + if (!self) { + return nil; + } + + _settings = settings; + _fileManager = fileManager; + + NSString *sdkBundleID = FIRCLSApplicationGetSDKBundleID(); + _operationQueue = [NSOperationQueue new]; + [_operationQueue setMaxConcurrentOperationCount:1]; + [_operationQueue setName:[sdkBundleID stringByAppendingString:@".on-demand-queue"]]; + _dispatchQueue = dispatch_queue_create("com.google.firebase.crashlytics.on.demand", 0); + _operationQueue.underlyingQueue = _dispatchQueue; + + _queuedOperationsCount = 0; + + _recordedOnDemandExceptionCount = 0; + _droppedOnDemandExceptionCount = 0; + + _lastUpdated = [NSDate timeIntervalSinceReferenceDate]; + _currentStep = -1; + + self.storedActiveReportPaths = [NSMutableArray array]; + + return self; +} + +/* + * Called from FIRCrashlytics whenever the on-demand record exception method is called. Handles + * rate limiting and exponential backoff. + */ +- (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel + withDataCollectionEnabled:(BOOL)dataCollectionEnabled + usingExistingReportManager:(FIRCLSExistingReportManager *)existingReportManager { + // Record the exception model into a new report if there is unused on-demand quota. Otherwise, + // log the occurrence but drop the event. + @synchronized(self) { + if ([self isQueueFull]) { + FIRCLSDebugLog(@"No available on-demand quota, dropping report"); + [self incrementDroppedExceptionCount]; + [self incrementRecordedExceptionCount]; + return NO; // Didn't record or submit the exception because no quota was available. + } + + FIRCLSDataCollectionToken *dataCollectionToken = [FIRCLSDataCollectionToken validToken]; + NSString *activeReportPath = [self recordOnDemandExceptionWithModel:exceptionModel]; + + if (!activeReportPath) { + FIRCLSErrorLog(@"Error recording on-demand exception"); + return NO; // Something went wrong when recording the exception, so we don't have a valid + // path. + } + + // Only submit an exception report if data collection is enabled. Otherwise, the report + // is stored until send or delete unsent reports is called. + [self incrementQueuedOperationCount]; + [self incrementRecordedExceptionCount]; + [self resetDroppedExceptionCount]; + + [self.operationQueue addOperationWithBlock:^{ + double uploadDelay = [self calculateUploadDelay]; + + if (dataCollectionEnabled) { + [existingReportManager handleOnDemandReportUpload:activeReportPath + dataCollectionToken:dataCollectionToken + asUrgent:YES]; + FIRCLSDebugLog(@"Submitted an on-demand exception, starting delay %.20f", uploadDelay); + } else { + [self.storedActiveReportPaths insertObject:activeReportPath atIndex:0]; + if ([self.storedActiveReportPaths count] > FIRCLSMaxUnsentReports) { + [self.fileManager removeItemAtPath:[self.storedActiveReportPaths lastObject]]; + [self.storedActiveReportPaths removeLastObject]; + [self decrementRecordedExceptionCount]; + [self incrementDroppedExceptionCount]; + } + FIRCLSDebugLog(@"Stored an on-demand exception, starting delay %.20f", uploadDelay); + } + [self implementOnDemandUploadDelay:uploadDelay]; + [self decrementQueuedOperationCount]; + }]; + return YES; // Recorded and submitted the exception. + } +} + +- (double)calculateUploadDelay { + double calculatedStepDuration = [self calculateStepDuration]; + double power = pow(self.settings.onDemandBackoffBase, calculatedStepDuration); + NSNumber *calculatedUploadDelay = + [NSNumber numberWithDouble:(SEC_PER_MINUTE / self.settings.onDemandUploadRate) * power]; + NSComparisonResult result = + [[NSNumber numberWithDouble:MAX_DELAY_SEC] compare:calculatedUploadDelay]; + return (result == NSOrderedAscending) ? MAX_DELAY_SEC : [calculatedUploadDelay doubleValue]; +} + +- (double)calculateStepDuration { + double currentTime = [NSDate timeIntervalSinceReferenceDate]; + BOOL queueIsFull = [self isQueueFull]; + + if (self.currentStep == -1) { + self.currentStep = 0; + self.lastUpdated = currentTime; + } + + double delta = + (currentTime - self.lastUpdated) / (double)self.settings.onDemandBackoffStepDuration; + double queueFullDuration = (self.currentStep + delta) > 100 ? 100 : (self.currentStep + delta); + double queueNotFullDuration = (self.currentStep - delta) < 0 ? 0 : (self.currentStep - delta); + double calculatedDuration = queueIsFull ? queueFullDuration : queueNotFullDuration; + + if (self.currentStep != calculatedDuration) { + self.currentStep = calculatedDuration; + self.lastUpdated = currentTime; + } + + return calculatedDuration; +} + +- (void)implementOnDemandUploadDelay:(int)delay { + sleep(delay); +} + +- (NSString *)recordOnDemandExceptionWithModel:(FIRExceptionModel *)exceptionModel { + return FIRCLSExceptionRecordOnDemandModel(exceptionModel, self.recordedOnDemandExceptionCount, + self.droppedOnDemandExceptionCount); +} + +- (int)droppedOnDemandExceptionCount { + @synchronized(self) { + return _droppedOnDemandExceptionCount; + } +} + +- (void)setDroppedOnDemandExceptionCount:(int)count { + @synchronized(self) { + _droppedOnDemandExceptionCount = count; + } +} + +- (void)incrementDroppedExceptionCount { + @synchronized(self) { + [self setDroppedOnDemandExceptionCount:[self droppedOnDemandExceptionCount] + 1]; + } +} + +- (void)decrementDroppedExceptionCount { + @synchronized(self) { + [self setDroppedOnDemandExceptionCount:[self droppedOnDemandExceptionCount] - 1]; + } +} + +- (void)resetDroppedExceptionCount { + @synchronized(self) { + [self setDroppedOnDemandExceptionCount:0]; + } +} + +- (int)recordedOnDemandExceptionCount { + @synchronized(self) { + return _recordedOnDemandExceptionCount; + } +} + +- (void)setRecordedOnDemandExceptionCount:(int)count { + @synchronized(self) { + _recordedOnDemandExceptionCount = count; + } +} + +- (void)incrementRecordedExceptionCount { + @synchronized(self) { + [self setRecordedOnDemandExceptionCount:[self recordedOnDemandExceptionCount] + 1]; + } +} + +- (void)decrementRecordedExceptionCount { + @synchronized(self) { + [self setRecordedOnDemandExceptionCount:[self recordedOnDemandExceptionCount] - 1]; + } +} + +- (int)getQueuedOperationsCount { + @synchronized(self) { + return _queuedOperationsCount; + } +} + +- (void)setQueuedOperationsCount:(int)count { + @synchronized(self) { + _queuedOperationsCount = count; + } +} + +- (void)incrementQueuedOperationCount { + @synchronized(self) { + [self setQueuedOperationsCount:[self getQueuedOperationsCount] + 1]; + } +} + +- (void)decrementQueuedOperationCount { + @synchronized(self) { + [self setQueuedOperationsCount:[self getQueuedOperationsCount] - 1]; + } +} + +- (BOOL)isQueueFull { + return ([self getQueuedOperationsCount] >= self.settings.onDemandUploadRate); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.h new file mode 100644 index 0000000..59e3f5f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.h @@ -0,0 +1,126 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +@class FIRCLSApplicationIdentifierModel; +@class FIRCLSFileManager; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRCLSSettings : NSObject + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager + appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel + NS_DESIGNATED_INITIALIZER; + +/** + * Recreates the settings dictionary by re-reading the settings file from persistent storage. This + * should be called before any settings values are read, as it will populate the underlying + * settingsDictionary. If the Google App ID has changed or there is an error, delete the cache file + * and settingsDictionary. If the cache has expired, set `isCacheExpired` to true so that settings + * are re-fetched, but do not delete any values. + */ +- (void)reloadFromCacheWithGoogleAppID:(NSString *)googleAppID + currentTimestamp:(NSTimeInterval)currentTimestamp; + +/** + * Stores a separate file with the settings expiration and Google App ID it was saved with + * so that we can later determine that the settings have expired. + * + * This should be called in a background thread right after the settings.json file has been + * downloaded. + */ +- (void)cacheSettingsWithGoogleAppID:(NSString *)googleAppID + currentTimestamp:(NSTimeInterval)currentTimestamp; + +/** + * Returns true when Settings should be fetched from the server again + */ +@property(nonatomic, readonly) BOOL isCacheExpired; + +/** + * Determines how long these Settings should be respected until the SDK should fetch again + */ +@property(nonatomic, readonly) uint32_t cacheDurationSeconds; + +/** + * When this is false, Crashlytics will not start up + */ +@property(nonatomic, readonly) BOOL collectReportsEnabled; + +/** + * When this is false, Crashlytics will not collect non-fatal errors and errors + * from the custom exception / record error APIs + */ +@property(nonatomic, readonly) BOOL errorReportingEnabled; + +/** + * When this is false, Crashlytics will not collect custom exceptions from the API + */ +@property(nonatomic, readonly) BOOL customExceptionsEnabled; + +/** + * When this is true, Crashlytics will collect data from MetricKit + */ +@property(nonatomic, readonly) BOOL metricKitCollectionEnabled; + +/** + * Returns the maximum number of custom exception events that will be + * recorded in a session. + */ +@property(nonatomic, readonly) uint32_t errorLogBufferSize; + +/** + * Returns the maximum size of the log buffer in bytes + */ +@property(nonatomic, readonly) uint32_t logBufferSize; + +/** + * Returns the maximum number of custom exceptions that will be collected + * in a session. + */ +@property(nonatomic, readonly) uint32_t maxCustomExceptions; + +/** + * Returns the maximum number of custom key-value pair keys (not bytes). + */ +@property(nonatomic, readonly) uint32_t maxCustomKeys; + +/** + * Returns the initial upload rate for on-demand exception reporting. + */ +@property(nonatomic, readonly) double onDemandUploadRate; + +/** + * Base exponent used when exponential backoff is triggered for on-demand reporting. + */ +@property(nonatomic, readonly) double onDemandBackoffBase; + +/** + * Step duration to use with exponential backoff for on-demand reporting. + */ +@property(nonatomic, readonly) uint32_t onDemandBackoffStepDuration; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.m new file mode 100644 index 0000000..c0703ec --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSettings.m @@ -0,0 +1,360 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h" + +NSString *const CreatedAtKey = @"created_at"; +NSString *const GoogleAppIDKey = @"google_app_id"; +NSString *const BuildInstanceID = @"build_instance_id"; +NSString *const AppVersion = @"app_version"; + +@interface FIRCLSSettings () + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; +@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel; + +@property(nonatomic, strong) NSDictionary *settingsDictionary; + +@property(nonatomic) BOOL isCacheKeyExpired; + +@end + +@implementation FIRCLSSettings + +- (instancetype)initWithFileManager:(FIRCLSFileManager *)fileManager + appIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel { + self = [super init]; + if (!self) { + return nil; + } + + _fileManager = fileManager; + _appIDModel = appIDModel; + + _settingsDictionary = nil; + _isCacheKeyExpired = NO; + + return self; +} + +#pragma mark - Public Methods + +- (void)reloadFromCacheWithGoogleAppID:(NSString *)googleAppID + currentTimestamp:(NSTimeInterval)currentTimestamp { + NSString *settingsFilePath = self.fileManager.settingsFilePath; + + NSData *data = [self.fileManager dataWithContentsOfFile:settingsFilePath]; + + if (!data) { + FIRCLSDebugLog(@"[Crashlytics:Settings] No settings were cached"); + + return; + } + + NSError *error = nil; + @synchronized(self) { + _settingsDictionary = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + } + + if (!_settingsDictionary) { + FIRCLSErrorLog(@"Could not load settings file data with error: %@", error.localizedDescription); + + // Attempt to remove it, in case it's messed up + [self deleteCachedSettings]; + return; + } + + NSDictionary *cacheKey = [self loadCacheKey]; + if (!cacheKey) { + FIRCLSErrorLog(@"Could not load settings cache key"); + + [self deleteCachedSettings]; + return; + } + + NSString *cachedGoogleAppID = cacheKey[GoogleAppIDKey]; + if (![cachedGoogleAppID isEqualToString:googleAppID]) { + FIRCLSDebugLog( + @"[Crashlytics:Settings] Invalidating settings cache because Google App ID changed"); + + [self deleteCachedSettings]; + return; + } + + NSTimeInterval cacheCreatedAt = [cacheKey[CreatedAtKey] unsignedIntValue]; + NSTimeInterval cacheDurationSeconds = self.cacheDurationSeconds; + if (currentTimestamp > (cacheCreatedAt + cacheDurationSeconds)) { + FIRCLSDebugLog(@"[Crashlytics:Settings] Settings TTL expired"); + + @synchronized(self) { + self.isCacheKeyExpired = YES; + } + } + + NSString *cacheBuildInstanceID = cacheKey[BuildInstanceID]; + if (![cacheBuildInstanceID isEqualToString:self.appIDModel.buildInstanceID]) { + FIRCLSDebugLog(@"[Crashlytics:Settings] Settings expired because build instance changed"); + + @synchronized(self) { + self.isCacheKeyExpired = YES; + } + } + + NSString *cacheAppVersion = cacheKey[AppVersion]; + if (![cacheAppVersion isEqualToString:self.appIDModel.synthesizedVersion]) { + FIRCLSDebugLog(@"[Crashlytics:Settings] Settings expired because app version changed"); + + @synchronized(self) { + self.isCacheKeyExpired = YES; + } + } +} + +- (void)cacheSettingsWithGoogleAppID:(NSString *)googleAppID + currentTimestamp:(NSTimeInterval)currentTimestamp { + NSNumber *createdAtTimestamp = [NSNumber numberWithDouble:currentTimestamp]; + NSDictionary *cacheKey = @{ + CreatedAtKey : createdAtTimestamp, + GoogleAppIDKey : googleAppID, + BuildInstanceID : self.appIDModel.buildInstanceID, + AppVersion : self.appIDModel.synthesizedVersion, + }; + + NSError *error = nil; + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:cacheKey + options:kNilOptions + error:&error]; + + if (!jsonData) { + FIRCLSErrorLog(@"Could not create settings cache key with error: %@", + error.localizedDescription); + + return; + } + + if ([self.fileManager fileExistsAtPath:self.fileManager.settingsCacheKeyPath]) { + [self.fileManager removeItemAtPath:self.fileManager.settingsCacheKeyPath]; + } + [self.fileManager createFileAtPath:self.fileManager.settingsCacheKeyPath + contents:jsonData + attributes:nil]; + + // If Settings were expired before, they should no longer be expired after this. + // This may be set back to YES if reloading from the cache fails + @synchronized(self) { + self.isCacheKeyExpired = NO; + } + + [self reloadFromCacheWithGoogleAppID:googleAppID currentTimestamp:currentTimestamp]; +} + +#pragma mark - Convenience Methods + +- (NSDictionary *)loadCacheKey { + NSData *cacheKeyData = + [self.fileManager dataWithContentsOfFile:self.fileManager.settingsCacheKeyPath]; + + if (!cacheKeyData) { + return nil; + } + + NSError *error = nil; + NSDictionary *cacheKey = [NSJSONSerialization JSONObjectWithData:cacheKeyData + options:NSJSONReadingAllowFragments + error:&error]; + return cacheKey; +} + +- (void)deleteCachedSettings { + __weak FIRCLSSettings *weakSelf = self; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ + __strong FIRCLSSettings *strongSelf = weakSelf; + if ([strongSelf.fileManager fileExistsAtPath:strongSelf.fileManager.settingsFilePath]) { + [strongSelf.fileManager removeItemAtPath:strongSelf.fileManager.settingsFilePath]; + } + if ([strongSelf.fileManager fileExistsAtPath:strongSelf.fileManager.settingsCacheKeyPath]) { + [strongSelf.fileManager removeItemAtPath:strongSelf.fileManager.settingsCacheKeyPath]; + } + }); + + @synchronized(self) { + self.isCacheKeyExpired = YES; + _settingsDictionary = nil; + } +} + +- (NSDictionary *)settingsDictionary { + @synchronized(self) { + return _settingsDictionary; + } +} + +#pragma mark - Settings Groups + +- (NSDictionary *)appSettings { + return self.settingsDictionary[@"app"]; +} + +- (NSDictionary *)sessionSettings { + return self.settingsDictionary[@"session"]; +} + +- (NSDictionary *)featuresSettings { + return self.settingsDictionary[@"features"]; +} + +- (NSDictionary *)fabricSettings { + return self.settingsDictionary[@"fabric"]; +} + +#pragma mark - Caching + +- (BOOL)isCacheExpired { + if (!self.settingsDictionary) { + return YES; + } + + @synchronized(self) { + return self.isCacheKeyExpired; + } +} + +- (uint32_t)cacheDurationSeconds { + id fetchedCacheDuration = self.settingsDictionary[@"cache_duration"]; + if (fetchedCacheDuration) { + return [fetchedCacheDuration unsignedIntValue]; + } + + return 60 * 60; +} + +#pragma mark - On / Off Switches + +- (BOOL)errorReportingEnabled { + NSNumber *value = [self featuresSettings][@"collect_logged_exceptions"]; + + if (value != nil) { + return [value boolValue]; + } + + return YES; +} + +- (BOOL)customExceptionsEnabled { + // Right now, recording custom exceptions from the API and + // automatically capturing non-fatal errors go hand in hand + return [self errorReportingEnabled]; +} + +- (BOOL)collectReportsEnabled { + NSNumber *value = [self featuresSettings][@"collect_reports"]; + + if (value != nil) { + return value.boolValue; + } + + return YES; +} + +- (BOOL)metricKitCollectionEnabled { + NSNumber *value = [self featuresSettings][@"collect_metric_kit"]; + + if (value != nil) { + return value.boolValue; + } + + return NO; +} + +#pragma mark - Optional Limit Overrides + +- (uint32_t)errorLogBufferSize { + return [self logBufferSize]; +} + +- (uint32_t)logBufferSize { + NSNumber *value = [self sessionSettings][@"log_buffer_size"]; + + if (value != nil) { + return value.unsignedIntValue; + } + + return 64 * 1000; +} + +- (uint32_t)maxCustomExceptions { + NSNumber *value = [self sessionSettings][@"max_custom_exception_events"]; + + if (value != nil) { + return value.unsignedIntValue; + } + + return 8; +} + +- (uint32_t)maxCustomKeys { + NSNumber *value = [self sessionSettings][@"max_custom_key_value_pairs"]; + + if (value != nil) { + return value.unsignedIntValue; + } + + return 64; +} + +#pragma mark - On Demand Reporting Parameters + +- (double)onDemandUploadRate { + NSNumber *value = self.settingsDictionary[@"on_demand_upload_rate_per_minute"]; + + if (value != nil) { + return value.doubleValue; + } + + return 10; // on-demand uploads allowed per minute +} + +- (double)onDemandBackoffBase { + NSNumber *value = self.settingsDictionary[@"on_demand_backoff_base"]; + + if (value != nil) { + return [value doubleValue]; + } + + return 1.5; // base of exponent for exponential backoff +} + +- (uint32_t)onDemandBackoffStepDuration { + NSNumber *value = self.settingsDictionary[@"on_demand_backoff_step_duration_seconds"]; + + if (value != nil) { + return value.unsignedIntValue; + } + + return 6; // step duration for exponential backoff +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h new file mode 100644 index 0000000..a18e604 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h @@ -0,0 +1,26 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRStackFrame; + +@interface FIRCLSSymbolResolver : NSObject + +- (BOOL)loadBinaryImagesFromFile:(NSString *)path; + +- (FIRStackFrame *)frameForAddress:(uint64_t)address; +- (BOOL)updateStackFrame:(FIRStackFrame *)frame; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.m new file mode 100644 index 0000000..8ce74da --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.m @@ -0,0 +1,176 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h" + +#include + +#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSInternalLogging.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +@interface FIRCLSSymbolResolver () { + NSMutableArray* _binaryImages; +} + +@end + +@implementation FIRCLSSymbolResolver + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _binaryImages = [NSMutableArray array]; + + return self; +} + +- (BOOL)loadBinaryImagesFromFile:(NSString*)path { + if ([path length] == 0) { + return NO; + } + + NSArray* sections = FIRCLSFileReadSections([path fileSystemRepresentation], false, nil); + + if ([sections count] == 0) { + FIRCLSErrorLog(@"Failed to read binary image file %@", path); + return NO; + } + + // filter out unloads, as well as loads with invalid entries + for (NSDictionary* entry in sections) { + NSDictionary* details = [entry objectForKey:@"load"]; + if (!details) { + continue; + } + + // This does happen occasionally and causes a crash. I'm really not sure there + // is anything sane we can do in this case. + if (![details objectForKey:@"base"] || ![details objectForKey:@"size"]) { + continue; + } + + if ([details objectForKey:@"base"] == (id)[NSNull null] || + [details objectForKey:@"size"] == (id)[NSNull null]) { + continue; + } + + [_binaryImages addObject:details]; + } + + [_binaryImages sortUsingComparator:^NSComparisonResult(id obj1, id obj2) { + NSNumber* base1 = [obj1 objectForKey:@"base"]; + NSNumber* base2 = [obj2 objectForKey:@"base"]; + + return [base1 compare:base2]; + }]; + + return YES; +} + +- (NSDictionary*)loadedBinaryImageForPC:(uintptr_t)pc { + NSUInteger index = + [_binaryImages indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL* stop) { + uintptr_t base = [[obj objectForKey:@"base"] unsignedIntegerValue]; + uintptr_t size = [[obj objectForKey:@"size"] unsignedIntegerValue]; + + return pc >= base && pc < (base + size); + }]; + + if (index == NSNotFound) { + return nil; + } + + return [_binaryImages objectAtIndex:index]; +} + +- (BOOL)fillInImageDetails:(FIRCLSBinaryImageDetails*)details forUUID:(NSString*)uuid { + if (!details || !uuid) { + return NO; + } + + return FIRCLSBinaryImageFindImageForUUID([uuid UTF8String], details); +} + +- (FIRStackFrame*)frameForAddress:(uint64_t)address { + FIRStackFrame* frame = [FIRStackFrame stackFrameWithAddress:(NSUInteger)address]; + + if (![self updateStackFrame:frame]) { + return nil; + } + + return frame; +} + +- (BOOL)updateStackFrame:(FIRStackFrame*)frame { + uint64_t address = [frame address]; + if (address == 0) { + return NO; + } + + NSDictionary* binaryImage = [self loadedBinaryImageForPC:(uintptr_t)address]; + + FIRCLSBinaryImageDetails imageDetails; + + if (![self fillInImageDetails:&imageDetails forUUID:[binaryImage objectForKey:@"uuid"]]) { +#if DEBUG + FIRCLSSDKLog("Image not found\n"); +#endif + return NO; + } + + uintptr_t addr = (uintptr_t)address - + (uintptr_t)[[binaryImage objectForKey:@"base"] unsignedIntegerValue] + + (uintptr_t)imageDetails.node.baseAddress; + Dl_info dlInfo; + + if (dladdr((void*)addr, &dlInfo) == 0) { +#if DEBUG + FIRCLSSDKLog("Could not look up address\n"); +#endif + return NO; + } + + if (addr - (uintptr_t)dlInfo.dli_saddr == 0) { + addr -= 2; + if (dladdr((void*)addr, &dlInfo) == 0) { +#if DEBUG + FIRCLSSDKLog("Could not look up address after move\n"); +#endif + return NO; + } + } + + if (dlInfo.dli_sname) { + NSString* symbol = [NSString stringWithUTF8String:dlInfo.dli_sname]; + + frame.symbol = symbol; + frame.rawSymbol = symbol; + } + + if (addr > (uintptr_t)dlInfo.dli_saddr) { + [frame setOffset:addr - (uintptr_t)dlInfo.dli_saddr]; + } + + [frame setLibrary:[[binaryImage objectForKey:@"path"] lastPathComponent]]; + + return YES; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h new file mode 100644 index 0000000..a3177b2 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h" + +@interface FIRCLSRecordApplication : FIRCLSRecordBase + +@property(nonatomic, copy) NSString *build_version; +@property(nonatomic, copy) NSString *display_version; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.m new file mode 100644 index 0000000..b447416 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.m @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h" + +@implementation FIRCLSRecordApplication + +- (instancetype)initWithDict:(NSDictionary *)dict { + self = [super initWithDict:dict]; + if (self) { + _display_version = dict[@"display_version"]; + _build_version = dict[@"build_version"]; + } + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h new file mode 100644 index 0000000..57c620d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * This is the base class to represent the data in the persisted crash (.clsrecord) files. + * The properties these subclasses are nullable on purpose. If there is an issue reading values + * from the crash files, continue as if those fields are optional so a report can still be uploaded. + * That way the issue can potentially be monitored through the backend. + **/ +@interface FIRCLSRecordBase : NSObject + +/** + * Mark the default initializer as unavailable so the subclasses do not have to add the same line + **/ +- (instancetype)init NS_UNAVAILABLE; + +/** + * All subclasses should define an initializer taking in a dictionary + **/ +- (instancetype)initWithDict:(NSDictionary *)dict; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.m new file mode 100644 index 0000000..9b07ffe --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.m @@ -0,0 +1,25 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h" + +@implementation FIRCLSRecordBase + +- (instancetype)initWithDict:(NSDictionary *)dict { + return [super init]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h new file mode 100644 index 0000000..a1a18bc --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h" + +@interface FIRCLSRecordHost : FIRCLSRecordBase + +@property(nonatomic, copy) NSString *platform; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.m new file mode 100644 index 0000000..dd678a0 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.m @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h" + +@implementation FIRCLSRecordHost + +- (instancetype)initWithDict:(NSDictionary *)dict { + self = [super initWithDict:dict]; + if (self) { + _platform = dict[@"platform"]; + } + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h new file mode 100644 index 0000000..dc508c5 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h @@ -0,0 +1,24 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordBase.h" + +@interface FIRCLSRecordIdentity : FIRCLSRecordBase + +@property(nonatomic, copy) NSString *build_version; +@property(nonatomic, copy) NSString *app_quality_session_id; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.m new file mode 100644 index 0000000..651d318 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.m @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h" + +@implementation FIRCLSRecordIdentity + +- (instancetype)initWithDict:(NSDictionary *)dict { + self = [super initWithDict:dict]; + if (self) { + _build_version = dict[@"build_version"]; + _app_quality_session_id = dict[@"app_quality_session_id"]; + } + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h new file mode 100644 index 0000000..4db047c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#include "Crashlytics/Protogen/nanopb/crashlytics.nanopb.h" + +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" + +#import + +/// This class is responsible for reading the persisted crash reports from disk and converting them +/// the information into the nanopb model to be used with GoogleDataTransport +@interface FIRCLSReportAdapter : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/// Initializer +/// @param folderPath Path where the persisted crash files reside +/// @param googleAppID ID for the app passed in from Firebase Core +/// @param installIDModel for pulling the Crashlytics Installation UUID +- (instancetype)initWithPath:(NSString *)folderPath + googleAppId:(NSString *)googleAppID + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + fiid:(NSString *)fiid + authToken:(NSString *)authToken; +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m new file mode 100644 index 0000000..2cbcdb9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.m @@ -0,0 +1,268 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h" +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h" + +#import +#import +#import + +@interface FIRCLSReportAdapter () + +@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel; +@property(nonatomic, copy) NSString *fiid; +@property(nonatomic, copy) NSString *authToken; + +@end + +@implementation FIRCLSReportAdapter + +- (instancetype)initWithPath:(NSString *)folderPath + googleAppId:(NSString *)googleAppID + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + fiid:(NSString *)fiid + authToken:(NSString *)authToken { + self = [super init]; + if (self) { + _folderPath = folderPath; + _googleAppID = googleAppID; + _installIDModel = installIDModel; + _fiid = [fiid copy]; + _authToken = [authToken copy]; + + [self loadMetaDataFile]; + + _report = [self protoReport]; + } + return self; +} + +- (void)dealloc { + pb_release(google_crashlytics_Report_fields, &_report); +} + +// +// MARK: Load from persisted crash files +// + +/// Reads from metadata.clsrecord +- (void)loadMetaDataFile { + NSString *path = [self.folderPath stringByAppendingPathComponent:FIRCLSReportMetadataFile]; + NSDictionary *dict = [FIRCLSReportAdapter combinedDictionariesFromFilePath:path]; + + self.identity = [[FIRCLSRecordIdentity alloc] initWithDict:dict[@"identity"]]; + self.host = [[FIRCLSRecordHost alloc] initWithDict:dict[@"host"]]; + self.application = [[FIRCLSRecordApplication alloc] initWithDict:dict[@"application"]]; +} + +/// Return the persisted crash file as a combined dictionary that way lookups can occur with a key +/// (to avoid ordering dependency) +/// @param filePath Persisted crash file path ++ (NSDictionary *)combinedDictionariesFromFilePath:(NSString *)filePath { + NSMutableDictionary *joinedDict = [[NSMutableDictionary alloc] init]; + for (NSDictionary *dict in [self dictionariesFromEachLineOfFile:filePath]) { + [joinedDict addEntriesFromDictionary:dict]; + } + return joinedDict; +} + +/// The persisted crash files contains JSON on separate lines. Read each line and return the JSON +/// data as a dictionary. +/// @param filePath Persisted crash file path ++ (NSArray *)dictionariesFromEachLineOfFile:(NSString *)filePath { + NSString *content = [[NSString alloc] initWithContentsOfFile:filePath + encoding:NSUTF8StringEncoding + error:nil]; + NSArray *lines = + [content componentsSeparatedByCharactersInSet:NSCharacterSet.newlineCharacterSet]; + + NSMutableArray *array = [[NSMutableArray alloc] init]; + + int lineNum = 0; + for (NSString *line in lines) { + lineNum++; + + if (line.length == 0) { + // Likely newline at the end of the file + continue; + } + + NSError *error; + NSDictionary *dict = + [NSJSONSerialization JSONObjectWithData:[line dataUsingEncoding:NSUTF8StringEncoding] + options:0 + error:&error]; + + if (error) { + FIRCLSErrorLog(@"Failed to read JSON from file (%@) line (%d) with error: %@", filePath, + lineNum, error); + } else { + [array addObject:dict]; + } + } + + return array; +} + +// +// MARK: GDTCOREventDataObject +// + +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, google_crashlytics_Report_fields, &_report)) { + FIRCLSErrorLog(@"Error in nanopb encoding for size: %s", PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, google_crashlytics_Report_fields, &_report)) { + FIRCLSErrorLog(@"Error in nanopb encoding for bytes: %s", PB_GET_ERROR(&ostream)); + } + + return CFBridgingRelease(dataRef); +} + +// +// MARK: NanoPB conversions +// + +- (google_crashlytics_Report)protoReport { + google_crashlytics_Report report = google_crashlytics_Report_init_default; + report.sdk_version = FIRCLSEncodeString(self.identity.build_version); + report.gmp_app_id = FIRCLSEncodeString(self.googleAppID); + report.platform = [self protoPlatformFromString:self.host.platform]; + report.installation_uuid = FIRCLSEncodeString(self.installIDModel.installID); + report.firebase_installation_id = FIRCLSEncodeString(self.fiid); + report.app_quality_session_id = FIRCLSEncodeString(self.identity.app_quality_session_id); + report.firebase_authentication_token = FIRCLSEncodeString(self.authToken); + report.build_version = FIRCLSEncodeString(self.application.build_version); + report.display_version = FIRCLSEncodeString(self.application.display_version); + report.apple_payload = [self protoFilesPayload]; + return report; +} + +- (google_crashlytics_FilesPayload)protoFilesPayload { + google_crashlytics_FilesPayload apple_payload = google_crashlytics_FilesPayload_init_default; + + NSArray *clsRecords = [self clsRecordFilePaths]; + google_crashlytics_FilesPayload_File *files = + malloc(sizeof(google_crashlytics_FilesPayload_File) * clsRecords.count); + + if (files == NULL) { + // files and files_count are initialized to NULL and 0 by default. + return apple_payload; + } + for (NSUInteger i = 0; i < clsRecords.count; i++) { + google_crashlytics_FilesPayload_File file = google_crashlytics_FilesPayload_File_init_default; + file.filename = FIRCLSEncodeString(clsRecords[i].lastPathComponent); + + NSError *error; + file.contents = FIRCLSEncodeData([NSData dataWithContentsOfFile:clsRecords[i] + options:0 + error:&error]); + if (error) { + FIRCLSErrorLog(@"Failed to read from %@ with error: %@", clsRecords[i], error); + } + + files[i] = file; + } + + apple_payload.files = files; + apple_payload.files_count = (pb_size_t)clsRecords.count; + + return apple_payload; +} + +- (NSArray *)clsRecordFilePaths { + NSMutableArray *clsRecords = [[NSMutableArray alloc] init]; + + NSError *error; + NSArray *files = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:self.folderPath + error:&error]; + + if (error) { + FIRCLSErrorLog(@"Failed to find .clsrecords from %@ with error: %@", self.folderPath, error); + return clsRecords; + } + + [files enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + NSString *filename = (NSString *)obj; + NSString *lowerExtension = filename.pathExtension.lowercaseString; + if ([lowerExtension isEqualToString:@"clsrecord"] || + [lowerExtension isEqualToString:@"symbolicated"]) { + [clsRecords addObject:[self.folderPath stringByAppendingPathComponent:filename]]; + } + }]; + + return [clsRecords sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]; +} + +- (google_crashlytics_Platforms)protoPlatformFromString:(NSString *)str { + NSString *platform = str.lowercaseString; + + if ([platform isEqualToString:@"ios"]) { + return google_crashlytics_Platforms_IOS; + } else if ([platform isEqualToString:@"mac"]) { + return google_crashlytics_Platforms_MAC_OS_X; + } else if ([platform isEqualToString:@"tvos"]) { + return google_crashlytics_Platforms_TVOS; + } else { + return google_crashlytics_Platforms_UNKNOWN_PLATFORM; + } +} + +/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * @note Memory needs to be freed manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *FIRCLSEncodeString(NSString *string) { + if ([string isMemberOfClass:[NSNull class]]) { + FIRCLSErrorLog(@"Expected encodable string, but found NSNull instead. " + @"Set a symbolic breakpoint at FIRCLSEncodeString to debug."); + string = nil; + } + NSString *stringToEncode = string ? string : @""; + NSData *stringBytes = [stringToEncode dataUsingEncoding:NSUTF8StringEncoding]; + return FIRCLSEncodeData(stringBytes); +} + +/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *FIRCLSEncodeData(NSData *data) { + pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytes == NULL) { + return NULL; + } + memcpy(pbBytes->bytes, [data bytes], data.length); + pbBytes->size = (pb_size_t)data.length; + return pbBytes; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h new file mode 100644 index 0000000..809e08d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter_Private.h @@ -0,0 +1,43 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSReportAdapter.h" + +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordApplication.h" +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordHost.h" +#import "Crashlytics/Crashlytics/Models/Record/FIRCLSRecordIdentity.h" + +pb_bytes_array_t *FIRCLSEncodeString(NSString *string); +pb_bytes_array_t *FIRCLSEncodeData(NSData *data); + +@interface FIRCLSReportAdapter () + +@property(nonatomic, readonly) BOOL hasCrashed; + +@property(nonatomic, strong) NSString *folderPath; +@property(nonatomic, strong) NSString *googleAppID; + +// From metadata.clsrecord +@property(nonatomic, strong) FIRCLSRecordIdentity *identity; +@property(nonatomic, strong) FIRCLSRecordHost *host; +@property(nonatomic, strong) FIRCLSRecordApplication *application; + +@property(nonatomic) google_crashlytics_Report report; + +- (google_crashlytics_Report)protoReport; +- (NSArray *)clsRecordFilePaths; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.h new file mode 100644 index 0000000..5636d3d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.h @@ -0,0 +1,23 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +typedef void (^FIRCLSAsyncOperationCompletionBlock)(NSError* error); + +@interface FIRCLSAsyncOperation : NSOperation + +@property(copy, nonatomic) FIRCLSAsyncOperationCompletionBlock asyncCompletion; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.m new file mode 100644 index 0000000..1ec49e4 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.m @@ -0,0 +1,135 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.h" + +@interface FIRCLSAsyncOperation () { + BOOL _internalExecuting; + BOOL _internalFinished; +} + +@property(nonatomic, strong) NSRecursiveLock *lock; + +@end + +@implementation FIRCLSAsyncOperation + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _internalExecuting = NO; + _internalFinished = NO; + + self.lock = [[NSRecursiveLock alloc] init]; + self.lock.name = @"com.crashlytics.async-operation-lock"; + + return self; +} + +#pragma mark - NSOperation Overrides +- (BOOL)isConcurrent { + return YES; +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (BOOL)isExecuting { + [self.lock lock]; + BOOL result = _internalExecuting; + [self.lock unlock]; + + return result; +} + +- (BOOL)isFinished { + [self.lock lock]; + BOOL result = _internalFinished; + [self.lock unlock]; + + return result; +} + +- (void)start { + if ([self checkForCancellation]) { + return; + } + + [self markStarted]; + + [self main]; +} + +#pragma mark - Utilities +- (void)changeValueForKey:(NSString *)key inBlock:(void (^)(void))block { + [self willChangeValueForKey:key]; + block(); + [self didChangeValueForKey:key]; +} + +- (void)lock:(void (^)(void))block { + [self.lock lock]; + block(); + [self.lock unlock]; +} + +- (BOOL)checkForCancellation { + if ([self isCancelled]) { + [self markDone]; + return YES; + } + + return NO; +} + +#pragma mark - State Management +- (void)unlockedMarkFinished { + [self changeValueForKey:@"isFinished" + inBlock:^{ + self->_internalFinished = YES; + }]; +} + +- (void)unlockedMarkStarted { + [self changeValueForKey:@"isExecuting" + inBlock:^{ + self->_internalExecuting = YES; + }]; +} + +- (void)unlockedMarkComplete { + [self changeValueForKey:@"isExecuting" + inBlock:^{ + self->_internalExecuting = NO; + }]; +} + +- (void)markStarted { + [self lock:^{ + [self unlockedMarkStarted]; + }]; +} + +- (void)markDone { + [self lock:^{ + [self unlockedMarkComplete]; + [self unlockedMarkFinished]; + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation_Private.h new file mode 100644 index 0000000..6dcc707 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation_Private.h @@ -0,0 +1,24 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/FIRCLSAsyncOperation.h" + +@interface FIRCLSAsyncOperation (Private) + +- (void)markStarted; +- (void)markDone; + +- (BOOL)checkForCancellation; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h new file mode 100644 index 0000000..1e90286 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h @@ -0,0 +1,30 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRCLSInternalReport; +@class FIRCLSSymbolResolver; + +@interface FIRCLSProcessReportOperation : NSOperation + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)initWithReport:(FIRCLSInternalReport *)report + resolver:(FIRCLSSymbolResolver *)resolver NS_DESIGNATED_INITIALIZER; + +@property(nonatomic, readonly) FIRCLSSymbolResolver *symbolResolver; +@property(nonatomic, readonly) FIRCLSInternalReport *report; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.m new file mode 100644 index 0000000..03a7c1e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.m @@ -0,0 +1,113 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Reports/FIRCLSProcessReportOperation.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInternalReport.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h" +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h" +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.h" +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.h" +#import "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +@implementation FIRCLSProcessReportOperation + +- (instancetype)initWithReport:(FIRCLSInternalReport *)report + resolver:(FIRCLSSymbolResolver *)resolver { + self = [super init]; + if (!self) { + return nil; + } + + _report = report; + _symbolResolver = resolver; + + return self; +} + +- (NSString *)binaryImagePath { + return self.report.binaryImagePath; +} + +- (NSArray *)threadArrayFromFile:(NSString *)path { + NSArray *threads = + FIRCLSFileReadSections([path fileSystemRepresentation], false, ^NSObject *(id obj) { + // use this to select out the one entry that has a "threads" top-level entry + return [obj objectForKey:@"threads"]; + }); + + if ([threads count] == 0) { + return nil; + } + + // threads is actually an array of arrays + threads = [threads objectAtIndex:0]; + if (!threads) { + return nil; + } + + NSMutableArray *threadArray = [NSMutableArray array]; + + for (NSDictionary *threadDetails in threads) { + NSMutableArray *frameArray = [NSMutableArray array]; + + for (NSNumber *pc in [threadDetails objectForKey:@"stacktrace"]) { + FIRStackFrame *frame = [FIRStackFrame stackFrameWithAddress:[pc unsignedIntegerValue]]; + + [frameArray addObject:frame]; + } + + [threadArray addObject:frameArray]; + } + + return threadArray; +} + +- (BOOL)symbolicateFile:(NSString *)path withResolver:(FIRCLSSymbolResolver *)resolver { + NSArray *threadArray = [self threadArrayFromFile:path]; + if (!threadArray) { + return NO; + } + + FIRCLSSymbolicationOperation *symbolicationOp = [[FIRCLSSymbolicationOperation alloc] init]; + [symbolicationOp setThreadArray:threadArray]; + [symbolicationOp setSymbolResolver:resolver]; + + FIRCLSDemangleOperation *demangleOp = [[FIRCLSDemangleOperation alloc] init]; + [demangleOp setThreadArray:threadArray]; + + FIRCLSSerializeSymbolicatedFramesOperation *serializeOp = + [[FIRCLSSerializeSymbolicatedFramesOperation alloc] init]; + [serializeOp setThreadArray:threadArray]; + [serializeOp setOutputPath:[path stringByAppendingPathExtension:@"symbolicated"]]; + + [symbolicationOp start]; + [demangleOp start]; + [serializeOp start]; + + return YES; +} + +- (void)main { + if (![self.symbolResolver loadBinaryImagesFromFile:self.binaryImagePath]) { + return; + } + + [self.report enumerateSymbolicatableFilesInContent:^(NSString *path) { + [self symbolicateFile:path withResolver:self.symbolResolver]; + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h new file mode 100644 index 0000000..0680153 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h @@ -0,0 +1,24 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h" + +@interface FIRCLSDemangleOperation : FIRCLSThreadArrayOperation + ++ (NSString *)demangleSymbol:(const char *)symbol; ++ (NSString *)demangleCppSymbol:(const char *)symbol; + +- (NSString *)demangleSymbol:(const char *)symbol; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.mm b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.mm new file mode 100644 index 0000000..106a33c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.mm @@ -0,0 +1,96 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSDemangleOperation.h" +#include "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +#import + +@implementation FIRCLSDemangleOperation + ++ (NSString *)demangleSymbol:(const char *)symbol { + if (!symbol) { + return nil; + } + + if (strncmp(symbol, "_Z", 2) == 0) { + return [self demangleCppSymbol:symbol]; + } else if (strncmp(symbol, "__Z", 3) == 0) { + return [self demangleBlockInvokeCppSymbol:symbol]; + } + + return nil; +} + ++ (NSString *)demangleBlockInvokeCppSymbol:(const char *)symbol { + NSString *string = [NSString stringWithUTF8String:symbol]; + + // search backwards, because this string should be at the end + NSRange range = [string rangeOfString:@"_block_invoke" options:NSBackwardsSearch]; + + if (range.location == NSNotFound) { + return nil; + } + + // we need at least a "_Z..." for a valid C++ symbol, so make sure of that + if (range.location < 5) { + return nil; + } + + // extract the mangled C++ symbol from the string + NSString *cppSymbol = [string substringWithRange:NSMakeRange(1, range.location - 1)]; + cppSymbol = [self demangleSymbol:[cppSymbol UTF8String]]; + if (!cppSymbol) { + return nil; + } + + // extract out just the "_block_invoke..." part + string = + [string substringWithRange:NSMakeRange(range.location, [string length] - range.location)]; + + // and glue that onto the end + return [cppSymbol stringByAppendingString:string]; +} + ++ (NSString *)demangleCppSymbol:(const char *)symbol { + int status; + char *buffer = NULL; + + buffer = __cxxabiv1::__cxa_demangle(symbol, buffer, NULL, &status); + if (!buffer) { + return nil; + } + + NSString *result = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return result; +} + +- (NSString *)demangleSymbol:(const char *)symbol { + return [[self class] demangleSymbol:symbol]; +} + +- (void)main { + [self enumerateFramesWithBlock:^(FIRStackFrame *frame) { + NSString *demangedSymbol = [self demangleSymbol:[[frame rawSymbol] UTF8String]]; + + if (demangedSymbol) { + [frame setSymbol:demangedSymbol]; + } + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.h new file mode 100644 index 0000000..7ce245d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.h @@ -0,0 +1,21 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h" + +@interface FIRCLSSerializeSymbolicatedFramesOperation : FIRCLSThreadArrayOperation + +@property(nonatomic, copy) NSString *outputPath; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.m new file mode 100644 index 0000000..445b37c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.m @@ -0,0 +1,63 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSerializeSymbolicatedFramesOperation.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h" + +@implementation FIRCLSSerializeSymbolicatedFramesOperation + +- (void)main { + FIRCLSFile file; + + // Make sure not to open in append mode, so we can overwrite any pre-existing symbolication + // files. + if (!FIRCLSFileInitWithPathMode(&file, [self.outputPath fileSystemRepresentation], false, + false)) { + FIRCLSErrorLog(@"Failed to create output file"); + return; + } + + FIRCLSFileWriteSectionStart(&file, "threads"); + FIRCLSFileWriteArrayStart(&file); + + for (NSArray *frameArray in self.threadArray) { + FIRCLSFileWriteArrayStart(&file); + + for (FIRStackFrame *frame in frameArray) { + FIRCLSFileWriteHashStart(&file); + FIRCLSFileWriteHashEntryString(&file, "symbol", [[frame symbol] UTF8String]); + + // only include this field if it is present and different + if (![[frame rawSymbol] isEqualToString:[frame symbol]]) { + FIRCLSFileWriteHashEntryString(&file, "raw_symbol", [[frame rawSymbol] UTF8String]); + } + + FIRCLSFileWriteHashEntryUint64(&file, "offset", [frame offset]); + FIRCLSFileWriteHashEntryString(&file, "library", [[frame library] UTF8String]); + + FIRCLSFileWriteHashEnd(&file); + } + + FIRCLSFileWriteArrayEnd(&file); + } + + FIRCLSFileWriteArrayEnd(&file); + FIRCLSFileWriteSectionEnd(&file); + FIRCLSFileClose(&file); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.h new file mode 100644 index 0000000..2a26d60 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.h @@ -0,0 +1,23 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h" + +@class FIRCLSSymbolResolver; + +@interface FIRCLSSymbolicationOperation : FIRCLSThreadArrayOperation + +@property(nonatomic, strong) FIRCLSSymbolResolver *symbolResolver; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.m new file mode 100644 index 0000000..a8111fd --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.m @@ -0,0 +1,27 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSSymbolicationOperation.h" + +#import "Crashlytics/Crashlytics/Models/FIRCLSSymbolResolver.h" + +@implementation FIRCLSSymbolicationOperation + +- (void)main { + [self enumerateFramesWithBlock:^(FIRStackFrame *frame) { + [self.symbolResolver updateStackFrame:frame]; + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h new file mode 100644 index 0000000..0c2a1df --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h @@ -0,0 +1,25 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRStackFrame; + +@interface FIRCLSThreadArrayOperation : NSOperation + +@property(nonatomic, strong) NSArray *threadArray; + +- (void)enumerateFramesWithBlock:(void (^)(FIRStackFrame *frame))block; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.m new file mode 100644 index 0000000..76f59d9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.m @@ -0,0 +1,31 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Operations/Symbolication/FIRCLSThreadArrayOperation.h" + +@implementation FIRCLSThreadArrayOperation + +- (void)enumerateFramesWithBlock:(void (^)(FIRStackFrame *frame))block { + for (NSArray *frameArray in self.threadArray) { + for (FIRStackFrame *frame in frameArray) { + block(frame); + + if ([self isCancelled]) { + break; + } + } + } +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h new file mode 100644 index 0000000..a07f19d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h @@ -0,0 +1,36 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIRCLSExistingReportManager_Private_h +#define FIRCLSExistingReportManager_Private_h + +#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h" + +/** + * Visible for testing + */ +@interface FIRCLSExistingReportManager (Private) + +@property(nonatomic, strong) NSOperationQueue *operationQueue; + +@property(nonatomic, strong) NSArray *existingUnemptyActiveReportPaths; +@property(nonatomic, strong) NSArray *processingReportPaths; +@property(nonatomic, strong) NSArray *preparedReportPaths; + +- (void)handleOnDemandReportUpload:(NSString *)path + dataCollectionToken:(FIRCLSDataCollectionToken *)dataCollectionToken + asUrgent:(BOOL)urgent; +@end + +#endif /* FIRCLSExistingReportManager_Private_h */ diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h new file mode 100644 index 0000000..3b58944 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIRCLSOnDemandModel_Private_h +#define FIRCLSOnDemandModel_Private_h + +#import + +#import "Crashlytics/Crashlytics/Models/FIRCLSOnDemandModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h" +#import "Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h" + +@interface FIRCLSOnDemandModel (Private) + +- (instancetype)initWithFIRCLSSettings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager; + +- (BOOL)recordOnDemandExceptionIfQuota:(FIRExceptionModel *)exceptionModel + withDataCollectionEnabled:(BOOL)dataCollectionEnabled + usingExistingReportManager:(FIRCLSExistingReportManager *)existingReportManager; + +- (int)getQueuedOperationsCount; +- (void)setQueuedOperationsCount:(int)count; + +// When data collection is off, stores active paths that have been recorded but not dispatched for +// upload. Kept sorted (newest at front) so that we can limit on-device reports to the newest +// `FIRCLSMaxUnsentReports` reports. +@property(nonatomic, strong) NSMutableArray *storedActiveReportPaths; + +@property(nonatomic, readonly) int recordedOnDemandExceptionCount; +@property(nonatomic, readonly) int droppedOnDemandExceptionCount; +@property(nonatomic, readonly) int queuedOperationsCount; + +@property(nonatomic, strong) NSOperationQueue *operationQueue; + +@end + +#endif /* FIRCLSOnDemandModel_Private_h */ diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h new file mode 100644 index 0000000..cbf8a81 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRCrashlyticsReport_Private.h @@ -0,0 +1,35 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIRCrashlyticsReport_Private_h +#define FIRCrashlyticsReport_Private_h + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Internal initializer because this object is created by the SDK. + **/ +@interface FIRCrashlyticsReport (Private) + +- (instancetype)initWithInternalReport:(FIRCLSInternalReport *)internalReport; + +@property(nonatomic, strong) FIRCLSInternalReport *internalReport; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRCrashlyticsReport_Private_h */ diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h new file mode 100644 index 0000000..b89290f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h @@ -0,0 +1,35 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIRExceptionModel_Private_h +#define FIRExceptionModel_Private_h + +#import + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRExceptionModel.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRExceptionModel (Private) + +@property(nonatomic, copy) NSString *name; +@property(nonatomic, copy) NSString *reason; +@property(nonatomic) BOOL isFatal; +@property(nonatomic) BOOL onDemand; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRExceptionModel_Private_h */ diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h new file mode 100644 index 0000000..0683cb7 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Private/FIRStackFrame_Private.h @@ -0,0 +1,44 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRStackFrame.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class is used in conjunction with recordExceptionModel to record information about + * non-ObjC, non-C++, and non-Swift exceptions. All information included here will be displayed in + *the Crashlytics UI, and can influence crash grouping. Be particularly careful with the use of the + *address properties. If set, Crashlytics will attempt symbolication and could overwrite other + *properties in the process. + **/ +@interface FIRStackFrame (Private) + ++ (instancetype)stackFrame; ++ (instancetype)stackFrameWithAddress:(NSUInteger)address; ++ (instancetype)stackFrameWithSymbol:(NSString *)symbol; + +@property(nonatomic, copy, nullable) NSString *symbol; +@property(nonatomic, copy, nullable) NSString *rawSymbol; +@property(nonatomic, copy, nullable) NSString *library; +@property(nonatomic, copy, nullable) NSString *fileName; +@property(nonatomic, assign) uint32_t lineNumber; +@property(nonatomic, assign) uint64_t offset; +@property(nonatomic, assign) uint64_t address; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h new file mode 100644 index 0000000..1ace1be --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlytics.h @@ -0,0 +1,248 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FIRCrashlyticsReport.h" +#import "FIRExceptionModel.h" + +#if __has_include() +#warning "FirebaseCrashlytics and Crashlytics are not compatible \ +in the same app because including multiple crash reporters can \ +cause problems when registering exception handlers." +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase Crashlytics API provides methods to annotate and manage fatal and + * non-fatal reports captured and reported to Firebase Crashlytics. + * + * By default, Firebase Crashlytics is initialized with `FirebaseApp.configure()`. + * + * Note: The Crashlytics class cannot be subclassed. If this makes testing difficult, + * we suggest using a wrapper class or a protocol extension. + */ +NS_SWIFT_NAME(Crashlytics) +@interface FIRCrashlytics : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Accesses the singleton Crashlytics instance. + * + * @return The singleton Crashlytics instance. + */ ++ (instancetype)crashlytics NS_SWIFT_NAME(crashlytics()); + +/** + * Adds logging that is sent with your crash data. The logging does not appear in app + * logs and is only visible in the Crashlytics dashboard. + * + * @param msg Message to log + */ +- (void)log:(NSString *)msg; + +/** + * Adds logging that is sent with your crash data. The logging does not appear in app + * logs and is only visible in the Crashlytics dashboard. + * + * @param format Format of string + * @param ... A comma-separated list of arguments to substitute into format + */ +- (void)logWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +/** + * Adds logging that is sent with your crash data. The logging does not appear in app + * logs and is only visible in the Crashlytics dashboard. + * + * @param format Format of string + * @param args Arguments to substitute into format + */ +- (void)logWithFormat:(NSString *)format + arguments:(va_list)args + __attribute__((__swift_name__("log(format:arguments:)"))); // Avoid `NS_SWIFT_NAME` (#9331). + +/** + * Sets a custom key and value to be associated with subsequent fatal and non-fatal reports. + * When setting an object value, the object is converted to a string. This is + * typically done by using the object's `description`. + * + * @param value The value to be associated with the key + * @param key A unique key + */ +- (void)setCustomValue:(nullable id)value forKey:(NSString *)key; + +/** + * Sets custom keys and values to be associated with subsequent fatal and non-fatal reports. + * The objects in the dictionary are converted to strings. This is + * typically done by using the object's `description`. + * + * @param keysAndValues The values to be associated with the corresponding keys + */ +- (void)setCustomKeysAndValues:(NSDictionary *)keysAndValues; + +/** + * Records a user ID (identifier) that's associated with subsequent fatal and non-fatal reports. + * + * If you want to associate a crash with a specific user, we recommend specifying an arbitrary + * string (e.g., a database, ID, hash, or other value that you can index and query, but is + * meaningless to a third-party observer). This allows you to facilitate responses for support + * requests and reach out to users for more information. + * + * @param userID An arbitrary user identifier string that associates a user to a record in your + * system. + */ +- (void)setUserID:(nullable NSString *)userID; + +/** + * Records a non-fatal event described by an Error object. The events are + * grouped and displayed similarly to crashes. Keep in mind that this method can be expensive. + * The total number of Errors that can be recorded during your app's life-cycle is limited by a + * fixed-size circular buffer. If the buffer is overrun, the oldest data is dropped. Errors are + * relayed to Crashlytics on a subsequent launch of your application. + * + * @param error Non-fatal error to be recorded + */ +- (void)recordError:(NSError *)error NS_SWIFT_NAME(record(error:)); + +/** + * Records a non-fatal event described by an NSError object. The events are + * grouped and displayed similarly to crashes. Keep in mind that this method can be expensive. + * The total number of NSErrors that can be recorded during your app's life-cycle is limited by a + * fixed-size circular buffer. If the buffer is overrun, the oldest data is dropped. Errors are + * relayed to Crashlytics on a subsequent launch of your application. + * + * @param error Non-fatal error to be recorded + * @param userInfo Additional keys and values to send with the logged error. These parameters are + * added to Crashlytics global list of keys and values that live with the session. + */ +- (void)recordError:(NSError *)error + userInfo:(nullable NSDictionary *)userInfo + NS_SWIFT_NAME(record(error:userInfo:)); + +/** + * Records an Exception Model described by an ExceptionModel object. The events are + * grouped and displayed similarly to crashes. Keep in mind that this method can be expensive. + * The total number of ExceptionModels that can be recorded during your app's life-cycle is + * limited by a fixed-size circular buffer. If the buffer is overrun, the oldest data is dropped. + * ExceptionModels are relayed to Crashlytics on a subsequent launch of your application. + * + * @param exceptionModel Instance of the ExceptionModel to be recorded + */ +- (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel + NS_SWIFT_NAME(record(exceptionModel:)); + +/** + * Returns whether the app crashed during the previous execution. + */ +- (BOOL)didCrashDuringPreviousExecution; + +/** + * Enables/disables automatic data collection. + * + * Calling this method overrides both the FirebaseCrashlyticsCollectionEnabled flag in your + * App's Info.plist and FirebaseApp's isDataCollectionDefaultEnabled flag. + * + * When you set a value for this method, it persists across runs of the app. + * + * The value does not apply until the next run of the app. If you want to disable data + * collection without rebooting, add the FirebaseCrashlyticsCollectionEnabled flag to your app's + * Info.plist. + * * + * @param enabled Determines whether automatic data collection is enabled + */ +- (void)setCrashlyticsCollectionEnabled:(BOOL)enabled; + +/** + * Indicates whether or not automatic data collection is enabled + * + * This method uses three ways to decide whether automatic data collection is enabled, + * in order of priority: + * - If setCrashlyticsCollectionEnabled is called with a value, use it + * - If the FirebaseCrashlyticsCollectionEnabled key is in your app's Info.plist, use it + * - Otherwise, use the default isDataCollectionDefaultEnabled in FirebaseApp + */ +- (BOOL)isCrashlyticsCollectionEnabled; + +/** + * Determines whether there are any unsent crash reports cached on the device, then calls the given + * callback. + * + * The callback only executes if automatic data collection is disabled. You can use + * the callback to get one-time consent from a user upon a crash, and then call + * sendUnsentReports or deleteUnsentReports, depending on whether or not the user gives consent. + * + * Disable automatic collection by: + * - Adding the `FirebaseCrashlyticsCollectionEnabled` key with the value set to NO to your app's + * Info.plist + * - Calling `FirebaseCrashlytics.crashlytics().setCrashlyticsCollectionEnabled(false)` in your app + * - Setting `FirebaseApp`'s `isDataCollectionDefaultEnabled` to false + * + * @param completion The callback that's executed once Crashlytics finishes checking for unsent + * reports. The callback is set to true if there are unsent reports on disk. + */ +- (void)checkForUnsentReportsWithCompletion:(void (^)(BOOL))completion + NS_SWIFT_NAME(checkForUnsentReports(completion:)); + +/** + * Determines whether there are any unsent crash reports cached on the device, then calls the given + * callback with a CrashlyticsReport object that you can use to update the unsent report. + * CrashlyticsReports have a lot of the familiar Crashlytics methods like setting custom keys and + * logs. + * + * The callback only executes if automatic data collection is disabled. You can use + * the callback to get one-time consent from a user upon a crash, and then call + * sendUnsentReports or deleteUnsentReports, depending on whether or not the user gives consent. + * + * Disable automatic collection by: + * - Adding the `FirebaseCrashlyticsCollectionEnabled` key with the value set to NO to your app's + * Info.plist + * - Calling `FirebaseCrashlytics.crashlytics().setCrashlyticsCollectionEnabled(false)` in your app + * - Setting `FirebaseApp`'s `isDataCollectionDefaultEnabled` to false + * + * Not calling `sendUnsentReports()`/`deleteUnsentReports()` will result in the report staying on + * disk, which means the same CrashlyticsReport can show up in multiple runs of the app. If you + * want avoid duplicates, ensure there was a crash on the last run of the app by checking the value + * of `didCrashDuringPreviousExecution`. + * + * @param completion The callback that's executed once Crashlytics finishes checking for unsent + * reports. The callback is called with the newest unsent Crashlytics Report, or nil if there are + * none cached on disk. + */ +- (void)checkAndUpdateUnsentReportsWithCompletion: + (void (^)(FIRCrashlyticsReport *_Nullable))completion + NS_SWIFT_NAME(checkAndUpdateUnsentReports(completion:)); + +/** + * Enqueues any unsent reports on the device to upload to Crashlytics. + * + * This method only applies if automatic data collection is disabled. + * + * When automatic data collection is enabled, Crashlytics automatically uploads and deletes reports + * at startup, so this method is ignored. + */ +- (void)sendUnsentReports; + +/** + * Deletes any unsent reports on the device. + * + * This method only applies if automatic data collection is disabled. + */ +- (void)deleteUnsentReports; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h new file mode 100644 index 0000000..56c4476 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRCrashlyticsReport.h @@ -0,0 +1,109 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase Crashlytics Report provides a way to read and write information + * to a past Crashlytics reports. A common use case is gathering end-user feedback + * on the next run of the app. + * + * The CrashlyticsReport should be modified before calling send/deleteUnsentReports. + */ +NS_SWIFT_NAME(CrashlyticsReport) +@interface FIRCrashlyticsReport : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Returns the unique ID for the Crashlytics report. + */ +@property(nonatomic, readonly) NSString *reportID; + +/** + * Returns the date that the report was created. + */ +@property(nonatomic, readonly) NSDate *dateCreated; + +/** + * Returns true when one of the events in the Crashlytics report is a crash. + */ +@property(nonatomic, readonly) BOOL hasCrash; + +/** + * Adds logging that is sent with your crash data. The logging does not appear in the + * system.log and is only visible in the Crashlytics dashboard. + * + * @param msg Message to log + */ +- (void)log:(NSString *)msg; + +/** + * Adds logging that is sent with your crash data. The logging does not appear in the + * system.log and is only visible in the Crashlytics dashboard. + * + * @param format Format of string + * @param ... A comma-separated list of arguments to substitute into format + */ +- (void)logWithFormat:(NSString *)format, ... NS_FORMAT_FUNCTION(1, 2); + +/** + * Adds logging that is sent with your crash data. The logging does not appear in the + * system.log and is only visible in the Crashlytics dashboard. + * + * @param format Format of string + * @param args Arguments to substitute into format + */ +- (void)logWithFormat:(NSString *)format + arguments:(va_list)args + __attribute__((__swift_name__("log(format:arguments:)"))); // Avoid `NS_SWIFT_NAME` (#9331). + +/** + * Sets a custom key and value to be associated with subsequent fatal and non-fatal reports. + * When setting an object value, the object is converted to a string. This is + * typically done by using the object's description. + * + * @param value The value to be associated with the key + * @param key A unique key + */ +- (void)setCustomValue:(nullable id)value forKey:(NSString *)key; + +/** + * Sets custom keys and values to be associated with subsequent fatal and non-fatal reports. + * The objects in the dictionary are converted to strings. This is + * typically done by using the object's description. + * + * @param keysAndValues The values to be associated with the corresponding keys + */ +- (void)setCustomKeysAndValues:(NSDictionary *)keysAndValues; + +/** + * Records a user ID (identifier) that's associated with subsequent fatal and non-fatal reports. + * + * If you want to associate a crash with a specific user, we recommend specifying an arbitrary + * string (e.g., a database, ID, hash, or other value that you can index and query, but is + * meaningless to a third-party observer). This allows you to facilitate responses for support + * requests and reach out to users for more information. + * + * @param userID An arbitrary user identifier string that associates a user to a record in your + * system. + */ +- (void)setUserID:(nullable NSString *)userID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRExceptionModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRExceptionModel.h new file mode 100644 index 0000000..4a89ce9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRExceptionModel.h @@ -0,0 +1,57 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FIRStackFrame.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase Crashlytics ExceptionModel provides a way to report custom exceptions + * to Crashlytics that came from a runtime environment outside of the native + * platform Crashlytics is running in. + */ +NS_SWIFT_NAME(ExceptionModel) +@interface FIRExceptionModel : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Initializes an ExceptionModel with the given required fields. + * + * @param name - typically the type of the Exception class + * @param reason - the human-readable reason the issue occurred + */ +- (instancetype)initWithName:(NSString *)name reason:(NSString *)reason; + +/** + * Creates an ExceptionModel with the given required fields. + * + * @param name - typically the type of the Exception class + * @param reason - the human-readable reason the issue occurred + */ ++ (instancetype)exceptionModelWithName:(NSString *)name + reason:(NSString *)reason NS_SWIFT_UNAVAILABLE(""); + +/** + * A list of stack frames that make up the stack trace. The order of the stack trace is top-first, + * so typically the "main" function is the last element in this list. + */ +@property(nonatomic, copy) NSArray *stackTrace; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRStackFrame.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRStackFrame.h new file mode 100644 index 0000000..61418c1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FIRStackFrame.h @@ -0,0 +1,63 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase Crashlytics `StackFrame` provides a way to construct the lines of + * a stack trace for reporting along with a recorded `ExceptionModel`. + */ +NS_SWIFT_NAME(StackFrame) +@interface FIRStackFrame : NSObject + +/** :nodoc: */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Initializes a symbolicated `StackFrame` with the given required fields. Symbolicated + * `StackFrame`s will appear in the Crashlytics dashboard as reported in these fields. + * + * @param symbol - The function or method name + * @param file - the file where the exception occurred + * @param line - the line number + */ +- (instancetype)initWithSymbol:(NSString *)symbol file:(NSString *)file line:(NSInteger)line; + +/** + * Creates a symbolicated `StackFrame` from an address. The address will be + * symbolicated in the Crashlytics backend for the customer and reported in the + * Crashlytics dashboard with the appropriate file name and line number. If an + * invalid address is provided it will appear in the dashboard as missing. + * + * @param address - the address where the exception occurred + */ ++ (instancetype)stackFrameWithAddress:(NSUInteger)address; + +/** + * Creates a symbolicated `StackFrame` with the given required fields. Symbolicated + * `StackFrame`s will appear in the Crashlytics dashboard as reported in these fields. + * + * @param symbol - The function or method name + * @param file - the file where the exception occurred + * @param line - the line number + */ ++ (instancetype)stackFrameWithSymbol:(NSString *)symbol + file:(NSString *)file + line:(NSInteger)line NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FirebaseCrashlytics.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FirebaseCrashlytics.h new file mode 100644 index 0000000..280ab81 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Public/FirebaseCrashlytics/FirebaseCrashlytics.h @@ -0,0 +1,20 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRCrashlytics.h" +#import "FIRCrashlyticsReport.h" +#import "FIRExceptionModel.h" +#import "FIRStackFrame.h" diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/CrashlyticsRemoteConfigManager.swift b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/CrashlyticsRemoteConfigManager.swift new file mode 100644 index 0000000..d6d5cb1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/CrashlyticsRemoteConfigManager.swift @@ -0,0 +1,141 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FirebaseRemoteConfigInterop +import Foundation + +@objc(FIRCLSPersistenceLog) +public protocol CrashlyticsPersistenceLog { + func updateRolloutsStateToPersistence(rollouts: Data, reportID: String) + func debugLog(message: String) +} + +@objc(FIRCLSRemoteConfigManager) +public class CrashlyticsRemoteConfigManager: NSObject { + public static let maxRolloutAssignments = 128 + public static let maxParameterValueLength = 256 + + private let lock = NSLock() + private var _rolloutAssignment: [RolloutAssignment] = [] + + var remoteConfig: RemoteConfigInterop + var persistenceDelegate: CrashlyticsPersistenceLog + + @objc public var rolloutAssignment: [RolloutAssignment] { + lock.lock() + defer { lock.unlock() } + let copy = _rolloutAssignment + return copy + } + + @objc public init(remoteConfig: RemoteConfigInterop, + persistenceDelegate: CrashlyticsPersistenceLog) { + self.remoteConfig = remoteConfig + self.persistenceDelegate = persistenceDelegate + } + + @objc public func updateRolloutsState(rolloutsState: RolloutsState, reportID: String) { + lock.lock() + _rolloutAssignment = normalizeRolloutAssignment(assignments: Array(rolloutsState.assignments)) + lock.unlock() + + // Writring to persistence + if let rolloutsData = + getRolloutsStateEncodedJsonData() { + persistenceDelegate.updateRolloutsStateToPersistence( + rollouts: rolloutsData, + reportID: reportID + ) + } + } + + /// Return string format: [{RolloutAssignment1}, {RolloutAssignment2}, {RolloutAssignment3}...] + /// This will get inserted into each clsrcord for non-fatal events. + /// Return a string type because later `FIRCLSFileWriteStringUnquoted` takes string as input + @objc public func getRolloutAssignmentsEncodedJsonString() -> String? { + let encodeData = getRolloutAssignmentsEncodedJsonData() + if let data = encodeData { + return String(data: data, encoding: .utf8) + } + + let debugInfo = encodeData?.debugDescription ?? "nil" + persistenceDelegate.debugLog(message: String( + format: "Failed to serialize rollouts: %@", + arguments: [debugInfo] + )) + + return nil + } +} + +private extension CrashlyticsRemoteConfigManager { + func normalizeRolloutAssignment(assignments: [RolloutAssignment]) -> [RolloutAssignment] { + var validatedAssignments = assignments + if assignments.count > CrashlyticsRemoteConfigManager.maxRolloutAssignments { + persistenceDelegate + .debugLog( + message: "Rollouts excess the maximum number of assignments can pass to Crashlytics" + ) + validatedAssignments = + Array(assignments[.. CrashlyticsRemoteConfigManager.maxParameterValueLength { + debugPrint( + "Rollouts excess the maximum length of parameter value can pass to Crashlytics", + assignment.parameterValue + ) + let upperBound = String.Index( + utf16Offset: CrashlyticsRemoteConfigManager.maxParameterValueLength, + in: assignment.parameterValue + ) + let slicedParameterValue = assignment.parameterValue[.. Data? { + let contentEncodedRolloutAssignments = rolloutAssignment.map { assignment in + EncodedRolloutAssignment(assignment: assignment) + } + + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + encoder.outputFormatting = .sortedKeys + let encodeData = try? encoder.encode(contentEncodedRolloutAssignments) + return encodeData + } + + /// Return string format: {"rollouts": [{RolloutAssignment1}, {RolloutAssignment2}, + /// {RolloutAssignment3}...]} + /// This will get stored in the separate rollouts.clsrecord + /// Return a data type because later `[NSFileHandler writeData:]` takes data as input + func getRolloutsStateEncodedJsonData() -> Data? { + let contentEncodedRolloutAssignments = rolloutAssignment.map { assignment in + EncodedRolloutAssignment(assignment: assignment) + } + + let state = EncodedRolloutsState(assignments: contentEncodedRolloutAssignments) + let encoder = JSONEncoder() + encoder.keyEncodingStrategy = .convertToSnakeCase + let encodeData = try? encoder.encode(state) + return encodeData + } +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/EncodedRolloutAssignment.swift b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/EncodedRolloutAssignment.swift new file mode 100644 index 0000000..725b630 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/EncodedRolloutAssignment.swift @@ -0,0 +1,44 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FirebaseRemoteConfigInterop +import Foundation + +@objc(FIRCLSEncodedRolloutsState) +class EncodedRolloutsState: NSObject, Codable { + @objc public private(set) var rollouts: [EncodedRolloutAssignment] + + @objc public init(assignments: [EncodedRolloutAssignment]) { + rollouts = assignments + super.init() + } +} + +@objc(FIRCLSEncodedRolloutAssignment) +class EncodedRolloutAssignment: NSObject, Codable { + @objc public private(set) var rolloutId: String + @objc public private(set) var variantId: String + @objc public private(set) var templateVersion: Int64 + @objc public private(set) var parameterKey: String + @objc public private(set) var parameterValue: String + + public init(assignment: RolloutAssignment) { + rolloutId = FileUtility.stringToHexConverter(for: assignment.rolloutId) + variantId = FileUtility.stringToHexConverter(for: assignment.variantId) + templateVersion = assignment.templateVersion + parameterKey = FileUtility.stringToHexConverter(for: assignment.parameterKey) + parameterValue = FileUtility.stringToHexConverter(for: assignment.parameterValue) + super.init() + } +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/StringToHexConverter.swift b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/StringToHexConverter.swift new file mode 100644 index 0000000..9d4365d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Rollouts/StringToHexConverter.swift @@ -0,0 +1,38 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +// This is a swift rewrite for the logic in FIRCLSFile for the function FIRCLSFileHexEncodeString() +@objc(FIRCLSwiftFileUtility) +public class FileUtility: NSObject { + @objc public static func stringToHexConverter(for string: String) -> String { + let hexMap = "0123456789abcdef" + + var processedString = "" + let utf8Array = string.utf8.map { UInt8($0) } + for c in utf8Array { + let index1 = String.Index( + utf16Offset: Int(c >> 4), + in: hexMap + ) + let index2 = String.Index( + utf16Offset: Int(c & 0x0F), + in: hexMap + ) + processedString = processedString + String(hexMap[index1]) + String(hexMap[index2]) + } + return processedString + } +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h new file mode 100644 index 0000000..8a44c8f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h @@ -0,0 +1,57 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +@class FIRCLSApplicationIdentifierModel; +@class FIRCLSDataCollectionToken; +@class FIRCLSFileManager; +@class FIRCLSInstallIdentifierModel; +@class FIRCLSSettings; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Use this class to retrieve remote settings for the application from crashlytics backend. + */ +@interface FIRCLSSettingsManager : NSObject + +/** + * Designated Initializer. + */ +- (instancetype)initWithAppIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + settings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager + googleAppID:(NSString *)googleAppID NS_DESIGNATED_INITIALIZER; +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/** + * This method kicks off downloading settings for the app. + * @param googleAppID (required) GMP id for the app. + * @param token (required) Data collection token signifying we can make network calls + */ +- (void)beginSettingsWithGoogleAppId:(NSString *)googleAppID + token:(FIRCLSDataCollectionToken *)token; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.m new file mode 100644 index 0000000..3655442 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.m @@ -0,0 +1,157 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Settings/FIRCLSSettingsManager.h" + +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h" +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" +#import "Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h" +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h" + +@interface FIRCLSSettingsManager () + +@property(nonatomic, strong) FIRCLSApplicationIdentifierModel *appIDModel; +@property(nonatomic, strong) FIRCLSInstallIdentifierModel *installIDModel; + +@property(nonatomic, strong) FIRCLSSettings *settings; + +@property(nonatomic, strong) FIRCLSFileManager *fileManager; + +@property(nonatomic) NSDictionary *configuration; +@property(nonatomic) NSDictionary *defaultConfiguration; +@property(nonatomic, copy) NSString *googleAppID; +@property(nonatomic, copy) NSDictionary *kitVersionsByKitBundleIdentifier; +@property(nonatomic, readonly) FIRCLSFABNetworkClient *networkClient; + +@end + +@implementation FIRCLSSettingsManager + +- (instancetype)initWithAppIDModel:(FIRCLSApplicationIdentifierModel *)appIDModel + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + settings:(FIRCLSSettings *)settings + fileManager:(FIRCLSFileManager *)fileManager + googleAppID:(NSString *)googleAppID { + self = [super init]; + if (!self) { + return nil; + } + + _appIDModel = appIDModel; + _installIDModel = installIDModel; + _settings = settings; + _fileManager = fileManager; + _googleAppID = googleAppID; + + _networkClient = [[FIRCLSFABNetworkClient alloc] initWithQueue:nil]; + + return self; +} + +- (void)beginSettingsWithGoogleAppId:(NSString *)googleAppID + token:(FIRCLSDataCollectionToken *)token { + NSParameterAssert(googleAppID); + + self.googleAppID = googleAppID; + + // This map helps us determine what versions of the SDK + // are out there. We're keeping the Fabric value in there for + // backwards compatibility + // TODO(b/141747635) + self.kitVersionsByKitBundleIdentifier = @{ + FIRCLSApplicationGetSDKBundleID() : FIRCLSSDKVersion(), + }; + + [self beginSettingsDownload:token]; +} + +#pragma mark Helper methods + +/** + * Makes a settings download request. If the request fails, the error is handled silently (with a + * log statement). + */ +- (void)beginSettingsDownload:(FIRCLSDataCollectionToken *)token { + FIRCLSDownloadAndSaveSettingsOperation *operation = nil; + operation = [[FIRCLSDownloadAndSaveSettingsOperation alloc] + initWithGoogleAppID:self.googleAppID + delegate:self + settingsURL:self.settingsURL + settingsDirectoryPath:self.fileManager.settingsDirectoryPath + settingsFilePath:self.fileManager.settingsFilePath + installIDModel:self.installIDModel + networkClient:self.networkClient + token:token]; + + [operation startWithToken:token]; +} + +- (void)finishNetworkingSession { + [self.networkClient invalidateAndCancel]; +} + +#pragma mark FIRCLSDownloadAndSaveSettingsOperationDelegate methods + +- (void)operation:(FIRCLSDownloadAndSaveSettingsOperation *)operation + didDownloadAndSaveSettingsWithError:(nullable NSError *)error { + if (error) { + NSString *message = @"Failed to download settings."; + if (error.userInfo && [error.userInfo objectForKey:@"status_code"] && + [[error.userInfo objectForKey:@"status_code"] + isEqualToNumber:[NSNumber numberWithInt:404]]) { + NSString *debugHint = @"If this is your first time launching the app, make sure you have " + @"enabled Crashlytics in the Firebase Console."; + message = [NSString stringWithFormat:@"%@ %@", message, debugHint]; + } + FIRCLSErrorLog(@"%@ %@", message, error); + [self finishNetworkingSession]; + return; + } + + FIRCLSDebugLog(@"Settings downloaded successfully"); + + NSTimeInterval currentTimestamp = [NSDate timeIntervalSinceReferenceDate]; + [self.settings cacheSettingsWithGoogleAppID:self.googleAppID currentTimestamp:currentTimestamp]; + + // we're all set! + [self finishNetworkingSession]; +} + +- (NSURL *)settingsURL { + // GET + // /spi/v2/platforms/:platform/apps/:identifier/settings?build_version=1234&display_version=abc&instance=xyz&source=1 + FIRCLSURLBuilder *url = [FIRCLSURLBuilder URLWithBase:FIRCLSSettingsEndpoint]; + + [url appendComponent:@"/spi/v2/platforms/"]; + [url escapeAndAppendComponent:self.appIDModel.platform]; + [url appendComponent:@"/gmp/"]; + [url escapeAndAppendComponent:self.googleAppID]; + [url appendComponent:@"/settings"]; + + [url appendValue:self.appIDModel.buildVersion forQueryParam:@"build_version"]; + [url appendValue:self.appIDModel.displayVersion forQueryParam:@"display_version"]; + [url appendValue:self.appIDModel.buildInstanceID forQueryParam:@"instance"]; + [url appendValue:@(self.appIDModel.installSource) forQueryParam:@"source"]; + // TODO: find the right param name for KitVersions and add them here + return url.URL; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h new file mode 100644 index 0000000..7b40ec7 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h @@ -0,0 +1,71 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * This class is a model for identifiers related to the application binary. + * It is thread-safe. + */ +@interface FIRCLSApplicationIdentifierModel : NSObject + +@property(nonatomic, readonly, nullable) NSString* bundleID; + +/** + * Returns the user-facing app name + */ +@property(nonatomic, readonly, nullable) NSString* displayName; + +@property(nonatomic, readonly, nullable) NSString* platform; +@property(nonatomic, readonly, nullable) NSString* buildVersion; +@property(nonatomic, readonly, nullable) NSString* displayVersion; + +/** + * Returns the synthesized app version, similar to how the backend does it + * () + */ +@property(nonatomic, readonly, nullable) NSString* synthesizedVersion; + +@property(nonatomic, readonly) FIRCLSApplicationInstallationSourceType installSource; + +/** + * A mapping between all supported architectures and their UUIDs + */ +@property(nonatomic, readonly) NSDictionary* architectureUUIDMap; + +/** + * Returns the linked OS SDK + */ +@property(nonatomic, readonly) NSString* builtSDKString; + +/** + * Returns the min supported OS + */ +@property(nonatomic, readonly) NSString* minimumSDKString; + +/** + * The unique identifier for this instance of the version of app running Crashlytics. This is + * computed by hashing the app itself. + * + * On Android, this is called the Build ID + */ +@property(nonatomic, readonly) NSString* buildInstanceID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.m new file mode 100644 index 0000000..975cf2b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.m @@ -0,0 +1,138 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#import "Crashlytics/Shared/FIRCLSByteUtility.h" +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" +#import "Crashlytics/Shared/FIRCLSUUID.h" + +@interface FIRCLSApplicationIdentifierModel () + +@property(nonatomic, copy, readwrite) NSDictionary *architectureUUIDMap; +@property(nonatomic, copy, readwrite) NSString *buildInstanceID; +@property(nonatomic, readonly) FIRCLSMachOVersion builtSDK; +@property(nonatomic, readonly) FIRCLSMachOVersion minimumSDK; + +@end + +@implementation FIRCLSApplicationIdentifierModel + +- (nullable instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + if (![self computeExecutableInfo]) { + return nil; + } + + [self computeInstanceIdentifier]; + + return self; +} + +- (NSString *)bundleID { + return FIRCLSApplicationGetBundleIdentifier(); +} + +- (NSString *)displayName { + return FIRCLSApplicationGetName(); +} + +- (NSString *)platform { + return FIRCLSApplicationGetPlatform(); +} + +- (NSString *)buildVersion { + return FIRCLSApplicationGetBundleVersion(); +} + +- (NSString *)displayVersion { + return FIRCLSApplicationGetShortBundleVersion(); +} + +- (NSString *)synthesizedVersion { + return [NSString stringWithFormat:@"%@ (%@)", self.displayVersion, self.buildVersion]; +} + +- (FIRCLSApplicationInstallationSourceType)installSource { + return FIRCLSApplicationInstallationSource(); +} + +- (NSString *)builtSDKString { + return FIRCLSMachOFormatVersion(&_builtSDK); +} + +- (NSString *)minimumSDKString { + return FIRCLSMachOFormatVersion(&_minimumSDK); +} + +- (BOOL)computeExecutableInfo { + struct FIRCLSMachOFile file; + + if (!FIRCLSMachOFileInitWithCurrent(&file)) { + return NO; + } + + NSMutableDictionary *executables = [NSMutableDictionary dictionary]; + + FIRCLSMachOFileEnumerateSlices(&file, ^(FIRCLSMachOSliceRef fileSlice) { + NSString *arch; + + arch = [NSString stringWithUTF8String:FIRCLSMachOSliceGetArchitectureName(fileSlice)]; + + FIRCLSMachOSliceEnumerateLoadCommands( + fileSlice, ^(uint32_t type, uint32_t size, const struct load_command *cmd) { + if (type == LC_UUID) { + const uint8_t *uuid; + + uuid = FIRCLSMachOGetUUID(cmd); + + [executables setObject:FIRCLSUUIDToNSString(uuid) forKey:arch]; + } else if (type == LC_VERSION_MIN_MACOSX || type == LC_VERSION_MIN_IPHONEOS) { + self->_minimumSDK = FIRCLSMachOGetMinimumOSVersion(cmd); + self->_builtSDK = FIRCLSMachOGetLinkedSDKVersion(cmd); + } + }); + }); + + FIRCLSMachOFileDestroy(&file); + + _architectureUUIDMap = executables; + + return YES; +} + +- (void)computeInstanceIdentifier { + // build up the components of the instance identifier + NSMutableString *string = [NSMutableString string]; + + // first, the uuids, sorted by architecture name + for (NSString *key in + [[_architectureUUIDMap allKeys] sortedArrayUsingSelector:@selector(compare:)]) { + [string appendString:[self.architectureUUIDMap objectForKey:key]]; + } + + // TODO: the instance identifier calculation needs to match Beta's expectation. So, we have to + // continue generating a less-correct value for now. One day, we should incorporate a hash of the + // Info.plist and icon data. + + _buildInstanceID = FIRCLSHashNSData([string dataUsingEncoding:NSUTF8StringEncoding]); +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.h new file mode 100644 index 0000000..2caeedb --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.h @@ -0,0 +1,80 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.h" + +@class FIRCLSDownloadAndSaveSettingsOperation; +@class FIRCLSFABNetworkClient; +@class FIRCLSInstallIdentifierModel; + +NS_ASSUME_NONNULL_BEGIN + +/** + * This is the protocol that a delegate of FIRCLSDownloadAndSaveSettingsOperation needs to follow. + */ +@protocol FIRCLSDownloadAndSaveSettingsOperationDelegate + +@required + +/** + * Method that is called when settings have been downloaded and saved, or an error has occurred + * during the operation. This method may be called on an arbitrary background thread. + */ +- (void)operation:(FIRCLSDownloadAndSaveSettingsOperation *)operation + didDownloadAndSaveSettingsWithError:(nullable NSError *)error; + +@end + +/** + * This operation downloads settings from the backend servers, and saves them in file on disk. + */ +@interface FIRCLSDownloadAndSaveSettingsOperation : FIRCLSNetworkOperation + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + token:(FIRCLSDataCollectionToken *)token NS_UNAVAILABLE; + +/** + * @param googleAppID must NOT be nil + * @param delegate gets a callback after settings have been downloaded or an error occurs. + * @param settingsURL must NOT be nil. This is the URL to which a download request is made. + * @param settingsDirectoryPath must NOT be nil. This is the directory on disk where the settings + * are persisted. + * @param settingsFilePath must NOT be nil. It is the full file path (including file name) in which + * settings will be persisted on disk. + * @param installIDModel must NOT be nil. This value is sent back to the backend to uniquely + * identify the app install. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + delegate:(id)delegate + settingsURL:(NSURL *)settingsURL + settingsDirectoryPath:(NSString *)settingsDirectoryPath + settingsFilePath:(NSString *)settingsFilePath + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + networkClient:(FIRCLSFABNetworkClient *)networkClient + token:(FIRCLSDataCollectionToken *)token NS_DESIGNATED_INITIALIZER; + +/** + * Delegate of this operation. + */ +@property(nonatomic, readonly, weak) id delegate; + +/** + * When an error occurs during this operation, it is made available in this property. + */ +@property(nonatomic, readonly) NSError *error; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.m new file mode 100644 index 0000000..3eb6b03 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.m @@ -0,0 +1,132 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Settings/Operations/FIRCLSDownloadAndSaveSettingsOperation.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Crashlytics/Models/FIRCLSInstallIdentifierModel.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "Crashlytics/Shared/FIRCLSFABHost.h" +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h" + +@interface FIRCLSDownloadAndSaveSettingsOperation () + +/** + * Method called to fetch the URL from where settings have to be downloaded. + */ +@property(readonly, nonatomic) NSURL *settingsURL; +/** + * File manager which will be used to save settings on disk. + */ +@property(readonly, nonatomic) NSFileManager *fileManager; + +/** + * Directory path on which settings file will be saved + */ +@property(readonly, nonatomic) NSString *settingsDirectoryPath; +/** + * Complete file path on which settings file will be saved + */ +@property(readonly, nonatomic) NSString *settingsFilePath; +/** + * App install identifier. + */ +@property(strong, readonly, nonatomic) FIRCLSInstallIdentifierModel *installIDModel; + +@property(weak, readonly, nonatomic) FIRCLSFABNetworkClient *networkClient; + +@end + +@implementation FIRCLSDownloadAndSaveSettingsOperation + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + delegate:(id)delegate + settingsURL:(NSURL *)settingsURL + settingsDirectoryPath:(NSString *)settingsDirectoryPath + settingsFilePath:(NSString *)settingsFilePath + installIDModel:(FIRCLSInstallIdentifierModel *)installIDModel + networkClient:(FIRCLSFABNetworkClient *)networkClient + token:(FIRCLSDataCollectionToken *)token { + NSParameterAssert(settingsURL); + NSParameterAssert(settingsDirectoryPath); + NSParameterAssert(settingsFilePath); + NSParameterAssert(installIDModel); + + self = [super initWithGoogleAppID:googleAppID token:token]; + if (self) { + _delegate = delegate; + _settingsURL = settingsURL.copy; + _settingsDirectoryPath = settingsDirectoryPath.copy; + _settingsFilePath = settingsFilePath.copy; + _fileManager = [[NSFileManager alloc] init]; + _installIDModel = installIDModel; + _networkClient = networkClient; + } + return self; +} + +- (NSMutableURLRequest *)mutableRequestWithDefaultHTTPHeaderFieldsAndTimeoutForURL:(NSURL *)url { + NSMutableURLRequest *request = + [super mutableRequestWithDefaultHTTPHeaderFieldsAndTimeoutForURL:url]; + request.HTTPMethod = @"GET"; + [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; + [request setValue:self.installIDModel.installID + forHTTPHeaderField:@"X-Crashlytics-Installation-ID"]; + [request setValue:FIRCLSHostModelInfo() forHTTPHeaderField:@"X-Crashlytics-Device-Model"]; + [request setValue:FIRCLSHostOSBuildVersion() + forHTTPHeaderField:@"X-Crashlytics-OS-Build-Version"]; + [request setValue:FIRCLSHostOSDisplayVersion() + forHTTPHeaderField:@"X-Crashlytics-OS-Display-Version"]; + [request setValue:FIRCLSSDKVersion() forHTTPHeaderField:@"X-Crashlytics-API-Client-Version"]; + + return request; +} + +- (void)main { + NSMutableURLRequest *request = + [self mutableRequestWithDefaultHTTPHeaderFieldsAndTimeoutForURL:self.settingsURL]; + + [self.networkClient + startDownloadTaskWithRequest:request + retryLimit:1 + completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { + if (error) { + self->_error = error; + [self.delegate operation:self didDownloadAndSaveSettingsWithError:self.error]; + [self finishWithError:error]; + return; + } + // This move needs to happen synchronously, because after this method completes, + // the file will not be available. + NSError *moveError = nil; + + // this removal will frequently fail, and we don't want the warning + [self.fileManager removeItemAtPath:self.settingsDirectoryPath error:nil]; + + [self.fileManager createDirectoryAtPath:self.settingsDirectoryPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + if (![self.fileManager moveItemAtPath:location.path + toPath:self.settingsFilePath + error:&moveError]) { + FIRCLSErrorLog(@"Unable to complete settings download %@", moveError); + self->_error = moveError; + } + [self.delegate operation:self didDownloadAndSaveSettingsWithError:self.error]; + [self finishWithError:self.error]; + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.h new file mode 100644 index 0000000..405f6ed --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.h @@ -0,0 +1,55 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FIRCLSDataCollectionToken; +@class FIRCLSSettings; + +/** + * This is a base class for network based operations. + */ +@interface FIRCLSNetworkOperation : FIRCLSFABAsyncOperation + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/** + * Designated initializer. All parameters are mandatory and must not be nil. + */ +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + token:(FIRCLSDataCollectionToken *)token NS_DESIGNATED_INITIALIZER; + +- (void)start NS_UNAVAILABLE; +- (void)startWithToken:(FIRCLSDataCollectionToken *)token; + +/** + * Creates a mutable request for posting to Crashlytics backend with a default timeout. + */ +- (NSMutableURLRequest *)mutableRequestWithDefaultHTTPHeaderFieldsAndTimeoutForURL:(NSURL *)url; + +/** + * Creates a mutable request for posting to Crashlytics backend with given timeout. + */ +- (NSMutableURLRequest *)mutableRequestWithDefaultHTTPHeadersForURL:(NSURL *)url + timeout:(NSTimeInterval)timeout; + +@property(nonatomic, strong, readonly) FIRCLSDataCollectionToken *token; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.m new file mode 100644 index 0000000..2129120 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.m @@ -0,0 +1,93 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Crashlytics/Settings/Operations/FIRCLSNetworkOperation.h" + +#import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h" +#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" +#import "Crashlytics/Shared/FIRCLSConstants.h" + +@interface FIRCLSNetworkOperation () + +@property(nonatomic, strong, readonly) NSString *googleAppID; + +@end + +@implementation FIRCLSNetworkOperation + +- (instancetype)initWithGoogleAppID:(NSString *)googleAppID + token:(FIRCLSDataCollectionToken *)token { + NSParameterAssert(googleAppID); + if (!googleAppID) { + return nil; + } + + self = [super init]; + if (self) { + _googleAppID = googleAppID; + _token = token; + } + return self; +} + +- (void)startWithToken:(FIRCLSDataCollectionToken *)token { + // Settings is considered data collection, so we must only + // call this with a valid token + if (![token isValid]) { + FIRCLSErrorLog(@"Skipping network operation with invalid data collection token"); + return; + } + + [super start]; +} + +- (NSMutableURLRequest *)mutableRequestWithDefaultHTTPHeaderFieldsAndTimeoutForURL:(NSURL *)url { + return [self mutableRequestWithDefaultHTTPHeadersForURL:url timeout:10.0]; +} + +- (NSMutableURLRequest *)mutableRequestWithDefaultHTTPHeadersForURL:(NSURL *)url + timeout:(NSTimeInterval)timeout { + NSMutableURLRequest *request = + [NSMutableURLRequest requestWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeout]; + + NSString *localeId = self.localeIdentifier; + + [request setValue:self.userAgentString forHTTPHeaderField:FIRCLSNetworkUserAgent]; + [request setValue:FIRCLSNetworkUTF8 forHTTPHeaderField:FIRCLSNetworkAcceptCharset]; + [request setValue:localeId forHTTPHeaderField:FIRCLSNetworkAcceptLanguage]; + [request setValue:localeId forHTTPHeaderField:FIRCLSNetworkContentLanguage]; + [request setValue:FIRCLSDeveloperToken forHTTPHeaderField:FIRCLSNetworkCrashlyticsDeveloperToken]; + [request setValue:FIRCLSApplicationGetSDKBundleID() + forHTTPHeaderField:FIRCLSNetworkCrashlyticsAPIClientId]; + [request setValue:FIRCLSSDKVersion() + forHTTPHeaderField:FIRCLSNetworkCrashlyticsAPIClientDisplayVersion]; + [request setValue:self.googleAppID forHTTPHeaderField:FIRCLSNetworkCrashlyticsGoogleAppId]; + + return request; +} + +- (NSString *)userAgentString { + return + [NSString stringWithFormat:@"%@/%@", FIRCLSApplicationGetSDKBundleID(), FIRCLSSDKVersion()]; +} + +- (NSString *)localeIdentifier { + return NSLocale.currentLocale.localeIdentifier; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.c new file mode 100644 index 0000000..4512aba --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.c @@ -0,0 +1,404 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include + +#if CLS_COMPACT_UNWINDING_SUPPORTED + +#pragma mark Parsing +bool FIRCLSCompactUnwindInit(FIRCLSCompactUnwindContext* context, + const void* unwindInfo, + const void* ehFrame, + uintptr_t loadAddress) { + if (!FIRCLSIsValidPointer(context)) { + FIRCLSSDKLog("Error: invalid context passed to compact unwind init"); + return false; + } + if (!FIRCLSIsValidPointer(unwindInfo)) { + FIRCLSSDKLog("Error: invalid unwind info passed to compact unwind init"); + return false; + } + if (!FIRCLSIsValidPointer(loadAddress)) { + FIRCLSSDKLog("Error: invalid load address passed to compact unwind init"); + return false; + } + + memset(context, 0, sizeof(FIRCLSCompactUnwindContext)); + + if (!FIRCLSReadMemory((vm_address_t)unwindInfo, &context->unwindHeader, + sizeof(struct unwind_info_section_header))) { + FIRCLSSDKLog("Error: could not read memory contents of unwindInfo\n"); + return false; + } + + if (context->unwindHeader.version != UNWIND_SECTION_VERSION) { + FIRCLSSDKLog("Error: bad unwind_info structure version (%d != %d)\n", + context->unwindHeader.version, UNWIND_SECTION_VERSION); + return false; + } + + // copy in the values + context->unwindInfo = unwindInfo; + context->ehFrame = ehFrame; + context->loadAddress = loadAddress; + + return true; +} + +void* FIRCLSCompactUnwindGetIndexData(FIRCLSCompactUnwindContext* context) { + return (void*)((uintptr_t)context->unwindInfo + + (uintptr_t)context->unwindHeader.indexSectionOffset); +} + +compact_unwind_encoding_t* FIRCLSCompactUnwindGetCommonEncodings( + FIRCLSCompactUnwindContext* context) { + return (compact_unwind_encoding_t*)((uintptr_t)context->unwindInfo + + (uintptr_t) + context->unwindHeader.commonEncodingsArraySectionOffset); +} + +void* FIRCLSCompactUnwindGetSecondLevelData(FIRCLSCompactUnwindContext* context) { + return (void*)((uintptr_t)context->unwindInfo + + context->indexHeader.secondLevelPagesSectionOffset); +} + +uintptr_t FIRCLSCompactUnwindGetIndexFunctionOffset(FIRCLSCompactUnwindContext* context) { + return context->loadAddress + context->indexHeader.functionOffset; +} +uintptr_t FIRCLSCompactUnwindGetTargetAddress(FIRCLSCompactUnwindContext* context, uintptr_t pc) { + uintptr_t offset = FIRCLSCompactUnwindGetIndexFunctionOffset(context); + + if (pc <= offset) { + FIRCLSSDKLog("Error: PC is invalid\n"); + return 0; + } + + return pc - offset; +} + +#pragma mark - Parsing and Lookup +bool FIRCLSCompactUnwindLookupFirstLevel(FIRCLSCompactUnwindContext* context, uintptr_t address) { + if (!context) { + return false; + } + + // In practice, it appears that there always one more first level entry + // than required. This actually makes sense, since we have to use this + // info to check if we are in range. This implies there must be + // at least 2 indices at a minimum. + + uint32_t indexCount = context->unwindHeader.indexCount; + if (indexCount < 2) { + return false; + } + + // make sure our address is valid + if (address < context->loadAddress) { + return false; + } + + struct unwind_info_section_header_index_entry* indexEntries = + FIRCLSCompactUnwindGetIndexData(context); + if (!indexEntries) { + return false; + } + + address -= context->loadAddress; // search relative to zero + + // minus one because of the extra entry - see comment above + for (uint32_t index = 0; index < indexCount - 1; ++index) { + uint32_t value = indexEntries[index].functionOffset; + uint32_t nextValue = indexEntries[index + 1].functionOffset; + + if (address >= value && address < nextValue) { + context->firstLevelNextFunctionOffset = nextValue; + context->indexHeader = indexEntries[index]; + return true; + } + } + + return false; +} + +uint32_t FIRCLSCompactUnwindGetSecondLevelPageKind(FIRCLSCompactUnwindContext* context) { + if (!context) { + return 0; + } + + return *(uint32_t*)FIRCLSCompactUnwindGetSecondLevelData(context); +} + +bool FIRCLSCompactUnwindLookupSecondLevelRegular(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + FIRCLSCompactUnwindResult* result) { + FIRCLSSDKLog("Encountered a regular second-level page\n"); + return false; +} + +// this only works for compressed entries right now +bool FIRCLSCompactUnwindBinarySearchSecondLevel(uintptr_t address, + uint32_t* index, + uint16_t entryCount, + uint32_t* entryArray) { + if (!index || !entryArray) { + return false; + } + + if (entryCount == 0) { + return false; + } + + if (address == 0) { + return false; + } + + uint32_t highIndex = entryCount; + *index = 0; + + while (*index < highIndex) { + uint32_t midIndex = (*index + highIndex) / 2; + + // FIRCLSSDKLog("%u %u %u\n", *index, midIndex, highIndex); + + uintptr_t value = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entryArray[midIndex]); + + if (value > address) { + if (highIndex == midIndex) { + return false; + } + + highIndex = midIndex; + continue; + } + + *index = midIndex; + + // are we at the end of the array? + if (midIndex == entryCount - 1) { + return false; + } + + uintptr_t nextValue = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entryArray[midIndex + 1]); + if (nextValue > address) { + // we've found it + break; + } + + *index += 1; + } + + // check to make sure we're still within bounds + return *index < entryCount; +} + +bool FIRCLSCompactUnwindLookupSecondLevelCompressed(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + FIRCLSCompactUnwindResult* result) { + if (!context || !result) { + return false; + } + + void* ptr = FIRCLSCompactUnwindGetSecondLevelData(context); + + if (!ptr) { + return false; + } + + memset(result, 0, sizeof(FIRCLSCompactUnwindResult)); + + struct unwind_info_compressed_second_level_page_header* header = + (struct unwind_info_compressed_second_level_page_header*)ptr; + + // adjust address + uintptr_t targetAddress = FIRCLSCompactUnwindGetTargetAddress(context, pc); + + uint32_t* entryArray = ptr + header->entryPageOffset; + + uint32_t index = 0; + + if (!FIRCLSCompactUnwindBinarySearchSecondLevel(targetAddress, &index, header->entryCount, + entryArray)) { + FIRCLSSDKLogInfo("Unable to find PC in second level\n"); + return false; + } + + uint32_t entry = entryArray[index]; + + // Computing the function start address is easy + result->functionStart = UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entry) + + FIRCLSCompactUnwindGetIndexFunctionOffset(context); + + // Computing the end is more complex, because we could be on the last entry. In that case, we + // cannot use the next value as the end. + result->functionEnd = context->loadAddress; + if (index < header->entryCount - 1) { + result->functionEnd += UNWIND_INFO_COMPRESSED_ENTRY_FUNC_OFFSET(entryArray[index + 1]) + + context->indexHeader.functionOffset; + } else { + result->functionEnd += context->firstLevelNextFunctionOffset; + } + + // FIRCLSSDKLog("Located %lx => %lx %lx\n", pc, result->functionStart, result->functionEnd); + + if ((pc < result->functionStart) || (pc >= result->functionEnd)) { + FIRCLSSDKLog("PC does not match computed function range\n"); + return false; + } + + uint32_t encodingIndex = UNWIND_INFO_COMPRESSED_ENTRY_ENCODING_INDEX(entry); + + // encoding could be in the common array + if (encodingIndex < context->unwindHeader.commonEncodingsArrayCount) { + result->encoding = FIRCLSCompactUnwindGetCommonEncodings(context)[encodingIndex]; + + // FIRCLSSDKLog("Entry has common encoding: 0x%x\n", result->encoding); + } else { + encodingIndex = encodingIndex - context->unwindHeader.commonEncodingsArrayCount; + + compact_unwind_encoding_t* encodings = ptr + header->encodingsPageOffset; + + result->encoding = encodings[encodingIndex]; + + // FIRCLSSDKLog("Entry has compressed encoding: 0x%x\n", result->encoding); + } + + if (result->encoding == 0) { + FIRCLSSDKLogInfo("Entry has has no unwind info\n"); + return false; + } + + return true; +} + +bool FIRCLSCompactUnwindLookupSecondLevel(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + FIRCLSCompactUnwindResult* result) { + switch (FIRCLSCompactUnwindGetSecondLevelPageKind(context)) { + case UNWIND_SECOND_LEVEL_REGULAR: + FIRCLSSDKLogInfo("Found a second level regular header\n"); + if (FIRCLSCompactUnwindLookupSecondLevelRegular(context, pc, result)) { + return true; + } + break; + case UNWIND_SECOND_LEVEL_COMPRESSED: + FIRCLSSDKLogInfo("Found a second level compressed header\n"); + if (FIRCLSCompactUnwindLookupSecondLevelCompressed(context, pc, result)) { + return true; + } + break; + default: + FIRCLSSDKLogError("Unrecognized header kind - unable to continue\n"); + break; + } + + return false; +} + +bool FIRCLSCompactUnwindLookup(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + FIRCLSCompactUnwindResult* result) { + if (!context || !result) { + return false; + } + + // step 1 - find the pc in the first-level index + if (!FIRCLSCompactUnwindLookupFirstLevel(context, pc)) { + FIRCLSSDKLogWarn("Unable to find pc in first level\n"); + return false; + } + + FIRCLSSDKLogDebug("Found first level (second => %u)\n", + context->indexHeader.secondLevelPagesSectionOffset); + + // step 2 - use that info to find the second-level information + // that second actually has the encoding info we're looking for. + if (!FIRCLSCompactUnwindLookupSecondLevel(context, pc, result)) { + FIRCLSSDKLogInfo("Second-level PC lookup failed\n"); + return false; + } + + return true; +} + +#pragma mark - Unwinding +bool FIRCLSCompactUnwindLookupAndCompute(FIRCLSCompactUnwindContext* context, + FIRCLSThreadContext* registers) { + if (!context || !registers) { + return false; + } + + uintptr_t pc = FIRCLSThreadContextGetPC(registers); + + // little sanity check + if (pc < context->loadAddress) { + return false; + } + + FIRCLSCompactUnwindResult result; + + memset(&result, 0, sizeof(result)); + + if (!FIRCLSCompactUnwindLookup(context, pc, &result)) { + FIRCLSSDKLogInfo("Unable to lookup compact unwind for pc %p\n", (void*)pc); + return false; + } + + // Ok, armed with the encoding, we can actually attempt to modify the registers. Because + // the encoding is arch-specific, this function has to be defined per-arch. + if (!FIRCLSCompactUnwindComputeRegisters(context, &result, registers)) { + FIRCLSSDKLogError("Failed to compute registers\n"); + return false; + } + + return true; +} + +#if CLS_DWARF_UNWINDING_SUPPORTED +bool FIRCLSCompactUnwindDwarfFrame(FIRCLSCompactUnwindContext* context, + uintptr_t dwarfOffset, + FIRCLSThreadContext* registers) { + if (!context || !registers) { + return false; + } + + // Everyone's favorite! Dwarf unwinding! + FIRCLSSDKLogInfo("Trying to read dwarf data with offset %lx\n", dwarfOffset); + + FIRCLSDwarfCFIRecord record; + + if (!FIRCLSDwarfParseCFIFromFDERecordOffset(&record, context->ehFrame, dwarfOffset)) { + FIRCLSSDKLogError("Unable to init FDE\n"); + return false; + } + + if (!FIRCLSDwarfUnwindComputeRegisters(&record, registers)) { + FIRCLSSDKLogError("Failed to compute DWARF registers\n"); + return false; + } + + return true; +} +#endif + +#else +INJECT_STRIP_SYMBOL(compact_unwind) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h new file mode 100644 index 0000000..a4698e7 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h @@ -0,0 +1,68 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" + +// We have to pack the arrays defined in this header, so +// we can reason about pointer math. +#pragma pack(push) +#pragma pack(1) +#include +#pragma pack(pop) + +// First masks out the value, and then shifts the value by the number +// of zeros in the mask. __builtin_ctz returns the number of trailing zeros. +// Its output is undefined if the input is zero. +#define GET_BITS_WITH_MASK(value, mask) ((value & mask) >> (mask == 0 ? 0 : __builtin_ctz(mask))) + +typedef struct { + const void* unwindInfo; + const void* ehFrame; + uintptr_t loadAddress; + + struct unwind_info_section_header unwindHeader; + struct unwind_info_section_header_index_entry indexHeader; + uint32_t firstLevelNextFunctionOffset; +} FIRCLSCompactUnwindContext; + +typedef struct { + compact_unwind_encoding_t encoding; + uintptr_t functionStart; + uintptr_t functionEnd; + uintptr_t lsda; + uintptr_t personality; + +} FIRCLSCompactUnwindResult; + +bool FIRCLSCompactUnwindInit(FIRCLSCompactUnwindContext* context, + const void* unwindInfo, + const void* ehFrame, + uintptr_t loadAddress); +void* FIRCLSCompactUnwindGetIndexData(FIRCLSCompactUnwindContext* context); +void* FIRCLSCompactUnwindGetSecondLevelData(FIRCLSCompactUnwindContext* context); +bool FIRCLSCompactUnwindFindFirstLevelIndex(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + uint32_t* index); + +bool FIRCLSCompactUnwindDwarfFrame(FIRCLSCompactUnwindContext* context, + uintptr_t dwarfOffset, + FIRCLSThreadContext* registers); +bool FIRCLSCompactUnwindLookupAndCompute(FIRCLSCompactUnwindContext* context, + FIRCLSThreadContext* registers); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h new file mode 100644 index 0000000..b918198 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h @@ -0,0 +1,28 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" +#pragma pack(push, 1) +#include +#pragma pack(pop) + +bool FIRCLSCompactUnwindLookup(FIRCLSCompactUnwindContext* context, + uintptr_t pc, + FIRCLSCompactUnwindResult* result); + +bool FIRCLSCompactUnwindComputeRegisters(FIRCLSCompactUnwindContext* context, + FIRCLSCompactUnwindResult* result, + FIRCLSThreadContext* registers); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c new file mode 100644 index 0000000..2bb37c1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.c @@ -0,0 +1,238 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#include "Crashlytics/third_party/libunwind/dwarf.h" + +#include + +#if CLS_DWARF_UNWINDING_SUPPORTED + +uint8_t FIRCLSParseUint8AndAdvance(const void** cursor) { + uint8_t tmp = **(uint8_t**)cursor; + + *cursor += sizeof(uint8_t); + + return tmp; +} + +uint16_t FIRCLSParseUint16AndAdvance(const void** cursor) { + uint16_t tmp = **(uint16_t**)cursor; + + *cursor += sizeof(uint16_t); + + return tmp; +} + +int16_t FIRCLSParseInt16AndAdvance(const void** cursor) { + int16_t tmp = **(int16_t**)cursor; + + *cursor += sizeof(int16_t); + + return tmp; +} + +uint32_t FIRCLSParseUint32AndAdvance(const void** cursor) { + uint32_t tmp = **(uint32_t**)cursor; + + *cursor += sizeof(uint32_t); + + return tmp; +} + +int32_t FIRCLSParseInt32AndAdvance(const void** cursor) { + int32_t tmp = **(int32_t**)cursor; + + *cursor += sizeof(int32_t); + + return tmp; +} + +uint64_t FIRCLSParseUint64AndAdvance(const void** cursor) { + uint64_t tmp = **(uint64_t**)cursor; + + *cursor += sizeof(uint64_t); + + return tmp; +} + +int64_t FIRCLSParseInt64AndAdvance(const void** cursor) { + int64_t tmp = **(int64_t**)cursor; + + *cursor += sizeof(int64_t); + + return tmp; +} + +uintptr_t FIRCLSParsePointerAndAdvance(const void** cursor) { + uintptr_t tmp = **(uintptr_t**)cursor; + + *cursor += sizeof(uintptr_t); + + return tmp; +} + +// Signed and Unsigned LEB128 decoding algorithms taken from Wikipedia - +// http://en.wikipedia.org/wiki/LEB128 +uint64_t FIRCLSParseULEB128AndAdvance(const void** cursor) { + uint64_t result = 0; + char shift = 0; + + for (int i = 0; i < sizeof(uint64_t); ++i) { + char byte; + + byte = **(uint8_t**)cursor; + + *cursor += 1; + + result |= ((0x7F & byte) << shift); + if ((0x80 & byte) == 0) { + break; + } + + shift += 7; + } + + return result; +} + +int64_t FIRCLSParseLEB128AndAdvance(const void** cursor) { + uint64_t result = 0; + char shift = 0; + char size = sizeof(int64_t) * 8; + char byte = 0; + + for (int i = 0; i < sizeof(uint64_t); ++i) { + byte = **(uint8_t**)cursor; + + *cursor += 1; + + result |= ((0x7F & byte) << shift); + shift += 7; + + /* sign bit of byte is second high order bit (0x40) */ + if ((0x80 & byte) == 0) { + break; + } + } + + if ((shift < size) && (0x40 & byte)) { + // sign extend + result |= -(1 << shift); + } + + return result; +} + +const char* FIRCLSParseStringAndAdvance(const void** cursor) { + const char* string; + + string = (const char*)(*cursor); + + // strlen doesn't include the null character, which we need to advance past + *cursor += strlen(string) + 1; + + return string; +} + +uint64_t FIRCLSParseRecordLengthAndAdvance(const void** cursor) { + uint64_t length; + + length = FIRCLSParseUint32AndAdvance(cursor); + if (length == DWARF_EXTENDED_LENGTH_FLAG) { + length = FIRCLSParseUint64AndAdvance(cursor); + } + + return length; +} + +uintptr_t FIRCLSParseAddressWithEncodingAndAdvance(const void** cursor, uint8_t encoding) { + if (encoding == DW_EH_PE_omit) { + return 0; + } + + if (!cursor) { + return CLS_INVALID_ADDRESS; + } + + if (!*cursor) { + return CLS_INVALID_ADDRESS; + } + + intptr_t inputAddr = (intptr_t)*cursor; + intptr_t addr; + + switch (encoding & DW_EH_PE_VALUE_MASK) { + case DW_EH_PE_ptr: + // 32 or 64 bits + addr = FIRCLSParsePointerAndAdvance(cursor); + break; + case DW_EH_PE_uleb128: + addr = (intptr_t)FIRCLSParseULEB128AndAdvance(cursor); + break; + case DW_EH_PE_udata2: + addr = FIRCLSParseUint16AndAdvance(cursor); + break; + case DW_EH_PE_udata4: + addr = FIRCLSParseUint32AndAdvance(cursor); + break; + case DW_EH_PE_udata8: + addr = (intptr_t)FIRCLSParseUint64AndAdvance(cursor); + break; + case DW_EH_PE_sleb128: + addr = (intptr_t)FIRCLSParseLEB128AndAdvance(cursor); + break; + case DW_EH_PE_sdata2: + addr = FIRCLSParseInt16AndAdvance(cursor); + break; + case DW_EH_PE_sdata4: + addr = FIRCLSParseInt32AndAdvance(cursor); + break; + case DW_EH_PE_sdata8: + addr = (intptr_t)FIRCLSParseInt64AndAdvance(cursor); + break; + default: + FIRCLSSDKLog("Unhandled: encoding 0x%02x\n", encoding); + return CLS_INVALID_ADDRESS; + } + + // and now apply the relative offset + switch (encoding & DW_EH_PE_RELATIVE_OFFSET_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + addr += inputAddr; + break; + default: + FIRCLSSDKLog("Unhandled: relative encoding 0x%02x\n", encoding); + return CLS_INVALID_ADDRESS; + } + + // Here's a crazy one. It seems this encoding means you actually look up + // the value of the address using the result address itself + if (encoding & DW_EH_PE_indirect) { + if (!addr) { + return CLS_INVALID_ADDRESS; + } + + addr = *(uintptr_t*)addr; + } + + return addr; +} +#else +INJECT_STRIP_SYMBOL(data_parsing) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h new file mode 100644 index 0000000..0158cc9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h @@ -0,0 +1,46 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +#if CLS_DWARF_UNWINDING_SUPPORTED + +#if CLS_CPU_64BIT +#define CLS_INVALID_ADDRESS (0xffffffffffffffff) +#else +#define CLS_INVALID_ADDRESS (0xffffffff) +#endif + +// basic data types +uint8_t FIRCLSParseUint8AndAdvance(const void** cursor); +uint16_t FIRCLSParseUint16AndAdvance(const void** cursor); +int16_t FIRCLSParseInt16AndAdvance(const void** cursor); +uint32_t FIRCLSParseUint32AndAdvance(const void** cursor); +int32_t FIRCLSParseInt32AndAdvance(const void** cursor); +uint64_t FIRCLSParseUint64AndAdvance(const void** cursor); +int64_t FIRCLSParseInt64AndAdvance(const void** cursor); +uintptr_t FIRCLSParsePointerAndAdvance(const void** cursor); +uint64_t FIRCLSParseULEB128AndAdvance(const void** cursor); +int64_t FIRCLSParseLEB128AndAdvance(const void** cursor); +const char* FIRCLSParseStringAndAdvance(const void** cursor); + +// FDE/CIE-specifc structures +uint64_t FIRCLSParseRecordLengthAndAdvance(const void** cursor); +uintptr_t FIRCLSParseAddressWithEncodingAndAdvance(const void** cursor, uint8_t encoding); + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.c new file mode 100644 index 0000000..ef975fe --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.c @@ -0,0 +1,453 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwindRegisters.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#include "Crashlytics/third_party/libunwind/dwarf.h" + +#if CLS_DWARF_UNWINDING_SUPPORTED + +static bool FIRCLSDwarfExpressionMachineExecute_bregN(FIRCLSDwarfExpressionMachine *machine, + uint8_t opcode); +static bool FIRCLSDwarfExpressionMachineExecute_deref(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_plus_uconst(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_and(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_plus(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_dup(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_swap(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_deref_size(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_ne(FIRCLSDwarfExpressionMachine *machine); +static bool FIRCLSDwarfExpressionMachineExecute_litN(FIRCLSDwarfExpressionMachine *machine, + uint8_t opcode); + +#pragma mark - +#pragma mark Stack Implementation +void FIRCLSDwarfExpressionStackInit(FIRCLSDwarfExpressionStack *stack) { + if (!FIRCLSIsValidPointer(stack)) { + return; + } + + memset(stack, 0, sizeof(FIRCLSDwarfExpressionStack)); + + stack->pointer = stack->buffer; +} + +bool FIRCLSDwarfExpressionStackIsValid(FIRCLSDwarfExpressionStack *stack) { + if (!FIRCLSIsValidPointer(stack)) { + return false; + } + + // check for valid stack pointer + if (stack->pointer < stack->buffer) { + return false; + } + + if (stack->pointer > stack->buffer + CLS_DWARF_EXPRESSION_STACK_SIZE) { + return false; + } + + return true; +} + +bool FIRCLSDwarfExpressionStackPush(FIRCLSDwarfExpressionStack *stack, intptr_t value) { + if (!FIRCLSDwarfExpressionStackIsValid(stack)) { + return false; + } + + if (stack->pointer == stack->buffer + CLS_DWARF_EXPRESSION_STACK_SIZE) { + // overflow + stack->pointer = NULL; + return false; + } + + *(stack->pointer) = value; + stack->pointer += 1; + + return true; +} + +intptr_t FIRCLSDwarfExpressionStackPeek(FIRCLSDwarfExpressionStack *stack) { + if (!FIRCLSDwarfExpressionStackIsValid(stack)) { + return 0; + } + + if (stack->pointer == stack->buffer) { + // underflow + stack->pointer = NULL; + return 0; + } + + return *(stack->pointer - 1); +} + +intptr_t FIRCLSDwarfExpressionStackPop(FIRCLSDwarfExpressionStack *stack) { + if (!FIRCLSDwarfExpressionStackIsValid(stack)) { + return 0; + } + + if (stack->pointer == stack->buffer) { + // underflow + stack->pointer = NULL; + return 0; + } + + stack->pointer -= 1; + + return *(stack->pointer); +} + +#pragma mark - +#pragma mark Machine API +bool FIRCLSDwarfExpressionMachineInit(FIRCLSDwarfExpressionMachine *machine, + const void *cursor, + const FIRCLSThreadContext *registers, + intptr_t stackValue) { + if (!FIRCLSIsValidPointer(machine)) { + return false; + } + + memset(machine, 0, sizeof(FIRCLSDwarfExpressionMachine)); + + if (!FIRCLSIsValidPointer(cursor)) { + return false; + } + + machine->dataCursor = cursor; + machine->registers = registers; + + FIRCLSDwarfExpressionStackInit(&machine->stack); + + return FIRCLSDwarfExpressionStackPush(&machine->stack, stackValue); +} + +bool FIRCLSDwarfExpressionMachinePrepareForExecution(FIRCLSDwarfExpressionMachine *machine) { + if (!FIRCLSIsValidPointer(machine)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return false; + } + + uint64_t expressionLength = FIRCLSParseULEB128AndAdvance(&machine->dataCursor); + + if (expressionLength == 0) { + FIRCLSSDKLog("Error: DWARF expression length is zero\n"); + return false; + } + + machine->endAddress = machine->dataCursor + expressionLength; + + return true; +} + +bool FIRCLSDwarfExpressionMachineIsFinished(FIRCLSDwarfExpressionMachine *machine) { + if (!FIRCLSIsValidPointer(machine)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return true; + } + + if (!FIRCLSIsValidPointer(machine->endAddress) || !FIRCLSIsValidPointer(machine->dataCursor)) { + FIRCLSSDKLog("Error: DWARF machine pointers invalid\n"); + return true; + } + + if (!FIRCLSDwarfExpressionStackIsValid(&machine->stack)) { + FIRCLSSDKLog("Error: DWARF machine stack invalid\n"); + return true; + } + + return machine->dataCursor >= machine->endAddress; +} + +bool FIRCLSDwarfExpressionMachineGetResult(FIRCLSDwarfExpressionMachine *machine, + intptr_t *result) { + if (!FIRCLSIsValidPointer(machine) || !FIRCLSIsValidPointer(result)) { + return false; + } + + if (machine->dataCursor != machine->endAddress) { + FIRCLSSDKLog("Error: DWARF expression hasn't completed execution\n"); + return false; + } + + *result = FIRCLSDwarfExpressionStackPeek(&machine->stack); + + return FIRCLSDwarfExpressionStackIsValid(&machine->stack); +} + +bool FIRCLSDwarfExpressionMachineExecuteNextOpcode(FIRCLSDwarfExpressionMachine *machine) { + if (!FIRCLSIsValidPointer(machine)) { + return false; + } + + const uint8_t opcode = FIRCLSParseUint8AndAdvance(&machine->dataCursor); + + bool success = false; + + switch (opcode) { + case DW_OP_deref: + success = FIRCLSDwarfExpressionMachineExecute_deref(machine); + break; + case DW_OP_dup: + success = FIRCLSDwarfExpressionMachineExecute_dup(machine); + break; + case DW_OP_and: + success = FIRCLSDwarfExpressionMachineExecute_and(machine); + break; + case DW_OP_plus: + success = FIRCLSDwarfExpressionMachineExecute_plus(machine); + break; + case DW_OP_swap: + success = FIRCLSDwarfExpressionMachineExecute_swap(machine); + break; + case DW_OP_plus_uconst: + success = FIRCLSDwarfExpressionMachineExecute_plus_uconst(machine); + break; + case DW_OP_ne: + success = FIRCLSDwarfExpressionMachineExecute_ne(machine); + break; + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + success = FIRCLSDwarfExpressionMachineExecute_litN(machine, opcode); + break; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + success = FIRCLSDwarfExpressionMachineExecute_bregN(machine, opcode); + break; + case DW_OP_deref_size: + success = FIRCLSDwarfExpressionMachineExecute_deref_size(machine); + break; + default: + FIRCLSSDKLog("Error: Unrecognized DWARF expression opcode 0x%x\n", opcode); + return false; + } + + return success; +} + +#pragma mark - +#pragma mark Helpers +static intptr_t FIRCLSDwarfExpressionMachineStackPop(FIRCLSDwarfExpressionMachine *machine) { + return FIRCLSDwarfExpressionStackPop(&machine->stack); +} + +static bool FIRCLSDwarfExpressionMachineStackPush(FIRCLSDwarfExpressionMachine *machine, + intptr_t value) { + return FIRCLSDwarfExpressionStackPush(&machine->stack, value); +} + +#pragma mark - +#pragma mark Opcode Implementations +static bool FIRCLSDwarfExpressionMachineExecute_bregN(FIRCLSDwarfExpressionMachine *machine, + uint8_t opcode) { + // find the register number, compute offset value, push + const uint8_t regNum = opcode - DW_OP_breg0; + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: DW_OP_breg invalid register number\n"); + return false; + } + + int64_t offset = FIRCLSParseLEB128AndAdvance(&machine->dataCursor); + + FIRCLSSDKLog("DW_OP_breg %d value %d\n", regNum, (int)offset); + + const intptr_t value = + FIRCLSDwarfUnwindGetRegisterValue(machine->registers, regNum) + (intptr_t)offset; + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_deref(FIRCLSDwarfExpressionMachine *machine) { + // pop stack, dereference, push result + intptr_t value = FIRCLSDwarfExpressionMachineStackPop(machine); + + FIRCLSSDKLog("DW_OP_deref value %p\n", (void *)value); + + if (!FIRCLSReadMemory(value, &value, sizeof(value))) { + FIRCLSSDKLog("Error: DW_OP_deref failed to read memory\n"); + return false; + } + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_plus_uconst(FIRCLSDwarfExpressionMachine *machine) { + // pop stack, add constant, push result + intptr_t value = FIRCLSDwarfExpressionMachineStackPop(machine); + + value += FIRCLSParseULEB128AndAdvance(&machine->dataCursor); + + FIRCLSSDKLog("DW_OP_plus_uconst value %lu\n", value); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_and(FIRCLSDwarfExpressionMachine *machine) { + FIRCLSSDKLog("DW_OP_plus_and\n"); + + intptr_t value = FIRCLSDwarfExpressionMachineStackPop(machine); + + value = value & FIRCLSDwarfExpressionMachineStackPop(machine); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_plus(FIRCLSDwarfExpressionMachine *machine) { + FIRCLSSDKLog("DW_OP_plus\n"); + + intptr_t value = FIRCLSDwarfExpressionMachineStackPop(machine); + + value = value + FIRCLSDwarfExpressionMachineStackPop(machine); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_dup(FIRCLSDwarfExpressionMachine *machine) { + // duplicate top of stack + intptr_t value = FIRCLSDwarfExpressionStackPeek(&machine->stack); + + FIRCLSSDKLog("DW_OP_dup value %lu\n", value); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_swap(FIRCLSDwarfExpressionMachine *machine) { + // swap top two values on the stack + intptr_t valueA = FIRCLSDwarfExpressionMachineStackPop(machine); + intptr_t valueB = FIRCLSDwarfExpressionMachineStackPop(machine); + + FIRCLSSDKLog("DW_OP_swap\n"); + + if (!FIRCLSDwarfExpressionMachineStackPush(machine, valueA)) { + return false; + } + + return FIRCLSDwarfExpressionMachineStackPush(machine, valueB); +} + +static bool FIRCLSDwarfExpressionMachineExecute_deref_size(FIRCLSDwarfExpressionMachine *machine) { + // pop stack, dereference variable sized value, push result + const void *address = (const void *)FIRCLSDwarfExpressionMachineStackPop(machine); + const uint8_t readSize = FIRCLSParseUint8AndAdvance(&machine->dataCursor); + intptr_t value = 0; + + FIRCLSSDKLog("DW_OP_deref_size %p size %u\n", address, readSize); + + switch (readSize) { + case 1: + value = FIRCLSParseUint8AndAdvance(&address); + break; + case 2: + value = FIRCLSParseUint16AndAdvance(&address); + break; + case 4: + value = FIRCLSParseUint32AndAdvance(&address); + break; + case 8: + // this is a little funky, as an 8 here really doesn't make sense for 32-bit platforms + value = (intptr_t)FIRCLSParseUint64AndAdvance(&address); + break; + default: + FIRCLSSDKLog("Error: unrecognized DW_OP_deref_size argument %x\n", readSize); + return false; + } + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_ne(FIRCLSDwarfExpressionMachine *machine) { + FIRCLSSDKLog("DW_OP_ne\n"); + + intptr_t value = FIRCLSDwarfExpressionMachineStackPop(machine); + + value = value != FIRCLSDwarfExpressionMachineStackPop(machine); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +static bool FIRCLSDwarfExpressionMachineExecute_litN(FIRCLSDwarfExpressionMachine *machine, + uint8_t opcode) { + const uint8_t value = opcode - DW_OP_lit0; + + FIRCLSSDKLog("DW_OP_lit %u\n", value); + + return FIRCLSDwarfExpressionMachineStackPush(machine, value); +} + +#else +INJECT_STRIP_SYMBOL(dwarf_expression_machine) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h new file mode 100644 index 0000000..2fb4628 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h @@ -0,0 +1,55 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" + +#define CLS_DWARF_EXPRESSION_STACK_SIZE (100) + +#if CLS_DWARF_UNWINDING_SUPPORTED + +typedef struct { + intptr_t buffer[CLS_DWARF_EXPRESSION_STACK_SIZE]; + intptr_t *pointer; +} FIRCLSDwarfExpressionStack; + +typedef struct { + FIRCLSDwarfExpressionStack stack; + const void *dataCursor; + const void *endAddress; + const FIRCLSThreadContext *registers; +} FIRCLSDwarfExpressionMachine; + +void FIRCLSDwarfExpressionStackInit(FIRCLSDwarfExpressionStack *stack); +bool FIRCLSDwarfExpressionStackIsValid(FIRCLSDwarfExpressionStack *stack); +bool FIRCLSDwarfExpressionStackPush(FIRCLSDwarfExpressionStack *stack, intptr_t value); +intptr_t FIRCLSDwarfExpressionStackPeek(FIRCLSDwarfExpressionStack *stack); +intptr_t FIRCLSDwarfExpressionStackPop(FIRCLSDwarfExpressionStack *stack); + +bool FIRCLSDwarfExpressionMachineInit(FIRCLSDwarfExpressionMachine *machine, + const void *cursor, + const FIRCLSThreadContext *registers, + intptr_t stackValue); +bool FIRCLSDwarfExpressionMachinePrepareForExecution(FIRCLSDwarfExpressionMachine *machine); +bool FIRCLSDwarfExpressionMachineIsFinished(FIRCLSDwarfExpressionMachine *machine); +bool FIRCLSDwarfExpressionMachineGetResult(FIRCLSDwarfExpressionMachine *machine, intptr_t *result); + +bool FIRCLSDwarfExpressionMachineExecuteNextOpcode(FIRCLSDwarfExpressionMachine *machine); + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.c new file mode 100644 index 0000000..de6e2aa --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.c @@ -0,0 +1,1001 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDataParsing.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfExpressionMachine.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#include "Crashlytics/third_party/libunwind/dwarf.h" + +#include + +#if CLS_DWARF_UNWINDING_SUPPORTED + +#define FIRCLSDwarfLog(__FORMAT__, ...) FIRCLSSDKLog(__FORMAT__, ##__VA_ARGS__) + +#define CLS_DWARF_EXPRESSION_STACK_SIZE (100) + +#pragma mark Prototypes +static bool FIRCLSDwarfParseAndProcessAugmentation(DWARFCIERecord* record, const void** ptr); + +#pragma mark - Record Parsing +bool FIRCLSDwarfParseCIERecord(DWARFCIERecord* cie, const void* ptr) { + if (!cie || !ptr) { + return false; + } + + memset(cie, 0, sizeof(DWARFCIERecord)); + + cie->length = FIRCLSParseRecordLengthAndAdvance(&ptr); + if (cie->length == 0) { + FIRCLSSDKLog("Error: CIE length invalid\n"); + return false; + } + + // the length does not include the length field(s) themselves + const void* endAddress = ptr + cie->length; + + if (FIRCLSParseUint32AndAdvance(&ptr) != DWARF_CIE_ID_CIE_FLAG) { + FIRCLSSDKLog("Error: CIE flag not found\n"); + } + + cie->version = FIRCLSParseUint8AndAdvance(&ptr); + if (cie->version != 1 && cie->version != 3) { + FIRCLSSDKLog("Error: CIE version %u unsupported\n", cie->version); + } + + cie->pointerEncoding = DW_EH_PE_absptr; + cie->lsdaEncoding = DW_EH_PE_absptr; + + cie->augmentation = FIRCLSParseStringAndAdvance(&ptr); + cie->codeAlignFactor = FIRCLSParseULEB128AndAdvance(&ptr); + cie->dataAlignFactor = FIRCLSParseLEB128AndAdvance(&ptr); + + switch (cie->version) { + case 1: + cie->returnAddressRegister = FIRCLSParseUint8AndAdvance(&ptr); + break; + case 3: + cie->returnAddressRegister = FIRCLSParseULEB128AndAdvance(&ptr); + break; + default: + FIRCLSSDKLog("Error: CIE version %u unsupported\n", cie->version); + return false; + } + + if (!FIRCLSDwarfParseAndProcessAugmentation(cie, &ptr)) { + return false; + } + + cie->instructions.data = ptr; + cie->instructions.length = (uint32_t)(endAddress - ptr); + + return true; +} + +static bool FIRCLSDwarfParseAndProcessAugmentation(DWARFCIERecord* record, const void** ptr) { + if (!record || !ptr) { + return false; + } + + if (!record->augmentation) { + return false; + } + + if (record->augmentation[0] == 0) { + return true; + } + + if (record->augmentation[0] != 'z') { + FIRCLSSDKLog("Error: Unimplemented: augmentation string %s\n", record->augmentation); + return false; + } + + size_t stringLength = strlen(record->augmentation); + + uint64_t dataLength = FIRCLSParseULEB128AndAdvance(ptr); + const void* ending = *ptr + dataLength; + + // start at 1 because we know the first character is a 'z' + for (size_t i = 1; i < stringLength; ++i) { + switch (record->augmentation[i]) { + case 'L': + // There is an LSDA pointer encoding present. The actual address of the LSDA + // is in the FDE + record->lsdaEncoding = FIRCLSParseUint8AndAdvance(ptr); + break; + case 'R': + // There is a pointer encoding present, used for all addresses in an FDE. + record->pointerEncoding = FIRCLSParseUint8AndAdvance(ptr); + break; + case 'P': + // Two arguments. A pointer encoding, and a pointer to a personality function encoded + // with that value. + record->personalityEncoding = FIRCLSParseUint8AndAdvance(ptr); + record->personalityFunction = + FIRCLSParseAddressWithEncodingAndAdvance(ptr, record->personalityEncoding); + if (record->personalityFunction == CLS_INVALID_ADDRESS) { + FIRCLSSDKLog("Error: Found an invalid start address\n"); + return false; + } + break; + case 'S': + record->signalFrame = true; + break; + default: + FIRCLSSDKLog("Error: Unhandled augmentation string entry %c\n", record->augmentation[i]); + return false; + } + + // small sanity check + if (*ptr > ending) { + return false; + } + } + + return true; +} + +bool FIRCLSDwarfParseFDERecord(DWARFFDERecord* fdeRecord, + bool parseCIE, + DWARFCIERecord* cieRecord, + const void* ptr) { + if (!fdeRecord || !cieRecord || !ptr) { + return false; + } + + fdeRecord->length = FIRCLSParseRecordLengthAndAdvance(&ptr); + if (fdeRecord->length == 0) { + FIRCLSSDKLog("Error: FDE has zero length\n"); + return false; + } + + // length does not include length field + const void* endAddress = ptr + fdeRecord->length; + + // According to the spec, this is 32/64 bit value, but libunwind always + // parses this as a 32bit value. + fdeRecord->cieOffset = FIRCLSParseUint32AndAdvance(&ptr); + if (fdeRecord->cieOffset == 0) { + FIRCLSSDKLog("Error: CIE offset invalid\n"); + return false; + } + + if (parseCIE) { + // The CIE offset is really weird. It appears to be an offset from the + // beginning of its field. This isn't what the documentation says, but it is + // a little ambiguous. This is what DwarfParser.hpp does. + // Note that we have to back up one sizeof(uint32_t), because we've advanced + // by parsing the offset + const void* ciePointer = ptr - fdeRecord->cieOffset - sizeof(uint32_t); + if (!FIRCLSDwarfParseCIERecord(cieRecord, ciePointer)) { + FIRCLSSDKLog("Error: Unable to parse CIE record\n"); + return false; + } + } + + if (!FIRCLSDwarfCIEIsValid(cieRecord)) { + FIRCLSSDKLog("Error: CIE invalid\n"); + return false; + } + + // the next field depends on the pointer encoding style used + fdeRecord->startAddress = + FIRCLSParseAddressWithEncodingAndAdvance(&ptr, cieRecord->pointerEncoding); + if (fdeRecord->startAddress == CLS_INVALID_ADDRESS) { + FIRCLSSDKLog("Error: Found an invalid start address\n"); + return false; + } + + // Here's something weird too. The range is encoded as a "special" address, where only the value + // is used, regardless of other pointer-encoding schemes. + fdeRecord->rangeSize = FIRCLSParseAddressWithEncodingAndAdvance( + &ptr, cieRecord->pointerEncoding & DW_EH_PE_VALUE_MASK); + if (fdeRecord->rangeSize == CLS_INVALID_ADDRESS) { + FIRCLSSDKLog("Error: Found an invalid address range\n"); + return false; + } + + // Just skip over the section for now. The data here is only needed for personality functions, + // which we don't need + if (FIRCLSDwarfCIEHasAugmentationData(cieRecord)) { + uintptr_t augmentationLength = (uintptr_t)FIRCLSParseULEB128AndAdvance(&ptr); + + ptr += augmentationLength; + } + + fdeRecord->instructions.data = ptr; + fdeRecord->instructions.length = (uint32_t)(endAddress - ptr); + + return true; +} + +bool FIRCLSDwarfParseCFIFromFDERecord(FIRCLSDwarfCFIRecord* record, const void* ptr) { + if (!record || !ptr) { + return false; + } + + return FIRCLSDwarfParseFDERecord(&record->fde, true, &record->cie, ptr); +} + +bool FIRCLSDwarfParseCFIFromFDERecordOffset(FIRCLSDwarfCFIRecord* record, + const void* ehFrame, + uintptr_t fdeOffset) { + if (!record || !ehFrame || (fdeOffset == 0)) { + return false; + } + + const void* ptr = ehFrame + fdeOffset; + + return FIRCLSDwarfParseCFIFromFDERecord(record, ptr); +} + +#pragma mark - Properties +bool FIRCLSDwarfCIEIsValid(DWARFCIERecord* cie) { + if (!cie) { + return false; + } + + if (cie->length == 0) { + return false; + } + + if (cie->version != 1 && cie->version != 3) { + return false; + } + + return true; +} + +bool FIRCLSDwarfCIEHasAugmentationData(DWARFCIERecord* cie) { + if (!cie) { + return false; + } + + if (!cie->augmentation) { + return false; + } + + return cie->augmentation[0] == 'z'; +} + +#pragma mark - Instructions + +static bool FIRCLSDwarfParseAndExecute_set_loc(const void** cursor, + DWARFCIERecord* cieRecord, + intptr_t* codeOffset) { + uintptr_t operand = FIRCLSParseAddressWithEncodingAndAdvance(cursor, cieRecord->pointerEncoding); + + *codeOffset = operand; + + FIRCLSDwarfLog("DW_CFA_set_loc %lu\n", operand); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_advance_loc1(const void** cursor, + DWARFCIERecord* cieRecord, + intptr_t* codeOffset) { + int64_t offset = FIRCLSParseUint8AndAdvance(cursor) * cieRecord->codeAlignFactor; + + *codeOffset += offset; + + FIRCLSDwarfLog("DW_CFA_advance_loc1 %lld\n", offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_advance_loc2(const void** cursor, + DWARFCIERecord* cieRecord, + intptr_t* codeOffset) { + int64_t offset = FIRCLSParseUint16AndAdvance(cursor) * cieRecord->codeAlignFactor; + + *codeOffset += offset; + + FIRCLSDwarfLog("DW_CFA_advance_loc2 %lld\n", offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_advance_loc4(const void** cursor, + DWARFCIERecord* cieRecord, + intptr_t* codeOffset) { + int64_t offset = FIRCLSParseUint32AndAdvance(cursor) * cieRecord->codeAlignFactor; + + *codeOffset += offset; + + FIRCLSDwarfLog("DW_CFA_advance_loc4 %lld\n", offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_def_cfa(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_def_cfa register number\n"); + return false; + } + + int64_t offset = FIRCLSParseULEB128AndAdvance(cursor); + + state->cfaRegister = regNum; + state->cfaRegisterOffset = offset; + + FIRCLSDwarfLog("DW_CFA_def_cfa %llu, %lld\n", regNum, offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_def_cfa_register(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_def_cfa_register register number\n"); + return false; + } + + state->cfaRegister = regNum; + + FIRCLSDwarfLog("DW_CFA_def_cfa_register %llu\n", regNum); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_def_cfa_offset(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t offset = FIRCLSParseULEB128AndAdvance(cursor); + + state->cfaRegisterOffset = offset; + + FIRCLSDwarfLog("DW_CFA_def_cfa_offset %lld\n", offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_same_value(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_same_value register number\n"); + return false; + } + + state->registers[regNum].location = FIRCLSDwarfRegisterUnused; + + FIRCLSDwarfLog("DW_CFA_same_value %llu\n", regNum); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_register(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_register number\n"); + return false; + } + + uint64_t regValue = FIRCLSParseULEB128AndAdvance(cursor); + + if (regValue > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_register value\n"); + return false; + } + + state->registers[regNum].location = FIRCLSDwarfRegisterInRegister; + state->registers[regNum].value = regValue; + + FIRCLSDwarfLog("DW_CFA_register %llu %llu\n", regNum, regValue); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_expression(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_expression register number\n"); + return false; + } + + state->registers[regNum].location = FIRCLSDwarfRegisterAtExpression; + state->registers[regNum].value = (uintptr_t)*cursor; + + // read the length of the expression, and advance past it + uint64_t length = FIRCLSParseULEB128AndAdvance(cursor); + *cursor += length; + + FIRCLSDwarfLog("DW_CFA_expression %llu %llu\n", regNum, length); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_val_expression(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + uint64_t regNum = FIRCLSParseULEB128AndAdvance(cursor); + + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_val_expression register number\n"); + return false; + } + + state->registers[regNum].location = FIRCLSDwarfRegisterIsExpression; + state->registers[regNum].value = (uintptr_t)*cursor; + + // read the length of the expression, and advance past it + uint64_t length = FIRCLSParseULEB128AndAdvance(cursor); + *cursor += length; + + FIRCLSDwarfLog("DW_CFA_val_expression %llu %llu\n", regNum, length); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_def_cfa_expression(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state) { + state->cfaRegister = CLS_DWARF_INVALID_REGISTER_NUM; + state->cfaExpression = *cursor; + + // read the length of the expression, and advance past it + uint64_t length = FIRCLSParseULEB128AndAdvance(cursor); + *cursor += length; + + FIRCLSDwarfLog("DW_CFA_def_cfa_expression %llu\n", length); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_offset(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state, + uint8_t regNum) { + if (regNum > CLS_DWARF_MAX_REGISTER_NUM) { + FIRCLSSDKLog("Error: Found an invalid DW_CFA_offset register number\n"); + return false; + } + + int64_t offset = FIRCLSParseULEB128AndAdvance(cursor) * cieRecord->dataAlignFactor; + + state->registers[regNum].location = FIRCLSDwarfRegisterInCFA; + state->registers[regNum].value = offset; + + FIRCLSDwarfLog("DW_CFA_offset %u, %lld\n", regNum, offset); + + return true; +} + +static bool FIRCLSDwarfParseAndExecute_advance_loc(const void** cursor, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state, + uint8_t delta, + intptr_t* codeOffset) { + if (!FIRCLSIsValidPointer(codeOffset) || !FIRCLSIsValidPointer(cieRecord)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return false; + } + + *codeOffset = delta * (intptr_t)cieRecord->codeAlignFactor; + + FIRCLSDwarfLog("DW_CFA_advance_loc %u\n", delta); + + return true; +} + +static bool FIRCLSDwarfParseAndExecuteInstructionWithOperand(const void** cursor, + uint8_t instruction, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state, + intptr_t* codeOffset) { + uint8_t operand = instruction & DW_CFA_OPERAND_MASK; + bool success = false; + + switch (instruction & DW_CFA_OPCODE_MASK) { + case DW_CFA_offset: + success = FIRCLSDwarfParseAndExecute_offset(cursor, cieRecord, state, operand); + break; + case DW_CFA_advance_loc: + success = + FIRCLSDwarfParseAndExecute_advance_loc(cursor, cieRecord, state, operand, codeOffset); + break; + case DW_CFA_restore: + FIRCLSSDKLog("Error: Unimplemented DWARF instruction with operand 0x%x\n", instruction); + break; + default: + FIRCLSSDKLog("Error: Unrecognized DWARF instruction 0x%x\n", instruction); + break; + } + + return success; +} + +#pragma mark - Expressions +static bool FIRCLSDwarfEvalulateExpression(const void* cursor, + const FIRCLSThreadContext* registers, + intptr_t stackValue, + intptr_t* result) { + FIRCLSDwarfLog("starting at %p with initial value %lx\n", cursor, stackValue); + + if (!FIRCLSIsValidPointer(cursor) || !FIRCLSIsValidPointer(result)) { + FIRCLSSDKLog("Error: inputs invalid\n"); + return false; + } + + FIRCLSDwarfExpressionMachine machine; + + if (!FIRCLSDwarfExpressionMachineInit(&machine, cursor, registers, stackValue)) { + FIRCLSSDKLog("Error: unable to init DWARF expression machine\n"); + return false; + } + + if (!FIRCLSDwarfExpressionMachinePrepareForExecution(&machine)) { + FIRCLSSDKLog("Error: unable to prepare for execution\n"); + return false; + } + + while (!FIRCLSDwarfExpressionMachineIsFinished(&machine)) { + if (!FIRCLSDwarfExpressionMachineExecuteNextOpcode(&machine)) { + FIRCLSSDKLog("Error: failed to execute DWARF machine opcode\n"); + return false; + } + } + + if (!FIRCLSDwarfExpressionMachineGetResult(&machine, result)) { + FIRCLSSDKLog("Error: failed to get DWARF expression result\n"); + return false; + } + + FIRCLSDwarfLog("successfully computed expression result\n"); + + return true; +} + +#pragma mark - Execution +bool FIRCLSDwarfInstructionsEnumerate(DWARFInstructions* instructions, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state, + intptr_t pcOffset) { + if (!instructions || !cieRecord || !state) { + FIRCLSSDKLog("Error: inputs invalid\n"); + return false; + } + + // This is a little bit of state that can't be put into the state structure, because + // it is possible for instructions to push/pop state that does not affect this value. + intptr_t codeOffset = 0; + + const void* cursor = instructions->data; + const void* endAddress = cursor + instructions->length; + + FIRCLSDwarfLog("Running instructions from %p to %p\n", cursor, endAddress); + + // parse the instructions, as long as: + // - our data pointer is still in range + // - the pc offset is within the range of instructions that apply + + while ((cursor < endAddress) && (codeOffset < pcOffset)) { + uint8_t instruction = FIRCLSParseUint8AndAdvance(&cursor); + bool success = false; + + switch (instruction) { + case DW_CFA_nop: + FIRCLSDwarfLog("DW_CFA_nop\n"); + continue; + case DW_CFA_set_loc: + success = FIRCLSDwarfParseAndExecute_set_loc(&cursor, cieRecord, &codeOffset); + break; + case DW_CFA_advance_loc1: + success = FIRCLSDwarfParseAndExecute_advance_loc1(&cursor, cieRecord, &codeOffset); + break; + case DW_CFA_advance_loc2: + success = FIRCLSDwarfParseAndExecute_advance_loc2(&cursor, cieRecord, &codeOffset); + break; + case DW_CFA_advance_loc4: + success = FIRCLSDwarfParseAndExecute_advance_loc4(&cursor, cieRecord, &codeOffset); + break; + case DW_CFA_def_cfa: + success = FIRCLSDwarfParseAndExecute_def_cfa(&cursor, cieRecord, state); + break; + case DW_CFA_def_cfa_register: + success = FIRCLSDwarfParseAndExecute_def_cfa_register(&cursor, cieRecord, state); + break; + case DW_CFA_def_cfa_offset: + success = FIRCLSDwarfParseAndExecute_def_cfa_offset(&cursor, cieRecord, state); + break; + case DW_CFA_same_value: + success = FIRCLSDwarfParseAndExecute_same_value(&cursor, cieRecord, state); + break; + case DW_CFA_register: + success = FIRCLSDwarfParseAndExecute_register(&cursor, cieRecord, state); + break; + case DW_CFA_def_cfa_expression: + success = FIRCLSDwarfParseAndExecute_def_cfa_expression(&cursor, cieRecord, state); + break; + case DW_CFA_expression: + success = FIRCLSDwarfParseAndExecute_expression(&cursor, cieRecord, state); + break; + case DW_CFA_val_expression: + success = FIRCLSDwarfParseAndExecute_val_expression(&cursor, cieRecord, state); + break; + case DW_CFA_offset_extended: + case DW_CFA_restore_extended: + case DW_CFA_undefined: + case DW_CFA_remember_state: + case DW_CFA_restore_state: + case DW_CFA_offset_extended_sf: + case DW_CFA_def_cfa_sf: + case DW_CFA_def_cfa_offset_sf: + case DW_CFA_val_offset: + case DW_CFA_val_offset_sf: + case DW_CFA_GNU_window_save: + case DW_CFA_GNU_args_size: + case DW_CFA_GNU_negative_offset_extended: + FIRCLSSDKLog("Error: Unimplemented DWARF instruction 0x%x\n", instruction); + return false; + default: + success = FIRCLSDwarfParseAndExecuteInstructionWithOperand(&cursor, instruction, cieRecord, + state, &codeOffset); + break; + } + + if (!success) { + FIRCLSSDKLog("Error: Failed to execute dwarf instruction 0x%x\n", instruction); + return false; + } + } + + return true; +} + +bool FIRCLSDwarfUnwindComputeRegisters(FIRCLSDwarfCFIRecord* record, + FIRCLSThreadContext* registers) { + if (!record || !registers) { + return false; + } + + // We need to run the dwarf instructions to compute our register values. + // - initialize state + // - run the CIE instructions + // - run the FDE instructions + // - grab the values + + FIRCLSDwarfState state; + + memset(&state, 0, sizeof(FIRCLSDwarfState)); + + // We need to run all the instructions in the CIE record. So, pass in a large value for the pc + // offset so we don't stop early. + if (!FIRCLSDwarfInstructionsEnumerate(&record->cie.instructions, &record->cie, &state, + INTPTR_MAX)) { + FIRCLSSDKLog("Error: Unable to run CIE instructions\n"); + return false; + } + + intptr_t pcOffset = FIRCLSThreadContextGetPC(registers) - record->fde.startAddress; + if (pcOffset < 0) { + FIRCLSSDKLog("Error: The FDE pcOffset value cannot be negative\n"); + return false; + } + + if (!FIRCLSDwarfInstructionsEnumerate(&record->fde.instructions, &record->cie, &state, + pcOffset)) { + FIRCLSSDKLog("Error: Unable to run FDE instructions\n"); + return false; + } + + uintptr_t cfaRegister = 0; + + if (!FIRCLSDwarfGetCFA(&state, registers, &cfaRegister)) { + FIRCLSSDKLog("Error: failed to get CFA\n"); + return false; + } + + if (!FIRCLSDwarfUnwindAssignRegisters(&state, registers, cfaRegister, registers)) { + FIRCLSSDKLogError("Error: Unable to assign DWARF registers\n"); + return false; + } + + return true; +} + +bool FIRCLSDwarfUnwindAssignRegisters(const FIRCLSDwarfState* state, + const FIRCLSThreadContext* registers, + uintptr_t cfaRegister, + FIRCLSThreadContext* outputRegisters) { + if (!FIRCLSIsValidPointer(state) || !FIRCLSIsValidPointer(registers)) { + FIRCLSSDKLogError("Error: input invalid\n"); + return false; + } + + // make a copy, which we'll be changing + FIRCLSThreadContext newThreadState = *registers; + + // loop through all the registers, so we can set their values + for (size_t i = 0; i <= CLS_DWARF_MAX_REGISTER_NUM; ++i) { + if (state->registers[i].location == FIRCLSDwarfRegisterUnused) { + continue; + } + + const uintptr_t value = + FIRCLSDwarfGetSavedRegister(registers, cfaRegister, state->registers[i]); + + if (!FIRCLSDwarfUnwindSetRegisterValue(&newThreadState, i, value)) { + FIRCLSSDKLog("Error: Unable to restore register value\n"); + return false; + } + } + + if (!FIRCLSDwarfUnwindSetRegisterValue(&newThreadState, CLS_DWARF_REG_SP, cfaRegister)) { + FIRCLSSDKLog("Error: Unable to restore SP value\n"); + return false; + } + + // sanity-check that things have changed + if (FIRCLSDwarfCompareRegisters(registers, &newThreadState, CLS_DWARF_REG_SP)) { + FIRCLSSDKLog("Error: Stack pointer hasn't changed\n"); + return false; + } + + if (FIRCLSDwarfCompareRegisters(registers, &newThreadState, CLS_DWARF_REG_RETURN)) { + FIRCLSSDKLog("Error: PC hasn't changed\n"); + return false; + } + + // set our new value + *outputRegisters = newThreadState; + + return true; +} + +#pragma mark - Register Operations +bool FIRCLSDwarfCompareRegisters(const FIRCLSThreadContext* a, + const FIRCLSThreadContext* b, + uint64_t registerNum) { + return FIRCLSDwarfUnwindGetRegisterValue(a, registerNum) == + FIRCLSDwarfUnwindGetRegisterValue(b, registerNum); +} + +bool FIRCLSDwarfGetCFA(FIRCLSDwarfState* state, + const FIRCLSThreadContext* registers, + uintptr_t* cfa) { + if (!FIRCLSIsValidPointer(state) || !FIRCLSIsValidPointer(registers) || + !FIRCLSIsValidPointer(cfa)) { + FIRCLSSDKLog("Error: invalid input\n"); + return false; + } + + if (state->cfaExpression) { + if (!FIRCLSDwarfEvalulateExpression(state->cfaExpression, registers, 0, (intptr_t*)cfa)) { + FIRCLSSDKLog("Error: failed to compute CFA expression\n"); + return false; + } + + return true; + } + + // libunwind checks that cfaRegister is not zero. This seems like a potential bug - why couldn't + // it be zero? + + *cfa = FIRCLSDwarfUnwindGetRegisterValue(registers, state->cfaRegister) + + (uintptr_t)state->cfaRegisterOffset; + + return true; +} + +uintptr_t FIRCLSDwarfGetSavedRegister(const FIRCLSThreadContext* registers, + uintptr_t cfaRegister, + FIRCLSDwarfRegister dRegister) { + intptr_t result = 0; + + FIRCLSDwarfLog("Getting register %x\n", dRegister.location); + + switch (dRegister.location) { + case FIRCLSDwarfRegisterInCFA: { + const uintptr_t address = cfaRegister + (uintptr_t)dRegister.value; + + if (!FIRCLSReadMemory(address, &result, sizeof(result))) { + FIRCLSSDKLog("Error: Unable to read CFA value\n"); + return 0; + } + } + return result; + case FIRCLSDwarfRegisterInRegister: + return FIRCLSDwarfUnwindGetRegisterValue(registers, dRegister.value); + case FIRCLSDwarfRegisterOffsetFromCFA: + FIRCLSSDKLog("Error: OffsetFromCFA unhandled\n"); + break; + case FIRCLSDwarfRegisterAtExpression: + if (!FIRCLSDwarfEvalulateExpression((void*)dRegister.value, registers, cfaRegister, + &result)) { + FIRCLSSDKLog("Error: unable to evaluate expression\n"); + return 0; + } + + if (!FIRCLSReadMemory(result, &result, sizeof(result))) { + FIRCLSSDKLog("Error: Unable to read memory computed from expression\n"); + return 0; + } + + return result; + case FIRCLSDwarfRegisterIsExpression: + if (!FIRCLSDwarfEvalulateExpression((void*)dRegister.value, registers, cfaRegister, + &result)) { + FIRCLSSDKLog("Error: unable to evaluate expression\n"); + return 0; + } + + return result; + default: + FIRCLSSDKLog("Error: Unrecognized register save location 0x%x\n", dRegister.location); + break; + } + + return 0; +} + +#if DEBUG +#pragma mark - Debugging +void FIRCLSCFIRecordShow(FIRCLSDwarfCFIRecord* record) { + if (!record) { + FIRCLSSDKLog("Error: CFI record: null\n"); + return; + } + + FIRCLSCIERecordShow(&record->cie); + FIRCLSFDERecordShow(&record->fde, &record->cie); +} + +void FIRCLSCIERecordShow(DWARFCIERecord* record) { + if (!record) { + FIRCLSSDKLog("Error: CIE: null\n"); + return; + } + + FIRCLSSDKLog("CIE:\n"); + FIRCLSSDKLog(" length: %llu\n", record->length); + FIRCLSSDKLog(" version: %u\n", record->version); + FIRCLSSDKLog(" augmentation: %s\n", record->augmentation); + FIRCLSSDKLog(" EH Data: 0x%04lx\n", record->ehData); + FIRCLSSDKLog("LSDA encoding: 0x%02x\n", record->lsdaEncoding); + FIRCLSSDKLog(" personality: 0x%lx\n", record->personalityFunction); + + FIRCLSDwarfPointerEncodingShow(" encoding", record->pointerEncoding); + FIRCLSDwarfPointerEncodingShow(" P encoding", record->personalityEncoding); + + FIRCLSSDKLog(" code align: %llu\n", record->codeAlignFactor); + FIRCLSSDKLog(" data align: %lld\n", record->dataAlignFactor); + FIRCLSSDKLog(" RA register: %llu\n", record->returnAddressRegister); + + FIRCLSDwarfInstructionsShow(&record->instructions, record); +} + +void FIRCLSFDERecordShow(DWARFFDERecord* record, DWARFCIERecord* cie) { + if (!record) { + FIRCLSSDKLog("FDE: null\n"); + return; + } + + FIRCLSSDKLog("FDE:\n"); + FIRCLSSDKLog(" length: %llu\n", record->length); + FIRCLSSDKLog(" CIE offset: %llu\n", record->cieOffset); + FIRCLSSDKLog(" start addr: 0x%lx\n", record->startAddress); + FIRCLSSDKLog(" range: %lu\n", record->rangeSize); + + FIRCLSDwarfInstructionsShow(&record->instructions, cie); +} + +void FIRCLSDwarfPointerEncodingShow(const char* leadString, uint8_t encoding) { + if (encoding == DW_EH_PE_omit) { + FIRCLSSDKLog("%s: 0x%02x (omit)\n", leadString, encoding); + } else { + const char* peValue = "unknown"; + const char* peOffset = ""; + + switch (encoding & DW_EH_PE_VALUE_MASK) { + case DW_EH_PE_absptr: + peValue = "DW_EH_PE_absptr"; + break; + case DW_EH_PE_uleb128: + peValue = "DW_EH_PE_uleb128"; + break; + case DW_EH_PE_udata2: + peValue = "DW_EH_PE_udata2"; + break; + case DW_EH_PE_udata4: + peValue = "DW_EH_PE_udata4"; + break; + case DW_EH_PE_udata8: + peValue = "DW_EH_PE_udata8"; + break; + case DW_EH_PE_signed: + peValue = "DW_EH_PE_signed"; + break; + case DW_EH_PE_sleb128: + peValue = "DW_EH_PE_sleb128"; + break; + case DW_EH_PE_sdata2: + peValue = "DW_EH_PE_sdata2"; + break; + case DW_EH_PE_sdata4: + peValue = "DW_EH_PE_sdata4"; + break; + case DW_EH_PE_sdata8: + peValue = "DW_EH_PE_sdata8"; + break; + default: + break; + } + + switch (encoding & DW_EH_PE_RELATIVE_OFFSET_MASK) { + case DW_EH_PE_absptr: + break; + case DW_EH_PE_pcrel: + peOffset = " + DW_EH_PE_pcrel"; + break; + case DW_EH_PE_textrel: + peOffset = " + DW_EH_PE_textrel"; + break; + case DW_EH_PE_datarel: + peOffset = " + DW_EH_PE_datarel"; + break; + case DW_EH_PE_funcrel: + peOffset = " + DW_EH_PE_funcrel"; + break; + case DW_EH_PE_aligned: + peOffset = " + DW_EH_PE_aligned"; + break; + case DW_EH_PE_indirect: + peOffset = " + DW_EH_PE_indirect"; + break; + default: + break; + } + + FIRCLSSDKLog("%s: 0x%02x (%s%s)\n", leadString, encoding, peValue, peOffset); + } +} + +void FIRCLSDwarfInstructionsShow(DWARFInstructions* instructions, DWARFCIERecord* cie) { + if (!instructions) { + FIRCLSSDKLog("Error: Instructions null\n"); + } + + FIRCLSDwarfState state; + + memset(&state, 0, sizeof(FIRCLSDwarfState)); + + FIRCLSDwarfInstructionsEnumerate(instructions, cie, &state, -1); +} + +#endif + +#else +INJECT_STRIP_SYMBOL(dwarf_unwind) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h new file mode 100644 index 0000000..dca84a0 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h @@ -0,0 +1,138 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwindRegisters.h" + +#if CLS_DWARF_UNWINDING_SUPPORTED + +#pragma mark Structures +typedef struct { + uint32_t length; + const void* data; +} DWARFInstructions; + +typedef struct { + uint64_t length; + uint8_t version; + uintptr_t ehData; // 8 bytes for 64-bit architectures, 4 bytes for 32 + const char* augmentation; + uint8_t pointerEncoding; + uint8_t lsdaEncoding; + uint8_t personalityEncoding; + uintptr_t personalityFunction; + uint64_t codeAlignFactor; + int64_t dataAlignFactor; + uint64_t returnAddressRegister; // is 64 bits enough for this value? + bool signalFrame; + + DWARFInstructions instructions; +} DWARFCIERecord; + +typedef struct { + uint64_t length; + uint64_t cieOffset; // also an arch-specific size + uintptr_t startAddress; + uintptr_t rangeSize; + + DWARFInstructions instructions; +} DWARFFDERecord; + +typedef struct { + DWARFCIERecord cie; + DWARFFDERecord fde; +} FIRCLSDwarfCFIRecord; + +typedef enum { + FIRCLSDwarfRegisterUnused = 0, + FIRCLSDwarfRegisterInCFA, + FIRCLSDwarfRegisterOffsetFromCFA, + FIRCLSDwarfRegisterInRegister, + FIRCLSDwarfRegisterAtExpression, + FIRCLSDwarfRegisterIsExpression +} FIRCLSDwarfRegisterLocation; + +typedef struct { + FIRCLSDwarfRegisterLocation location; + uint64_t value; +} FIRCLSDwarfRegister; + +typedef struct { + uint64_t cfaRegister; + int64_t cfaRegisterOffset; + const void* cfaExpression; + uint32_t spArgSize; + + FIRCLSDwarfRegister registers[CLS_DWARF_MAX_REGISTER_NUM + 1]; +} FIRCLSDwarfState; + +__BEGIN_DECLS + +#pragma mark - Parsing +bool FIRCLSDwarfParseCIERecord(DWARFCIERecord* cie, const void* ptr); +bool FIRCLSDwarfParseFDERecord(DWARFFDERecord* fdeRecord, + bool parseCIE, + DWARFCIERecord* cieRecord, + const void* ptr); +bool FIRCLSDwarfParseCFIFromFDERecord(FIRCLSDwarfCFIRecord* record, const void* ptr); +bool FIRCLSDwarfParseCFIFromFDERecordOffset(FIRCLSDwarfCFIRecord* record, + const void* ehFrame, + uintptr_t fdeOffset); + +#pragma mark - Properties +bool FIRCLSDwarfCIEIsValid(DWARFCIERecord* cie); +bool FIRCLSDwarfCIEHasAugmentationData(DWARFCIERecord* cie); + +#pragma mark - Execution +bool FIRCLSDwarfInstructionsEnumerate(DWARFInstructions* instructions, + DWARFCIERecord* cieRecord, + FIRCLSDwarfState* state, + intptr_t pcOffset); +bool FIRCLSDwarfUnwindComputeRegisters(FIRCLSDwarfCFIRecord* record, + FIRCLSThreadContext* registers); +bool FIRCLSDwarfUnwindAssignRegisters(const FIRCLSDwarfState* state, + const FIRCLSThreadContext* registers, + uintptr_t cfaRegister, + FIRCLSThreadContext* outputRegisters); + +#pragma mark - Register Operations +bool FIRCLSDwarfCompareRegisters(const FIRCLSThreadContext* a, + const FIRCLSThreadContext* b, + uint64_t registerNum); + +bool FIRCLSDwarfGetCFA(FIRCLSDwarfState* state, + const FIRCLSThreadContext* registers, + uintptr_t* cfa); +uintptr_t FIRCLSDwarfGetSavedRegister(const FIRCLSThreadContext* registers, + uintptr_t cfaRegister, + FIRCLSDwarfRegister dRegister); + +#if DEBUG +#pragma mark - Debugging +void FIRCLSCFIRecordShow(FIRCLSDwarfCFIRecord* record); +void FIRCLSCIERecordShow(DWARFCIERecord* record); +void FIRCLSFDERecordShow(DWARFFDERecord* record, DWARFCIERecord* cie); +void FIRCLSDwarfPointerEncodingShow(const char* leadString, uint8_t encoding); +void FIRCLSDwarfInstructionsShow(DWARFInstructions* instructions, DWARFCIERecord* cie); +#endif + +__END_DECLS + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwindRegisters.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwindRegisters.h new file mode 100644 index 0000000..7e015cf --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwindRegisters.h @@ -0,0 +1,152 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" + +#if CLS_CPU_X86_64 +enum { + CLS_DWARF_X86_64_RAX = 0, + CLS_DWARF_X86_64_RDX = 1, + CLS_DWARF_X86_64_RCX = 2, + CLS_DWARF_X86_64_RBX = 3, + CLS_DWARF_X86_64_RSI = 4, + CLS_DWARF_X86_64_RDI = 5, + CLS_DWARF_X86_64_RBP = 6, + CLS_DWARF_X86_64_RSP = 7, + CLS_DWARF_X86_64_R8 = 8, + CLS_DWARF_X86_64_R9 = 9, + CLS_DWARF_X86_64_R10 = 10, + CLS_DWARF_X86_64_R11 = 11, + CLS_DWARF_X86_64_R12 = 12, + CLS_DWARF_X86_64_R13 = 13, + CLS_DWARF_X86_64_R14 = 14, + CLS_DWARF_X86_64_R15 = 15, + + CLS_DWARF_X86_64_RET_ADDR = 16 +}; + +#define CLS_DWARF_REG_RETURN CLS_DWARF_X86_64_RET_ADDR +#define CLS_DWARF_REG_SP CLS_DWARF_X86_64_RSP +#define CLS_DWARF_REG_FP CLS_DWARF_X86_64_RBP + +#define CLS_DWARF_MAX_REGISTER_NUM (CLS_DWARF_X86_64_RET_ADDR) + +#elif CLS_CPU_I386 + +enum { + CLS_DWARF_X86_EAX = 0, + CLS_DWARF_X86_ECX = 1, + CLS_DWARF_X86_EDX = 2, + CLS_DWARF_X86_EBX = 3, + CLS_DWARF_X86_EBP = 4, + CLS_DWARF_X86_ESP = 5, + CLS_DWARF_X86_ESI = 6, + CLS_DWARF_X86_EDI = 7, + + CLS_DWARF_X86_RET_ADDR = 8 +}; + +#define CLS_DWARF_REG_RETURN CLS_DWARF_X86_RET_ADDR +#define CLS_DWARF_REG_SP CLS_DWARF_X86_ESP +#define CLS_DWARF_REG_FP CLS_DWARF_X86_EBP + +#define CLS_DWARF_MAX_REGISTER_NUM (CLS_DWARF_X86_RET_ADDR) + +#elif CLS_CPU_ARM64 + +// 64-bit ARM64 registers +enum { + CLS_DWARF_ARM64_X0 = 0, + CLS_DWARF_ARM64_X1 = 1, + CLS_DWARF_ARM64_X2 = 2, + CLS_DWARF_ARM64_X3 = 3, + CLS_DWARF_ARM64_X4 = 4, + CLS_DWARF_ARM64_X5 = 5, + CLS_DWARF_ARM64_X6 = 6, + CLS_DWARF_ARM64_X7 = 7, + CLS_DWARF_ARM64_X8 = 8, + CLS_DWARF_ARM64_X9 = 9, + CLS_DWARF_ARM64_X10 = 10, + CLS_DWARF_ARM64_X11 = 11, + CLS_DWARF_ARM64_X12 = 12, + CLS_DWARF_ARM64_X13 = 13, + CLS_DWARF_ARM64_X14 = 14, + CLS_DWARF_ARM64_X15 = 15, + CLS_DWARF_ARM64_X16 = 16, + CLS_DWARF_ARM64_X17 = 17, + CLS_DWARF_ARM64_X18 = 18, + CLS_DWARF_ARM64_X19 = 19, + CLS_DWARF_ARM64_X20 = 20, + CLS_DWARF_ARM64_X21 = 21, + CLS_DWARF_ARM64_X22 = 22, + CLS_DWARF_ARM64_X23 = 23, + CLS_DWARF_ARM64_X24 = 24, + CLS_DWARF_ARM64_X25 = 25, + CLS_DWARF_ARM64_X26 = 26, + CLS_DWARF_ARM64_X27 = 27, + CLS_DWARF_ARM64_X28 = 28, + CLS_DWARF_ARM64_X29 = 29, + CLS_DWARF_ARM64_FP = 29, + CLS_DWARF_ARM64_X30 = 30, + CLS_DWARF_ARM64_LR = 30, + CLS_DWARF_ARM64_X31 = 31, + CLS_DWARF_ARM64_SP = 31, + // reserved block + CLS_DWARF_ARM64_D0 = 64, + CLS_DWARF_ARM64_D1 = 65, + CLS_DWARF_ARM64_D2 = 66, + CLS_DWARF_ARM64_D3 = 67, + CLS_DWARF_ARM64_D4 = 68, + CLS_DWARF_ARM64_D5 = 69, + CLS_DWARF_ARM64_D6 = 70, + CLS_DWARF_ARM64_D7 = 71, + CLS_DWARF_ARM64_D8 = 72, + CLS_DWARF_ARM64_D9 = 73, + CLS_DWARF_ARM64_D10 = 74, + CLS_DWARF_ARM64_D11 = 75, + CLS_DWARF_ARM64_D12 = 76, + CLS_DWARF_ARM64_D13 = 77, + CLS_DWARF_ARM64_D14 = 78, + CLS_DWARF_ARM64_D15 = 79, + CLS_DWARF_ARM64_D16 = 80, + CLS_DWARF_ARM64_D17 = 81, + CLS_DWARF_ARM64_D18 = 82, + CLS_DWARF_ARM64_D19 = 83, + CLS_DWARF_ARM64_D20 = 84, + CLS_DWARF_ARM64_D21 = 85, + CLS_DWARF_ARM64_D22 = 86, + CLS_DWARF_ARM64_D23 = 87, + CLS_DWARF_ARM64_D24 = 88, + CLS_DWARF_ARM64_D25 = 89, + CLS_DWARF_ARM64_D26 = 90, + CLS_DWARF_ARM64_D27 = 91, + CLS_DWARF_ARM64_D28 = 92, + CLS_DWARF_ARM64_D29 = 93, + CLS_DWARF_ARM64_D30 = 94, + CLS_DWARF_ARM64_D31 = 95 +}; + +#define CLS_DWARF_MAX_REGISTER_NUM (CLS_DWARF_ARM64_SP) + +#define CLS_DWARF_REG_RETURN CLS_DWARF_ARM64_LR +#define CLS_DWARF_REG_SP CLS_DWARF_ARM64_SP +#define CLS_DWARF_REG_FP CLS_DWARF_ARM64_FP + +#endif + +#define CLS_DWARF_INVALID_REGISTER_NUM (CLS_DWARF_MAX_REGISTER_NUM + 1) diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.c new file mode 100644 index 0000000..91b2af9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.c @@ -0,0 +1,319 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.h" +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#include +#include +#include + +// Without a limit on the number of frames we unwind, there's a real possibility +// we'll get stuck in an infinite loop. But, we still need pretty big limits, +// because stacks can get quite big. Also, the stacks are different on the platforms. +// These values were empirically determined (~525000 on OS X, ~65000 on iOS). +#if TARGET_OS_EMBEDDED +const uint32_t FIRCLSUnwindMaxFrames = 100000; +#else +const uint32_t FIRCLSUnwindMaxFrames = 600000; +#endif + +const uint32_t FIRCLSUnwindInfiniteRecursionCountThreshold = 10; + +#pragma mark Prototypes +static bool FIRCLSUnwindNextFrameUsingAllStrategies(FIRCLSUnwindContext* context); +#if CLS_COMPACT_UNWINDING_SUPPORTED +static bool FIRCLSUnwindWithCompactUnwindInfo(FIRCLSUnwindContext* context); +#endif +bool FIRCLSUnwindContextHasValidPCAndSP(FIRCLSUnwindContext* context); + +#pragma mark - API +bool FIRCLSUnwindInit(FIRCLSUnwindContext* context, FIRCLSThreadContext threadContext) { + if (!context) { + return false; + } + + memset(context, 0, sizeof(FIRCLSUnwindContext)); + + context->registers = threadContext; + + return true; +} + +bool FIRCLSUnwindNextFrame(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return false; + } + + if (!FIRCLSUnwindContextHasValidPCAndSP(context)) { + // This is a special-case. It is possible to try to unwind a thread that has no stack (ie, is + // executing zero functions. I believe this happens when a thread has exited, but before the + // kernel has actually cleaned it up. This situation can only apply to the first frame. So, in + // that case, we don't count it as an error. But, if it happens mid-unwind, it's a problem. + + if (context->frameCount == 0) { + FIRCLSSDKLog("Cancelling unwind for thread with invalid PC/SP\n"); + } else { + FIRCLSSDKLog("Error: thread PC/SP invalid before unwind\n"); + } + + return false; + } + + if (!FIRCLSUnwindNextFrameUsingAllStrategies(context)) { + FIRCLSSDKLogError("Failed to advance to the next frame\n"); + return false; + } + + uintptr_t pc = FIRCLSUnwindGetPC(context); + uintptr_t sp = FIRCLSUnwindGetStackPointer(context); + + // Unwinding will complete when this is no longer a valid value + if (!FIRCLSIsValidPointer(pc)) { + return false; + } + + // after unwinding, validate that we have a sane register value + if (!FIRCLSIsValidPointer(sp)) { + FIRCLSSDKLog("Error: SP (%p) isn't a valid pointer\n", (void*)sp); + return false; + } + + // track repeating frames + if (context->lastFramePC == pc) { + context->repeatCount += 1; + } else { + context->repeatCount = 0; + } + + context->frameCount += 1; + context->lastFramePC = pc; + + return true; +} + +#pragma mark - Register Accessors +uintptr_t FIRCLSUnwindGetPC(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + return 0; + } + + return FIRCLSThreadContextGetPC(&context->registers); +} + +uintptr_t FIRCLSUnwindGetStackPointer(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + return 0; + } + + return FIRCLSThreadContextGetStackPointer(&context->registers); +} + +static uintptr_t FIRCLSUnwindGetFramePointer(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + return 0; + } + + return FIRCLSThreadContextGetFramePointer(&context->registers); +} + +uint32_t FIRCLSUnwindGetFrameRepeatCount(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + return 0; + } + + return context->repeatCount; +} + +#pragma mark - Unwind Strategies +static bool FIRCLSUnwindNextFrameUsingAllStrategies(FIRCLSUnwindContext* context) { + if (!FIRCLSIsValidPointer(context)) { + FIRCLSSDKLogError("Arguments invalid\n"); + return false; + } + + if (context->frameCount >= FIRCLSUnwindMaxFrames) { + FIRCLSSDKLogWarn("Exceeded maximum number of frames\n"); + return false; + } + + uintptr_t pc = FIRCLSUnwindGetPC(context); + + // Ok, what's going on here? libunwind's UnwindCursor::setInfoBasedOnIPRegister has a + // parameter that, if true, does this subtraction. Despite the comments in the code + // (of 35.1), I found that the parameter was almost always set to true. + // + // I then ran into a problem when unwinding from _pthread_start -> thread_start. This + // is a common transition, which happens in pretty much every report. An extra frame + // was being generated, because the PC we get for _pthread_start was mapping to exactly + // one greater than the function's last byte, according to the compact unwind info. This + // resulted in using the wrong compact encoding, and picking the next function, which + // turned out to be dwarf instead of a frame pointer. + + // So, the moral is - do the subtraction for all frames except the first. I haven't found + // a case where it produces an incorrect result. Also note that at first, I thought this would + // subtract one from the final addresses too. But, the end of this function will *compute* PC, + // so this value is used only to look up unwinding data. + + if (context->frameCount > 0) { + --pc; + if (!FIRCLSThreadContextSetPC(&context->registers, pc)) { + FIRCLSSDKLogError("Unable to set PC\n"); + return false; + } + } + + if (!FIRCLSIsValidPointer(pc)) { + FIRCLSSDKLogError("PC is invalid\n"); + return false; + } + + // the first frame is special - as the registers we need + // are already loaded by definition + if (context->frameCount == 0) { + return true; + } + +#if CLS_COMPACT_UNWINDING_SUPPORTED + // attempt to advance to the next frame using compact unwinding, and + // only fall back to the frame pointer if that fails + if (FIRCLSUnwindWithCompactUnwindInfo(context)) { + return true; + } +#endif + + // If the frame pointer is zero, we cannot use an FP-based unwind and we can reasonably + // assume that we've just gotten to the end of the stack. + if (FIRCLSUnwindGetFramePointer(context) == 0) { + FIRCLSSDKLogWarn("FP is zero, aborting unwind\n"); + // make sure to set the PC to zero, to indicate the unwind is complete + return FIRCLSThreadContextSetPC(&context->registers, 0); + } + + // Only allow stack scanning (as a last resort) if we're on the first frame. All others + // are too likely to screw up. + if (FIRCLSUnwindWithFramePointer(&context->registers, context->frameCount == 1)) { + return true; + } + + FIRCLSSDKLogError("Unable to use frame pointer\n"); + + return false; +} + +#if CLS_COMPACT_UNWINDING_SUPPORTED +static bool FIRCLSUnwindWithCompactUnwindInfo(FIRCLSUnwindContext* context) { + if (!context) { + return false; + } + + // step one - find the image the current pc is within + FIRCLSBinaryImageRuntimeNode image; + + uintptr_t pc = FIRCLSUnwindGetPC(context); + + if (!FIRCLSBinaryImageSafeFindImageForAddress(pc, &image)) { + FIRCLSSDKLogWarn("Unable to find binary for %p\n", (void*)pc); + return false; + } + +#if CLS_BINARY_IMAGE_RUNTIME_NODE_RECORD_NAME + FIRCLSSDKLogDebug("Binary image for %p at %p => %s\n", (void*)pc, image.baseAddress, image.name); +#else + FIRCLSSDKLogDebug("Binary image for %p at %p\n", (void*)pc, image.baseAddress); +#endif + + if (!FIRCLSBinaryImageSafeHasUnwindInfo(&image)) { + FIRCLSSDKLogInfo("Binary image at %p has no unwind info\n", image.baseAddress); + return false; + } + + if (!FIRCLSCompactUnwindInit(&context->compactUnwindState, image.unwindInfo, image.ehFrame, + (uintptr_t)image.baseAddress)) { + FIRCLSSDKLogError("Unable to read unwind info\n"); + return false; + } + + // this function will actually attempt to find compact unwind info for the current PC, + // and use it to mutate the context register state + return FIRCLSCompactUnwindLookupAndCompute(&context->compactUnwindState, &context->registers); +} +#endif + +#pragma mark - Utility Functions +bool FIRCLSUnwindContextHasValidPCAndSP(FIRCLSUnwindContext* context) { + return FIRCLSIsValidPointer(FIRCLSUnwindGetPC(context)) && + FIRCLSIsValidPointer(FIRCLSUnwindGetStackPointer(context)); +} + +#if CLS_CPU_64BIT +#define BASIC_INFO_TYPE vm_region_basic_info_64_t +#define BASIC_INFO VM_REGION_BASIC_INFO_64 +#define BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT_64 +#define vm_region_query_fn vm_region_64 +#else +#define BASIC_INFO_TYPE vm_region_basic_info_t +#define BASIC_INFO VM_REGION_BASIC_INFO +#define BASIC_INFO_COUNT VM_REGION_BASIC_INFO_COUNT +#define vm_region_query_fn vm_region +#endif +bool FIRCLSUnwindIsAddressExecutable(vm_address_t address) { +#if CLS_COMPACT_UNWINDING_SUPPORTED + FIRCLSBinaryImageRuntimeNode unusedNode; + + return FIRCLSBinaryImageSafeFindImageForAddress(address, &unusedNode); +#else + return true; +#endif +} + +bool FIRCLSUnwindFirstExecutableAddress(vm_address_t start, + vm_address_t end, + vm_address_t* foundAddress) { + // This function walks up the data on the stack, looking for the first value that is an address on + // an executable page. This is a heurestic, and can hit false positives. + + *foundAddress = 0; // write in a 0 + + do { + vm_address_t address; + + FIRCLSSDKLogDebug("Checking address %p => %p\n", (void*)start, (void*)*(uintptr_t*)start); + + // if start isn't a valid pointer, don't even bother trying + if (FIRCLSIsValidPointer(start)) { + if (!FIRCLSReadMemory(start, &address, sizeof(void*))) { + // if we fail to read from the stack, we're done + return false; + } + + FIRCLSSDKLogDebug("Checking for executable %p\n", (void*)address); + // when we find an executable address, we're finished + if (FIRCLSUnwindIsAddressExecutable(address)) { + *foundAddress = address; + return true; + } + } + + start += sizeof(void*); // move back up the stack + + } while (start < end); + + return false; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h new file mode 100644 index 0000000..cbf46f9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h @@ -0,0 +1,53 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" +#if CLS_COMPACT_UNWINDING_SUPPORTED +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" +#endif +#include +#include + +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" + +extern const uint32_t FIRCLSUnwindMaxFrames; + +extern const uint32_t FIRCLSUnwindInfiniteRecursionCountThreshold; + +typedef struct { + FIRCLSThreadContext registers; + uint32_t frameCount; +#if CLS_COMPACT_UNWINDING_SUPPORTED + FIRCLSCompactUnwindContext compactUnwindState; +#endif + uintptr_t lastFramePC; + uint32_t repeatCount; +} FIRCLSUnwindContext; + +// API +bool FIRCLSUnwindInit(FIRCLSUnwindContext* context, FIRCLSThreadContext threadContext); + +bool FIRCLSUnwindNextFrame(FIRCLSUnwindContext* context); +uintptr_t FIRCLSUnwindGetPC(FIRCLSUnwindContext* context); +uintptr_t FIRCLSUnwindGetStackPointer(FIRCLSUnwindContext* context); +uint32_t FIRCLSUnwindGetFrameRepeatCount(FIRCLSUnwindContext* context); + +// utility functions +bool FIRCLSUnwindIsAddressExecutable(vm_address_t address); +bool FIRCLSUnwindFirstExecutableAddress(vm_address_t start, + vm_address_t end, + vm_address_t* foundAddress); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h new file mode 100644 index 0000000..714a7ae --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h @@ -0,0 +1,32 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSThreadState.h" +#if CLS_COMPACT_UNWINDING_SUPPORTED +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" +#endif + +bool FIRCLSUnwindWithFramePointer(FIRCLSThreadContext *registers, bool allowScanning); +uintptr_t FIRCLSUnwindStackPointerFromFramePointer(uintptr_t framePtr); + +#if CLS_DWARF_UNWINDING_SUPPORTED +uintptr_t FIRCLSCompactUnwindDwarfOffset(compact_unwind_encoding_t encoding); +bool FIRCLSDwarfUnwindSetRegisterValue(FIRCLSThreadContext *registers, + uint64_t num, + uintptr_t value); +uintptr_t FIRCLSDwarfUnwindGetRegisterValue(const FIRCLSThreadContext *registers, uint64_t num); +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arm.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arm.c new file mode 100644 index 0000000..d97ad39 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arm.c @@ -0,0 +1,313 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#if CLS_CPU_ARM || CLS_CPU_ARM64 + +static bool FIRCLSUnwindWithLRRegister(FIRCLSThreadContext* registers) { + if (!FIRCLSIsValidPointer(registers)) { + return false; + } + + // Return address is in LR, SP is pointing to the next frame. + uintptr_t value = FIRCLSThreadContextGetLinkRegister(registers); + + if (!FIRCLSIsValidPointer(value)) { + FIRCLSSDKLog("Error: LR value is invalid\n"); + return false; + } + + return FIRCLSThreadContextSetPC(registers, value); +} + +bool FIRCLSUnwindWithFramePointer(FIRCLSThreadContext* registers, bool allowScanning) { + if (allowScanning) { + // The LR register does have the return address here, but there are situations where + // this can produce false matches. Better backend rules can fix this up in many cases. + if (FIRCLSUnwindWithLRRegister(registers)) { + return true; + } else { + // In this case, we're unable to use the LR. We don't want to just stop unwinding, so + // proceed with the normal, non-scanning path + FIRCLSSDKLog("Unable to use LR, skipping\n"); + } + } + + // read the values from the stack + const uintptr_t framePointer = FIRCLSThreadContextGetFramePointer(registers); + uintptr_t stack[2]; + + if (!FIRCLSReadMemory((vm_address_t)framePointer, stack, sizeof(stack))) { + // unable to read the first stack frame + FIRCLSSDKLog("Error: failed to read memory at address %p\n", (void*)framePointer); + return false; + } + + if (!FIRCLSThreadContextSetPC(registers, stack[1])) { + return false; + } + + if (!FIRCLSThreadContextSetFramePointer(registers, stack[0])) { + return false; + } + + if (!FIRCLSThreadContextSetStackPointer(registers, + FIRCLSUnwindStackPointerFromFramePointer(framePointer))) { + return false; + } + + return true; +} + +uintptr_t FIRCLSUnwindStackPointerFromFramePointer(uintptr_t framePtr) { + // the stack pointer is the frame pointer plus the two saved pointers for the frame + return framePtr + 2 * sizeof(void*); +} + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSCompactUnwindComputeRegisters(FIRCLSCompactUnwindContext* context, + FIRCLSCompactUnwindResult* result, + FIRCLSThreadContext* registers) { + if (!context || !result || !registers) { + return false; + } + + // Note that compact_uwnind_encoding.h has a few bugs in it prior to iOS 8.0. + // Only refer to the >= 8.0 header. + switch (result->encoding & UNWIND_ARM64_MODE_MASK) { + case UNWIND_ARM64_MODE_FRAMELESS: + // Interestingly, we also know the size of the stack frame, by + // using UNWIND_ARM64_FRAMELESS_STACK_SIZE_MASK. Is that useful? + return FIRCLSUnwindWithLRRegister(registers); + break; + case UNWIND_ARM64_MODE_DWARF: + return FIRCLSCompactUnwindDwarfFrame( + context, result->encoding & UNWIND_ARM64_DWARF_SECTION_OFFSET, registers); + break; + case UNWIND_ARM64_MODE_FRAME: + return FIRCLSUnwindWithFramePointer(registers, false); + default: + FIRCLSSDKLog("Invalid encoding 0x%x\n", result->encoding); + break; + } + + return false; +} +#endif + +#if CLS_DWARF_UNWINDING_SUPPORTED +uintptr_t FIRCLSDwarfUnwindGetRegisterValue(const FIRCLSThreadContext* registers, uint64_t num) { + switch (num) { + case CLS_DWARF_ARM64_X0: + return registers->__ss.__x[0]; + case CLS_DWARF_ARM64_X1: + return registers->__ss.__x[1]; + case CLS_DWARF_ARM64_X2: + return registers->__ss.__x[2]; + case CLS_DWARF_ARM64_X3: + return registers->__ss.__x[3]; + case CLS_DWARF_ARM64_X4: + return registers->__ss.__x[4]; + case CLS_DWARF_ARM64_X5: + return registers->__ss.__x[5]; + case CLS_DWARF_ARM64_X6: + return registers->__ss.__x[6]; + case CLS_DWARF_ARM64_X7: + return registers->__ss.__x[7]; + case CLS_DWARF_ARM64_X8: + return registers->__ss.__x[8]; + case CLS_DWARF_ARM64_X9: + return registers->__ss.__x[9]; + case CLS_DWARF_ARM64_X10: + return registers->__ss.__x[10]; + case CLS_DWARF_ARM64_X11: + return registers->__ss.__x[11]; + case CLS_DWARF_ARM64_X12: + return registers->__ss.__x[12]; + case CLS_DWARF_ARM64_X13: + return registers->__ss.__x[13]; + case CLS_DWARF_ARM64_X14: + return registers->__ss.__x[14]; + case CLS_DWARF_ARM64_X15: + return registers->__ss.__x[15]; + case CLS_DWARF_ARM64_X16: + return registers->__ss.__x[16]; + case CLS_DWARF_ARM64_X17: + return registers->__ss.__x[17]; + case CLS_DWARF_ARM64_X18: + return registers->__ss.__x[18]; + case CLS_DWARF_ARM64_X19: + return registers->__ss.__x[19]; + case CLS_DWARF_ARM64_X20: + return registers->__ss.__x[20]; + case CLS_DWARF_ARM64_X21: + return registers->__ss.__x[21]; + case CLS_DWARF_ARM64_X22: + return registers->__ss.__x[22]; + case CLS_DWARF_ARM64_X23: + return registers->__ss.__x[23]; + case CLS_DWARF_ARM64_X24: + return registers->__ss.__x[24]; + case CLS_DWARF_ARM64_X25: + return registers->__ss.__x[25]; + case CLS_DWARF_ARM64_X26: + return registers->__ss.__x[26]; + case CLS_DWARF_ARM64_X27: + return registers->__ss.__x[27]; + case CLS_DWARF_ARM64_X28: + return registers->__ss.__x[28]; + case CLS_DWARF_ARM64_FP: + return FIRCLSThreadContextGetFramePointer(registers); + case CLS_DWARF_ARM64_LR: + return FIRCLSThreadContextGetLinkRegister(registers); + case CLS_DWARF_ARM64_SP: + return FIRCLSThreadContextGetStackPointer(registers); + default: + break; + } + + FIRCLSSDKLog("Error: Unrecognized get register number %llu\n", num); + + return 0; +} + +bool FIRCLSDwarfUnwindSetRegisterValue(FIRCLSThreadContext* registers, + uint64_t num, + uintptr_t value) { + switch (num) { + case CLS_DWARF_ARM64_X0: + registers->__ss.__x[0] = value; + return true; + case CLS_DWARF_ARM64_X1: + registers->__ss.__x[1] = value; + return true; + case CLS_DWARF_ARM64_X2: + registers->__ss.__x[2] = value; + return true; + case CLS_DWARF_ARM64_X3: + registers->__ss.__x[3] = value; + return true; + case CLS_DWARF_ARM64_X4: + registers->__ss.__x[4] = value; + return true; + case CLS_DWARF_ARM64_X5: + registers->__ss.__x[5] = value; + return true; + case CLS_DWARF_ARM64_X6: + registers->__ss.__x[6] = value; + return true; + case CLS_DWARF_ARM64_X7: + registers->__ss.__x[7] = value; + return true; + case CLS_DWARF_ARM64_X8: + registers->__ss.__x[8] = value; + return true; + case CLS_DWARF_ARM64_X9: + registers->__ss.__x[9] = value; + return true; + case CLS_DWARF_ARM64_X10: + registers->__ss.__x[10] = value; + return true; + case CLS_DWARF_ARM64_X11: + registers->__ss.__x[11] = value; + return true; + case CLS_DWARF_ARM64_X12: + registers->__ss.__x[12] = value; + return true; + case CLS_DWARF_ARM64_X13: + registers->__ss.__x[13] = value; + return true; + case CLS_DWARF_ARM64_X14: + registers->__ss.__x[14] = value; + return true; + case CLS_DWARF_ARM64_X15: + registers->__ss.__x[15] = value; + return true; + case CLS_DWARF_ARM64_X16: + registers->__ss.__x[16] = value; + return true; + case CLS_DWARF_ARM64_X17: + registers->__ss.__x[17] = value; + return true; + case CLS_DWARF_ARM64_X18: + registers->__ss.__x[18] = value; + return true; + case CLS_DWARF_ARM64_X19: + registers->__ss.__x[19] = value; + return true; + case CLS_DWARF_ARM64_X20: + registers->__ss.__x[20] = value; + return true; + case CLS_DWARF_ARM64_X21: + registers->__ss.__x[21] = value; + return true; + case CLS_DWARF_ARM64_X22: + registers->__ss.__x[22] = value; + return true; + case CLS_DWARF_ARM64_X23: + registers->__ss.__x[23] = value; + return true; + case CLS_DWARF_ARM64_X24: + registers->__ss.__x[24] = value; + return true; + case CLS_DWARF_ARM64_X25: + registers->__ss.__x[25] = value; + return true; + case CLS_DWARF_ARM64_X26: + registers->__ss.__x[26] = value; + return true; + case CLS_DWARF_ARM64_X27: + registers->__ss.__x[27] = value; + return true; + case CLS_DWARF_ARM64_X28: + registers->__ss.__x[28] = value; + return true; + case CLS_DWARF_ARM64_FP: + FIRCLSThreadContextSetFramePointer(registers, value); + return true; + case CLS_DWARF_ARM64_SP: + FIRCLSThreadContextSetStackPointer(registers, value); + return true; + case CLS_DWARF_ARM64_LR: + // Here's what's going on. For x86, the "return register" is virtual. The architecture + // doesn't actually have one, but DWARF does have the concept. So, when the system + // tries to set the return register, we set the PC. You can see this behavior + // in the FIRCLSDwarfUnwindSetRegisterValue implementation for that architecture. In the + // case of ARM64, the register is real. So, we have to be extra careful to make sure + // we update the PC here. Otherwise, when a DWARF unwind completes, it won't have + // changed the PC to the right value. + FIRCLSThreadContextSetLinkRegister(registers, value); + FIRCLSThreadContextSetPC(registers, value); + return true; + default: + break; + } + + FIRCLSSDKLog("Unrecognized set register number %llu\n", num); + + return false; +} +#endif + +#else +INJECT_STRIP_SYMBOL(unwind_arm) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.c b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.c new file mode 100644 index 0000000..1279905 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.c @@ -0,0 +1,537 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.h" +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind_Private.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" +#include "Crashlytics/Crashlytics/Unwind/Dwarf/FIRCLSDwarfUnwind.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind.h" +#include "Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_arch.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h" + +#if CLS_CPU_X86 + +static bool FIRCLSCompactUnwindBPFrame(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers); +static bool FIRCLSCompactUnwindFrameless(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers, + uintptr_t functionStart, + bool indirect); + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSCompactUnwindComputeRegisters(FIRCLSCompactUnwindContext* context, + FIRCLSCompactUnwindResult* result, + FIRCLSThreadContext* registers) { + if (!FIRCLSIsValidPointer(context) || !FIRCLSIsValidPointer(result) || + !FIRCLSIsValidPointer(registers)) { + FIRCLSSDKLogError("invalid inputs\n"); + return false; + } + + FIRCLSSDKLogDebug("Computing registers for encoding %x\n", result->encoding); + + switch (result->encoding & CLS_X86_MODE_MASK) { + case CLS_X86_MODE_BP_FRAME: + return FIRCLSCompactUnwindBPFrame(result->encoding, registers); + case CLS_X86_MODE_STACK_IMMD: + return FIRCLSCompactUnwindFrameless(result->encoding, registers, result->functionStart, + false); + case CLS_X86_MODE_STACK_IND: + return FIRCLSCompactUnwindFrameless(result->encoding, registers, result->functionStart, true); + case CLS_X86_MODE_DWARF: + return FIRCLSCompactUnwindDwarfFrame(context, result->encoding & CLS_X86_DWARF_SECTION_OFFSET, + registers); + default: + FIRCLSSDKLogError("Invalid encoding %x\n", result->encoding); + break; + } + + return false; +} +#endif + +static bool FIRCLSCompactUnwindBPFrame(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers) { + // this is the plain-vanilla frame pointer process + + // uint32_t offset = GET_BITS_WITH_MASK(encoding, UNWIND_X86_EBP_FRAME_OFFSET); + // uint32_t locations = GET_BITS_WITH_MASK(encoding, UNWIND_X86_64_RBP_FRAME_REGISTERS); + + // TODO: pretty sure we do need to restore registers here, so that if a subsequent frame needs + // these results, they will be correct + + // Checkout CompactUnwinder.hpp in libunwind for how to do this. Since we don't make use of any of + // those registers for a stacktrace only, there's nothing we need do with them. + + // read the values from the stack + const uintptr_t framePointer = FIRCLSThreadContextGetFramePointer(registers); + uintptr_t stack[2]; + + if (!FIRCLSReadMemory((vm_address_t)framePointer, stack, sizeof(stack))) { + // unable to read the first stack frame + FIRCLSSDKLog("Error: failed to read memory at address %p\n", (void*)framePointer); + return false; + } + + if (!FIRCLSThreadContextSetPC(registers, stack[1])) { + return false; + } + + if (!FIRCLSThreadContextSetFramePointer(registers, stack[0])) { + return false; + } + + if (!FIRCLSThreadContextSetStackPointer(registers, + FIRCLSUnwindStackPointerFromFramePointer(framePointer))) { + return false; + } + + return true; +} + +bool FIRCLSUnwindWithStackScanning(FIRCLSThreadContext* registers) { + vm_address_t start = (vm_address_t)FIRCLSThreadContextGetStackPointer(registers); + vm_address_t end = (vm_address_t)FIRCLSThreadContextGetFramePointer(registers); + + uintptr_t newPC = 0; + + if (!FIRCLSUnwindFirstExecutableAddress(start, end, (vm_address_t*)&newPC)) { + return false; + } + + return FIRCLSThreadContextSetPC(registers, newPC); +} + +bool FIRCLSUnwindWithFramePointer(FIRCLSThreadContext* registers, bool allowScanning) { + // Here's an interesting case. We've just processed the first frame, and it did + // not have any unwind info. If that first function did not allocate + // a stack frame, we'll "skip" the caller. This might sound unlikely, but it actually + // happens a lot in practice. + + // Sooo, one thing we can do is try to stack the stack for things that look like return + // addresses. Normally, this technique will hit many false positives. But, if we do it + // only for the second frame, and only when we don't have other unwind info available. + + if (allowScanning) { + FIRCLSSDKLogInfo("Attempting stack scan\n"); + if (FIRCLSUnwindWithStackScanning(registers)) { + FIRCLSSDKLogInfo("Stack scan successful\n"); + return true; + } + } + + // If we ever do anything else with the encoding, we need to be sure + // to set it up right. + return FIRCLSCompactUnwindBPFrame(CLS_X86_MODE_BP_FRAME, registers); +} + +uintptr_t FIRCLSUnwindStackPointerFromFramePointer(uintptr_t framePtr) { + // the stack pointer is the frame pointer plus the two saved pointers for the frame + return framePtr + 2 * sizeof(void*); +} + +#if CLS_COMPACT_UNWINDING_SUPPORTED || CLS_DWARF_UNWINDING_SUPPORTED +uintptr_t FIRCLSDwarfUnwindGetRegisterValue(const FIRCLSThreadContext* registers, uint64_t num) { + switch (num) { +#if CLS_CPU_X86_64 + case CLS_DWARF_X86_64_RAX: + return registers->__ss.__rax; + case CLS_DWARF_X86_64_RDX: + return registers->__ss.__rdx; + case CLS_DWARF_X86_64_RCX: + return registers->__ss.__rcx; + case CLS_DWARF_X86_64_RBX: + return registers->__ss.__rbx; + case CLS_DWARF_X86_64_RSI: + return registers->__ss.__rsi; + case CLS_DWARF_X86_64_RDI: + return registers->__ss.__rdi; + case CLS_DWARF_X86_64_RBP: + return registers->__ss.__rbp; + case CLS_DWARF_X86_64_RSP: + return registers->__ss.__rsp; + case CLS_DWARF_X86_64_R8: + return registers->__ss.__r8; + case CLS_DWARF_X86_64_R9: + return registers->__ss.__r9; + case CLS_DWARF_X86_64_R10: + return registers->__ss.__r10; + case CLS_DWARF_X86_64_R11: + return registers->__ss.__r11; + case CLS_DWARF_X86_64_R12: + return registers->__ss.__r12; + case CLS_DWARF_X86_64_R13: + return registers->__ss.__r13; + case CLS_DWARF_X86_64_R14: + return registers->__ss.__r14; + case CLS_DWARF_X86_64_R15: + return registers->__ss.__r15; + case CLS_DWARF_X86_64_RET_ADDR: + return registers->__ss.__rip; +#elif CLS_CPU_I386 + case CLS_DWARF_X86_EAX: + return registers->__ss.__eax; + case CLS_DWARF_X86_ECX: + return registers->__ss.__ecx; + case CLS_DWARF_X86_EDX: + return registers->__ss.__edx; + case CLS_DWARF_X86_EBX: + return registers->__ss.__ebx; + case CLS_DWARF_X86_EBP: + return registers->__ss.__ebp; + case CLS_DWARF_X86_ESP: + return registers->__ss.__esp; + case CLS_DWARF_X86_ESI: + return registers->__ss.__esi; + case CLS_DWARF_X86_EDI: + return registers->__ss.__edi; + case CLS_DWARF_X86_RET_ADDR: + return registers->__ss.__eip; +#endif + default: + break; + } + + FIRCLSSDKLog("Error: Unrecognized get register number %llu\n", num); + + return 0; +} + +bool FIRCLSDwarfUnwindSetRegisterValue(FIRCLSThreadContext* registers, + uint64_t num, + uintptr_t value) { + switch (num) { +#if CLS_CPU_X86_64 + case CLS_DWARF_X86_64_RAX: + registers->__ss.__rax = value; + return true; + case CLS_DWARF_X86_64_RDX: + registers->__ss.__rdx = value; + return true; + case CLS_DWARF_X86_64_RCX: + registers->__ss.__rcx = value; + return true; + case CLS_DWARF_X86_64_RBX: + registers->__ss.__rbx = value; + return true; + case CLS_DWARF_X86_64_RSI: + registers->__ss.__rsi = value; + return true; + case CLS_DWARF_X86_64_RDI: + registers->__ss.__rdi = value; + return true; + case CLS_DWARF_X86_64_RBP: + registers->__ss.__rbp = value; + return true; + case CLS_DWARF_X86_64_RSP: + registers->__ss.__rsp = value; + return true; + case CLS_DWARF_X86_64_R8: + registers->__ss.__r8 = value; + return true; + case CLS_DWARF_X86_64_R9: + registers->__ss.__r9 = value; + return true; + case CLS_DWARF_X86_64_R10: + registers->__ss.__r10 = value; + return true; + case CLS_DWARF_X86_64_R11: + registers->__ss.__r11 = value; + return true; + case CLS_DWARF_X86_64_R12: + registers->__ss.__r12 = value; + return true; + case CLS_DWARF_X86_64_R13: + registers->__ss.__r13 = value; + return true; + case CLS_DWARF_X86_64_R14: + registers->__ss.__r14 = value; + return true; + case CLS_DWARF_X86_64_R15: + registers->__ss.__r15 = value; + return true; + case CLS_DWARF_X86_64_RET_ADDR: + registers->__ss.__rip = value; + return true; +#elif CLS_CPU_I386 + case CLS_DWARF_X86_EAX: + registers->__ss.__eax = value; + return true; + case CLS_DWARF_X86_ECX: + registers->__ss.__ecx = value; + return true; + case CLS_DWARF_X86_EDX: + registers->__ss.__edx = value; + return true; + case CLS_DWARF_X86_EBX: + registers->__ss.__ebx = value; + return true; + case CLS_DWARF_X86_EBP: + registers->__ss.__ebp = value; + return true; + case CLS_DWARF_X86_ESP: + registers->__ss.__esp = value; + return true; + case CLS_DWARF_X86_ESI: + registers->__ss.__esi = value; + return true; + case CLS_DWARF_X86_EDI: + registers->__ss.__edi = value; + return true; + case CLS_DWARF_X86_RET_ADDR: + registers->__ss.__eip = value; + return true; +#endif + default: + break; + } + + FIRCLSSDKLog("Unrecognized set register number %llu\n", num); + + return false; +} +#endif + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSCompactUnwindComputeStackSize(const compact_unwind_encoding_t encoding, + const uintptr_t functionStart, + const bool indirect, + uint32_t* const stackSize) { + if (!FIRCLSIsValidPointer(stackSize)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return false; + } + + const uint32_t stackSizeEncoded = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_SIZE); + + if (!indirect) { + *stackSize = stackSizeEncoded * sizeof(void*); + return true; + } + + const vm_address_t sublAddress = functionStart + stackSizeEncoded; + uint32_t sublValue = 0; + + if (!FIRCLSReadMemory(sublAddress, &sublValue, sizeof(uint32_t))) { + FIRCLSSDKLog("Error: unable to read subl value\n"); + return false; + } + + const uint32_t stackAdjust = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_ADJUST); + + *stackSize = sublValue + stackAdjust * sizeof(void*); + + return true; +} + +bool FIRCLSCompactUnwindDecompressPermutation(const compact_unwind_encoding_t encoding, + uintptr_t permutatedRegisters[const static 6]) { + const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT); + uint32_t permutation = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_PERMUTATION); + + switch (regCount) { + case 6: + permutatedRegisters[0] = permutation / 120; + permutation -= (permutatedRegisters[0] * 120); + permutatedRegisters[1] = permutation / 24; + permutation -= (permutatedRegisters[1] * 24); + permutatedRegisters[2] = permutation / 6; + permutation -= (permutatedRegisters[2] * 6); + permutatedRegisters[3] = permutation / 2; + permutation -= (permutatedRegisters[3] * 2); + permutatedRegisters[4] = permutation; + permutatedRegisters[5] = 0; + break; + case 5: + permutatedRegisters[0] = permutation / 120; + permutation -= (permutatedRegisters[0] * 120); + permutatedRegisters[1] = permutation / 24; + permutation -= (permutatedRegisters[1] * 24); + permutatedRegisters[2] = permutation / 6; + permutation -= (permutatedRegisters[2] * 6); + permutatedRegisters[3] = permutation / 2; + permutation -= (permutatedRegisters[3] * 2); + permutatedRegisters[4] = permutation; + break; + case 4: + permutatedRegisters[0] = permutation / 60; + permutation -= (permutatedRegisters[0] * 60); + permutatedRegisters[1] = permutation / 12; + permutation -= (permutatedRegisters[1] * 12); + permutatedRegisters[2] = permutation / 3; + permutation -= (permutatedRegisters[2] * 3); + permutatedRegisters[3] = permutation; + break; + case 3: + permutatedRegisters[0] = permutation / 20; + permutation -= (permutatedRegisters[0] * 20); + permutatedRegisters[1] = permutation / 4; + permutation -= (permutatedRegisters[1] * 4); + permutatedRegisters[2] = permutation; + break; + case 2: + permutatedRegisters[0] = permutation / 5; + permutation -= (permutatedRegisters[0] * 5); + permutatedRegisters[1] = permutation; + break; + case 1: + permutatedRegisters[0] = permutation; + break; + case 0: + break; + default: + FIRCLSSDKLog("Error: unhandled number of register permutations for encoding %x\n", encoding); + return false; + } + + return true; +} + +bool FIRCLSCompactUnwindRemapRegisters(const compact_unwind_encoding_t encoding, + uintptr_t permutatedRegisters[const static 6], + uintptr_t savedRegisters[const static 6]) { + const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT); + + if (regCount > 6) { + FIRCLSSDKLog("Error: invalid register number count %d\n", regCount); + return false; + } + + // Re-number the registers + + // You are probably wondering, what the hell is this algorithm even doing? It is + // taken from libunwind's implementation that does the same thing. + bool used[7] = {false, false, false, false, false, false, false}; + for (uint32_t i = 0; i < regCount; ++i) { + int renum = 0; + for (int u = 1; u < 7; ++u) { + if (!used[u]) { + if (renum == permutatedRegisters[i]) { + savedRegisters[i] = u; + used[u] = true; + break; + } + ++renum; + } + } + } + + return true; +} + +bool FIRCLSCompactUnwindRestoreRegisters(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers, + uint32_t stackSize, + const uintptr_t savedRegisters[const static 6], + uintptr_t* address) { + if (!FIRCLSIsValidPointer(registers) || !FIRCLSIsValidPointer(address)) { + FIRCLSSDKLog("Error: invalid inputs\n"); + return false; + } + + const uint32_t regCount = GET_BITS_WITH_MASK(encoding, CLS_X86_FRAMELESS_STACK_REG_COUNT); + + // compute initial address of saved registers + *address = FIRCLSThreadContextGetStackPointer(registers) + stackSize - sizeof(void*) - + sizeof(void*) * regCount; + uintptr_t value = 0; + + for (uint32_t i = 0; i < regCount; ++i) { + value = 0; + + switch (savedRegisters[i]) { + case CLS_X86_REG_RBP: + if (!FIRCLSReadMemory((vm_address_t)*address, (void*)&value, sizeof(uintptr_t))) { + FIRCLSSDKLog("Error: unable to read memory to set register\n"); + return false; + } + + if (!FIRCLSThreadContextSetFramePointer(registers, value)) { + FIRCLSSDKLog("Error: unable to set FP\n"); + return false; + } + break; + default: + // here, we are restoring a register we don't need for unwinding + FIRCLSSDKLog("Error: skipping a restore of register %d at %p\n", (int)savedRegisters[i], + (void*)*address); + break; + } + + *address += sizeof(void*); + } + + return true; +} + +static bool FIRCLSCompactUnwindFrameless(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers, + uintptr_t functionStart, + bool indirect) { + FIRCLSSDKLog("Frameless unwind encountered with encoding %x\n", encoding); + + uint32_t stackSize = 0; + if (!FIRCLSCompactUnwindComputeStackSize(encoding, functionStart, indirect, &stackSize)) { + FIRCLSSDKLog("Error: unable to compute stack size for encoding %x\n", encoding); + return false; + } + + uintptr_t permutatedRegisters[6]; + + memset(permutatedRegisters, 0, sizeof(permutatedRegisters)); + if (!FIRCLSCompactUnwindDecompressPermutation(encoding, permutatedRegisters)) { + FIRCLSSDKLog("Error: unable to decompress registers %x\n", encoding); + return false; + } + + uintptr_t savedRegisters[6]; + + memset(savedRegisters, 0, sizeof(savedRegisters)); + if (!FIRCLSCompactUnwindRemapRegisters(encoding, permutatedRegisters, savedRegisters)) { + FIRCLSSDKLog("Error: unable to remap registers %x\n", encoding); + return false; + } + + uintptr_t address = 0; + + if (!FIRCLSCompactUnwindRestoreRegisters(encoding, registers, stackSize, savedRegisters, + &address)) { + FIRCLSSDKLog("Error: unable to restore registers\n"); + return false; + } + + FIRCLSSDKLog("SP is %p and we are reading %p\n", + (void*)FIRCLSThreadContextGetStackPointer(registers), (void*)address); + // read the value from the stack, now that we know the address to read + uintptr_t value = 0; + if (!FIRCLSReadMemory((vm_address_t)address, (void*)&value, sizeof(uintptr_t))) { + FIRCLSSDKLog("Error: unable to read memory to set register\n"); + return false; + } + + FIRCLSSDKLog("Read PC to be %p\n", (void*)value); + if (!FIRCLSIsValidPointer(value)) { + FIRCLSSDKLog("Error: computed PC is invalid\n"); + return false; + } + + return FIRCLSThreadContextSetPC(registers, value) && + FIRCLSThreadContextSetStackPointer(registers, address + sizeof(void*)); +} +#endif + +#else +INJECT_STRIP_SYMBOL(unwind_x86) +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.h b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.h new file mode 100644 index 0000000..849da28 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Crashlytics/Unwind/FIRCLSUnwind_x86.h @@ -0,0 +1,76 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h" +#include "Crashlytics/Crashlytics/Unwind/Compact/FIRCLSCompactUnwind.h" + +// Add some abstraction to compact unwinding, because compact +// unwinding is nearly identical between 32 and 64 bit +#if CLS_CPU_X86_64 + +#define CLS_X86_MODE_MASK UNWIND_X86_64_MODE_MASK +#define CLS_X86_MODE_BP_FRAME UNWIND_X86_64_MODE_RBP_FRAME +#define CLS_X86_MODE_STACK_IMMD UNWIND_X86_64_MODE_STACK_IMMD +#define CLS_X86_MODE_STACK_IND UNWIND_X86_64_MODE_STACK_IND +#define CLS_X86_MODE_DWARF UNWIND_X86_64_MODE_DWARF + +#define CLS_X86_BP_FRAME_REGISTERS UNWIND_X86_64_RBP_FRAME_REGISTERS +#define CLS_X86_BP_FRAME_OFFSET UNWIND_X86_64_RBP_FRAME_OFFSET + +#define CLS_X86_FRAMELESS_STACK_SIZE UNWIND_X86_64_FRAMELESS_STACK_SIZE +#define CLS_X86_FRAMELESS_STACK_ADJUST UNWIND_X86_64_FRAMELESS_STACK_ADJUST +#define CLS_X86_FRAMELESS_STACK_REG_COUNT UNWIND_X86_64_FRAMELESS_STACK_REG_COUNT +#define CLS_X86_FRAMELESS_STACK_REG_PERMUTATION UNWIND_X86_64_FRAMELESS_STACK_REG_PERMUTATION + +#define CLS_X86_DWARF_SECTION_OFFSET UNWIND_X86_64_DWARF_SECTION_OFFSET + +#define CLS_X86_REG_RBP UNWIND_X86_64_REG_RBP + +#else + +#define CLS_X86_MODE_MASK UNWIND_X86_MODE_MASK +#define CLS_X86_MODE_BP_FRAME UNWIND_X86_MODE_EBP_FRAME +#define CLS_X86_MODE_STACK_IMMD UNWIND_X86_MODE_STACK_IMMD +#define CLS_X86_MODE_STACK_IND UNWIND_X86_MODE_STACK_IND +#define CLS_X86_MODE_DWARF UNWIND_X86_MODE_DWARF + +#define CLS_X86_BP_FRAME_REGISTERS UNWIND_X86_RBP_FRAME_REGISTERS +#define CLS_X86_BP_FRAME_OFFSET UNWIND_X86_RBP_FRAME_OFFSET + +#define CLS_X86_FRAMELESS_STACK_SIZE UNWIND_X86_FRAMELESS_STACK_SIZE +#define CLS_X86_FRAMELESS_STACK_ADJUST UNWIND_X86_FRAMELESS_STACK_ADJUST +#define CLS_X86_FRAMELESS_STACK_REG_COUNT UNWIND_X86_FRAMELESS_STACK_REG_COUNT +#define CLS_X86_FRAMELESS_STACK_REG_PERMUTATION UNWIND_X86_FRAMELESS_STACK_REG_PERMUTATION + +#define CLS_X86_DWARF_SECTION_OFFSET UNWIND_X86_DWARF_SECTION_OFFSET + +#define CLS_X86_REG_RBP UNWIND_X86_REG_EBP + +#endif + +#if CLS_COMPACT_UNWINDING_SUPPORTED +bool FIRCLSCompactUnwindComputeStackSize(const compact_unwind_encoding_t encoding, + const uintptr_t functionStart, + const bool indirect, + uint32_t* const stackSize); +bool FIRCLSCompactUnwindDecompressPermutation(const compact_unwind_encoding_t encoding, + uintptr_t permutatedRegisters[const static 6]); +bool FIRCLSCompactUnwindRestoreRegisters(compact_unwind_encoding_t encoding, + FIRCLSThreadContext* registers, + uint32_t stackSize, + const uintptr_t savedRegisters[const static 6], + uintptr_t* address); +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/LICENSE b/Pods/FirebaseCrashlytics/Crashlytics/LICENSE new file mode 100644 index 0000000..925bc57 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/LICENSE @@ -0,0 +1,230 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +The following copyright from Hewlett-Packard Development Company, L.P. +applies to the dwarf.h file in third_party/libunwind + + libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.c b/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.c new file mode 100644 index 0000000..cb88acc --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.c @@ -0,0 +1,80 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "Crashlytics/Protogen/nanopb/crashlytics.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t google_crashlytics_Report_fields[11] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_crashlytics_Report, sdk_version, sdk_version, 0), + PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, gmp_app_id, sdk_version, 0), + PB_FIELD( 4, UENUM , SINGULAR, STATIC , OTHER, google_crashlytics_Report, platform, gmp_app_id, 0), + PB_FIELD( 5, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, installation_uuid, platform, 0), + PB_FIELD( 6, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, build_version, installation_uuid, 0), + PB_FIELD( 7, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, display_version, build_version, 0), + PB_FIELD( 10, MESSAGE , SINGULAR, STATIC , OTHER, google_crashlytics_Report, apple_payload, display_version, &google_crashlytics_FilesPayload_fields), + PB_FIELD( 16, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, firebase_installation_id, apple_payload, 0), + PB_FIELD( 17, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, app_quality_session_id, firebase_installation_id, 0), + PB_FIELD( 19, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_Report, firebase_authentication_token, app_quality_session_id, 0), + PB_LAST_FIELD +}; + +const pb_field_t google_crashlytics_FilesPayload_fields[2] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, google_crashlytics_FilesPayload, files, files, &google_crashlytics_FilesPayload_File_fields), + PB_LAST_FIELD +}; + +const pb_field_t google_crashlytics_FilesPayload_File_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, google_crashlytics_FilesPayload_File, filename, filename, 0), + PB_FIELD( 2, BYTES , SINGULAR, POINTER , OTHER, google_crashlytics_FilesPayload_File, contents, filename, 0), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_crashlytics_Report, apple_payload) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_google_crashlytics_Report_google_crashlytics_FilesPayload_google_crashlytics_FilesPayload_File) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(google_crashlytics_Report, apple_payload) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_google_crashlytics_Report_google_crashlytics_FilesPayload_google_crashlytics_FilesPayload_File) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.h b/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.h new file mode 100644 index 0000000..4ad4f89 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Protogen/nanopb/crashlytics.nanopb.h @@ -0,0 +1,113 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GOOGLE_CRASHLYTICS_CRASHLYTICS_NANOPB_H_INCLUDED +#define PB_GOOGLE_CRASHLYTICS_CRASHLYTICS_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _google_crashlytics_Platforms { + google_crashlytics_Platforms_UNKNOWN_PLATFORM = 0, + google_crashlytics_Platforms_IOS = 1, + google_crashlytics_Platforms_TVOS = 2, + google_crashlytics_Platforms_MAC_OS_X = 5 +} google_crashlytics_Platforms; +#define _google_crashlytics_Platforms_MIN google_crashlytics_Platforms_UNKNOWN_PLATFORM +#define _google_crashlytics_Platforms_MAX google_crashlytics_Platforms_MAC_OS_X +#define _google_crashlytics_Platforms_ARRAYSIZE ((google_crashlytics_Platforms)(google_crashlytics_Platforms_MAC_OS_X+1)) + +/* Struct definitions */ +typedef struct _google_crashlytics_FilesPayload { + pb_size_t files_count; + struct _google_crashlytics_FilesPayload_File *files; +/* @@protoc_insertion_point(struct:google_crashlytics_FilesPayload) */ +} google_crashlytics_FilesPayload; + +typedef struct _google_crashlytics_FilesPayload_File { + pb_bytes_array_t *filename; + pb_bytes_array_t *contents; +/* @@protoc_insertion_point(struct:google_crashlytics_FilesPayload_File) */ +} google_crashlytics_FilesPayload_File; + +typedef struct _google_crashlytics_Report { + pb_bytes_array_t *sdk_version; + pb_bytes_array_t *gmp_app_id; + google_crashlytics_Platforms platform; + pb_bytes_array_t *installation_uuid; + pb_bytes_array_t *build_version; + pb_bytes_array_t *display_version; + google_crashlytics_FilesPayload apple_payload; + pb_bytes_array_t *firebase_installation_id; + pb_bytes_array_t *app_quality_session_id; + pb_bytes_array_t *firebase_authentication_token; +/* @@protoc_insertion_point(struct:google_crashlytics_Report) */ +} google_crashlytics_Report; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define google_crashlytics_Report_init_default {NULL, NULL, _google_crashlytics_Platforms_MIN, NULL, NULL, NULL, google_crashlytics_FilesPayload_init_default, NULL, NULL} +#define google_crashlytics_FilesPayload_init_default {0, NULL} +#define google_crashlytics_FilesPayload_File_init_default {NULL, NULL} +#define google_crashlytics_Report_init_zero {NULL, NULL, _google_crashlytics_Platforms_MIN, NULL, NULL, NULL, google_crashlytics_FilesPayload_init_zero, NULL, NULL} +#define google_crashlytics_FilesPayload_init_zero {0, NULL} +#define google_crashlytics_FilesPayload_File_init_zero {NULL, NULL} + +/* Field tags (for use in manual encoding/decoding) */ +#define google_crashlytics_FilesPayload_files_tag 1 +#define google_crashlytics_FilesPayload_File_filename_tag 1 +#define google_crashlytics_FilesPayload_File_contents_tag 2 +#define google_crashlytics_Report_sdk_version_tag 1 +#define google_crashlytics_Report_gmp_app_id_tag 3 +#define google_crashlytics_Report_platform_tag 4 +#define google_crashlytics_Report_installation_uuid_tag 5 +#define google_crashlytics_Report_firebase_installation_id_tag 16 +#define google_crashlytics_Report_app_quality_session_id_tag 17 +#define google_crashlytics_Report_firebase_authentication_token 19 +#define google_crashlytics_Report_build_version_tag 6 +#define google_crashlytics_Report_display_version_tag 7 +#define google_crashlytics_Report_apple_payload_tag 10 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t google_crashlytics_Report_fields[11]; +extern const pb_field_t google_crashlytics_FilesPayload_fields[2]; +extern const pb_field_t google_crashlytics_FilesPayload_File_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* google_crashlytics_Report_size depends on runtime parameters */ +/* google_crashlytics_FilesPayload_size depends on runtime parameters */ +/* google_crashlytics_FilesPayload_File_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CRASHLYTICS_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/FirebaseCrashlytics/Crashlytics/README.md b/Pods/FirebaseCrashlytics/Crashlytics/README.md new file mode 100644 index 0000000..55d36e6 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/README.md @@ -0,0 +1,39 @@ +# Firebase Crashlytics SDK + +## Development + +Follow the subsequent instructions to develop, debug, unit test, and +integration test FirebaseCrashlytics: + +### Prereqs + +- At least CocoaPods 1.6.0 +- Install [cocoapods-generate](https://github.com/square/cocoapods-generate) +- For nanopb and GDT: + - `brew install protobuf nanopb-generator` + - `easy_install protobuf python` + +### To Develop + +- Run `Crashlytics/generate_project.sh` +- `open gen/FirebaseCrashlytics/FirebaseCrashlytics.xcworkspace` + +You're now in an Xcode workspace generate for building, debugging and +testing the FirebaseCrashlytics CocoaPod. + +### Running Unit Tests + +Open the generated workspace, choose the FirebaseCrashlytics-Unit-unit scheme and press Command-u. + +### Changing crash report uploads (using GDT) + +#### Update report proto + +If the crash report proto needs to be updated, follow these instructions: + +- Update `ProtoSupport/Protos/crashlytics.proto` with the new changes +- Depending on the type of fields added/removed, also update `ProtoSupport/Protos/crashlytics.options`. + `CALLBACK` type fields in crashlytics.nanopb.c needs to be changed to `POINTER` + (through the options file). Known field types that require an entry in crashlytics.options are + `strings`, `repeated` and `bytes`. +- Run `generate_project.sh` to update the nanopb .c/.h files. \ No newline at end of file diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseCrashlytics/Crashlytics/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..410a473 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,49 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeCrashData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAppFunctionality + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + CA92.1 + + + + + \ No newline at end of file diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.h new file mode 100644 index 0000000..17758b3 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.h @@ -0,0 +1,41 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Returns a SHA1 Hash of the input `Data` + */ +NSString *FIRCLSHashNSData(NSData *data); +/** + * Returns a SHA256 Hash of the input `Data` + */ +NSString *FIRCLS256HashNSData(NSData *data); +/** + * Returns a SHA1 Hash of the input bytes + */ +NSString *FIRCLSHashBytes(const void *bytes, size_t length); +/** + * Populates a Hex value conversion of value into outputBuffer. + * If value is nil, then outputBuffer is not modified. + */ +void FIRCLSSafeHexToString(const uint8_t *value, size_t length, char *outputBuffer); + +/** + * Iterates through the raw bytes of data in a way that is similar to + * `Data`'s `enumerateBytes(_ block:)`, but is safe to call from older + * OSes that do not support it. + */ +void FIRCLSEnumerateByteRangesOfNSDataUsingBlock( + NSData *data, void (^block)(const void *bytes, NSRange byteRange, BOOL *stop)); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.m new file mode 100644 index 0000000..8298bf1 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSByteUtility.m @@ -0,0 +1,120 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSByteUtility.h" + +#import +#import + +#pragma mark Private functions + +static const char FIRCLSHexMap[] = "0123456789abcdef"; + +void FIRCLSHexFromByte(uint8_t c, char output[]) { + if (!output) { + return; + } + + output[0] = FIRCLSHexMap[c >> 4]; + output[1] = FIRCLSHexMap[c & 0x0f]; +} + +void FIRCLSSafeHexToString(const uint8_t *value, size_t length, char *outputBuffer) { + if (!outputBuffer) { + return; + } + + memset(outputBuffer, 0, (length * 2) + 1); + + if (!value) { + return; + } + + for (size_t i = 0; i < length; ++i) { + uint8_t c = value[i]; + + FIRCLSHexFromByte(c, &outputBuffer[i * 2]); + } +} + +NSString *FIRCLSNSDataPrettyDescription(NSData *data) { + NSString *string; + char *buffer; + size_t size; + NSUInteger length; + + // we need 2 hex char for every byte of data, plus one more spot for a + // null terminator + length = data.length; + size = (length * 2) + 1; + buffer = malloc(sizeof(char) * size); + + if (!buffer) { + return nil; + } + + FIRCLSSafeHexToString(data.bytes, length, buffer); + + string = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return string; +} + +#pragma mark Public functions + +NSString *FIRCLSHashBytes(const void *bytes, size_t length) { + uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; + CC_SHA1(bytes, (CC_LONG)length, digest); + + NSData *result = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; + + return FIRCLSNSDataPrettyDescription(result); +} + +NSString *FIRCLSHashNSData(NSData *data) { + return FIRCLSHashBytes(data.bytes, data.length); +} + +NSString *FIRCLS256HashBytes(const void *bytes, size_t length) { + uint8_t digest[CC_SHA256_DIGEST_LENGTH] = {0}; + CC_SHA256(bytes, (CC_LONG)length, digest); + + NSData *result = [NSData dataWithBytes:digest length:CC_SHA256_DIGEST_LENGTH]; + + return FIRCLSNSDataPrettyDescription(result); +} + +NSString *FIRCLS256HashNSData(NSData *data) { + return FIRCLS256HashBytes(data.bytes, data.length); +} + +void FIRCLSEnumerateByteRangesOfNSDataUsingBlock( + NSData *data, void (^block)(const void *bytes, NSRange byteRange, BOOL *stop)) { + if ([data respondsToSelector:@selector(enumerateByteRangesUsingBlock:)]) { + [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) { + block(bytes, byteRange, stop); + }]; + + return; + } + + // Fall back to the less-efficient mechanism for older OSes. Safe + // to ignore the return value of stop, since we'll only ever + // call this once anyways + BOOL stop = NO; + + block(data.bytes, NSMakeRange(0, data.length), &stop); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.h new file mode 100644 index 0000000..c7034c6 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.h @@ -0,0 +1,51 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const FIRCLSDeveloperToken; + +// User Messages +FOUNDATION_EXPORT NSString *const FIRCLSMissingConsumerKeyMsg; +FOUNDATION_EXPORT NSString *const FIRCLSMissingConsumerSecretMsg; + +// Exceptions +FOUNDATION_EXPORT NSString *const FIRCLSException; + +// Endpoints +FOUNDATION_EXPORT NSString *const FIRCLSSettingsEndpoint; +FOUNDATION_EXPORT NSString *const FIRCLSConfigureEndpoint; +FOUNDATION_EXPORT NSString *const FIRCLSReportsEndpoint; + +// Network requests +FOUNDATION_EXPORT NSString *const FIRCLSNetworkAccept; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkAcceptCharset; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkApplicationJson; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkAcceptLanguage; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkContentLanguage; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkCrashlyticsAPIClientDisplayVersion; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkCrashlyticsAPIClientId; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkCrashlyticsDeveloperToken; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkCrashlyticsGoogleAppId; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkCrashlyticsOrgId; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkUserAgent; +FOUNDATION_EXPORT NSString *const FIRCLSNetworkUTF8; + +NSString *FIRCLSSDKGeneratorName(void); + +NSString *FIRCLSSDKVersion(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.m new file mode 100644 index 0000000..301a57d --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSConstants.m @@ -0,0 +1,56 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSConstants.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#define STR_HELPER(x) #x +#define STR(x) STR_HELPER(x) + +NSString* const FIRCLSDeveloperToken = @"77f0789d8e230eccdb4b99b82dccd78d47f9b604"; + +// User Messages +NSString* const FIRCLSMissingConsumerKeyMsg = @"consumer key is nil or zero length"; +NSString* const FIRCLSMissingConsumerSecretMsg = @"consumer secret is nil or zero length"; + +// Exceptions +NSString* const FIRCLSException = @"FIRCLSException"; + +// Endpoints +NSString* const FIRCLSSettingsEndpoint = @"https://firebase-settings.crashlytics.com"; +NSString* const FIRCLSConfigureEndpoint = @"https://update.crashlytics.com"; +NSString* const FIRCLSReportsEndpoint = @"https://reports.crashlytics.com"; + +// Network requests +NSString* const FIRCLSNetworkAccept = @"Accept"; +NSString* const FIRCLSNetworkAcceptCharset = @"Accept-Charset"; +NSString* const FIRCLSNetworkApplicationJson = @"application/json"; +NSString* const FIRCLSNetworkAcceptLanguage = @"Accept-Language"; +NSString* const FIRCLSNetworkContentLanguage = @"Content-Language"; +NSString* const FIRCLSNetworkCrashlyticsAPIClientDisplayVersion = + @"X-Crashlytics-API-Client-Display-Version"; +NSString* const FIRCLSNetworkCrashlyticsAPIClientId = @"X-Crashlytics-API-Client-Id"; +NSString* const FIRCLSNetworkCrashlyticsDeveloperToken = @"X-Crashlytics-Developer-Token"; +NSString* const FIRCLSNetworkCrashlyticsGoogleAppId = @"X-Crashlytics-Google-App-Id"; +NSString* const FIRCLSNetworkCrashlyticsOrgId = @"X-Crashlytics-Org-Id"; +NSString* const FIRCLSNetworkUserAgent = @"User-Agent"; +NSString* const FIRCLSNetworkUTF8 = @"utf-8"; + +NSString* FIRCLSSDKGeneratorName(void) { + return [NSString stringWithFormat:@"%s/%s", STR(CLS_SDK_NAME), FIRCLSSDKVersion().UTF8String]; +} + +NSString* FIRCLSSDKVersion(void) { + return FIRFirebaseVersion(); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.h new file mode 100644 index 0000000..82c8fcc --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.h @@ -0,0 +1,35 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Returns the OS version of the host device + */ +NSOperatingSystemVersion FIRCLSHostGetOSVersion(void); + +/** + * Returns model info for the device on which app is running + */ +NSString *FIRCLSHostModelInfo(void); + +/** + * Returns a string representing the OS build + */ +NSString *FIRCLSHostOSBuildVersion(void); + +/** + * Returns a concatenated string of the OS version(majorVersion.minorVersion.patchVersion) + */ +NSString *FIRCLSHostOSDisplayVersion(void); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.m new file mode 100644 index 0000000..b6971c9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSFABHost.m @@ -0,0 +1,95 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Shared/FIRCLSFABHost.h" + +#import + +#if TARGET_OS_WATCH +#import +#elif TARGET_OS_IPHONE +#import +#endif + +#include + +#define FIRCLS_HOST_SYSCTL_BUFFER_SIZE (128) + +#pragma mark - OS Versions + +#pragma mark Private + +static NSString *FIRCLSHostSysctlEntry(const char *sysctlKey) { + char buffer[FIRCLS_HOST_SYSCTL_BUFFER_SIZE]; + size_t bufferSize = FIRCLS_HOST_SYSCTL_BUFFER_SIZE; + if (sysctlbyname(sysctlKey, buffer, &bufferSize, NULL, 0) != 0) { + return nil; + } + return [NSString stringWithUTF8String:buffer]; +} + +#pragma mark Public + +NSOperatingSystemVersion FIRCLSHostGetOSVersion(void) { + // works on macos(10.10), ios(8.0), watchos(2.0), tvos(9.0) + if ([NSProcessInfo.processInfo respondsToSelector:@selector(operatingSystemVersion)]) { + return [NSProcessInfo.processInfo operatingSystemVersion]; + } + + NSOperatingSystemVersion version = {0, 0, 0}; + +#if TARGET_OS_IPHONE + +#if TARGET_OS_WATCH + NSString *versionString = [[WKInterfaceDevice currentDevice] systemVersion]; +#else + NSString *versionString = [[UIDevice currentDevice] systemVersion]; +#endif + + NSArray *parts = [versionString componentsSeparatedByString:@"."]; + + if (parts.count > 0) { + version.majorVersion = [[parts objectAtIndex:0] integerValue]; + } + + if ([parts count] > 1) { + version.minorVersion = [[parts objectAtIndex:1] integerValue]; + } + + if ([parts count] > 2) { + version.patchVersion = [[parts objectAtIndex:2] integerValue]; + } + +#endif + + return version; +} + +NSString *FIRCLSHostOSBuildVersion(void) { + return FIRCLSHostSysctlEntry("kern.osversion"); +} + +NSString *FIRCLSHostOSDisplayVersion(void) { + NSOperatingSystemVersion version = FIRCLSHostGetOSVersion(); + return [NSString stringWithFormat:@"%ld.%ld.%ld", (long)version.majorVersion, + (long)version.minorVersion, (long)version.patchVersion]; +} + +#pragma mark - Host Models + +#pragma mark Public + +NSString *FIRCLSHostModelInfo(void) { + return [GULAppEnvironmentUtil deviceSimulatorModel]; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.h new file mode 100644 index 0000000..ae80c46 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.h @@ -0,0 +1,34 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +typedef enum { + FIRCLSCodeMappingSourceUnknown, + FIRCLSCodeMappingSourceBuild, + FIRCLSCodeSourceCache, + FIRCLSCodeSourceSpotlight +} FIRCLSCodeMappingSource; + +@interface FIRCLSCodeMapping : NSObject + ++ (instancetype)mappingWithURL:(NSURL*)URL; + +- (instancetype)initWithURL:(NSURL*)URL; + +@property(nonatomic, copy, readonly) NSURL* URL; +@property(nonatomic, assign) FIRCLSCodeMappingSource source; +@property(nonatomic, copy, readonly) NSString* sourceName; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.m new file mode 100644 index 0000000..ca3008b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.m @@ -0,0 +1,40 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSCodeMapping.h" + +@interface FIRCLSCodeMapping () { + FIRCLSCodeMappingSource _source; +} + +@end + +@implementation FIRCLSCodeMapping + ++ (instancetype)mappingWithURL:(NSURL *)URL { + return [[self alloc] initWithURL:URL]; +} + +- (instancetype)initWithURL:(NSURL *)URL { + self = [super init]; + if (!self) { + return nil; + } + + _URL = [URL copy]; + + return self; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h new file mode 100644 index 0000000..a974f53 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h @@ -0,0 +1,117 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + +#include +#include +#include + +#include + +struct FIRCLSMachOFile { + int fd; + size_t mappedSize; + void* mappedFile; +}; +typedef struct FIRCLSMachOFile* FIRCLSMachOFileRef; + +struct FIRCLSMachOSlice { + const void* startAddress; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; +}; +typedef struct FIRCLSMachOSlice* FIRCLSMachOSliceRef; + +typedef struct { + uint32_t major; + uint32_t minor; + uint32_t bugfix; +} FIRCLSMachOVersion; + +typedef struct { + uint64_t addr; + uint64_t size; + uint32_t offset; +} FIRCLSMachOSection; + +typedef struct { + char segname[16]; + uint64_t vmaddr; + uint64_t vmsize; +} FIRCLSMachOSegmentCommand; + +typedef void (^FIRCLSMachOSliceIterator)(FIRCLSMachOSliceRef slice); +typedef void (^FIRCLSMachOLoadCommandIterator)(uint32_t type, + uint32_t size, + const struct load_command* cmd); +typedef void (*FIRCLSMachOLoadCommandIteratorFunc)(uint32_t type, + uint32_t size, + const struct load_command* cmd, + void* context); + +__BEGIN_DECLS + +bool FIRCLSMachOFileInitWithPath(FIRCLSMachOFileRef file, const char* path); +bool FIRCLSMachOFileInitWithCurrent(FIRCLSMachOFileRef file); +void FIRCLSMachOFileDestroy(FIRCLSMachOFileRef file); +void FIRCLSMachOFileEnumerateSlices(FIRCLSMachOFileRef file, FIRCLSMachOSliceIterator block); +struct FIRCLSMachOSlice FIRCLSMachOFileSliceWithArchitectureName(FIRCLSMachOFileRef file, + const char* name); + +void FIRCLSMachOEnumerateSlicesAtAddress(void* executableData, FIRCLSMachOSliceIterator block); +void FIRCLSMachOSliceEnumerateLoadCommands(FIRCLSMachOSliceRef slice, + FIRCLSMachOLoadCommandIterator block); +void FIRCLSMachOSliceEnumerateLoadCommands_f(FIRCLSMachOSliceRef slice, + void* context, + FIRCLSMachOLoadCommandIteratorFunc function); +struct FIRCLSMachOSlice FIRCLSMachOSliceGetCurrent(void); +struct FIRCLSMachOSlice FIRCLSMachOSliceWithHeader(void* machHeader); + +const char* FIRCLSMachOSliceGetExecutablePath(FIRCLSMachOSliceRef slice); +const char* FIRCLSMachOSliceGetArchitectureName(FIRCLSMachOSliceRef slice); +bool FIRCLSMachOSliceIs64Bit(FIRCLSMachOSliceRef slice); +bool FIRCLSMachOSliceGetSectionByName(FIRCLSMachOSliceRef slice, + const char* segName, + const char* sectionName, + const void** ptr); +bool FIRCLSMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice, + const char* segName, + const char* sectionName, + FIRCLSMachOSection* section); +void FIRCLSMachOSliceGetUnwindInformation(FIRCLSMachOSliceRef slice, + const void** ehFrame, + const void** unwindInfo); + +// load-command-specific calls for convenience + +// returns a pointer to the 16-byte UUID +uint8_t const* FIRCLSMachOGetUUID(const struct load_command* cmd); +const char* FIRCLSMachOGetDylibPath(const struct load_command* cmd); + +// return true if the header indicates the binary is encrypted +bool FIRCLSMachOGetEncrypted(const struct load_command* cmd); + +// SDK minimums +FIRCLSMachOVersion FIRCLSMachOGetMinimumOSVersion(const struct load_command* cmd); +FIRCLSMachOVersion FIRCLSMachOGetLinkedSDKVersion(const struct load_command* cmd); + +// Helpers +FIRCLSMachOSegmentCommand FIRCLSMachOGetSegmentCommand(const struct load_command* cmd); + +#ifdef __OBJC__ +NSString* FIRCLSMachONormalizeUUID(CFUUIDBytes* uuidBytes); +NSString* FIRCLSMachOFormatVersion(FIRCLSMachOVersion* version); +#endif +__END_DECLS diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.m new file mode 100644 index 0000000..477541c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.m @@ -0,0 +1,560 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" +#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h" + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include + +// This is defined in newer versions of iOS/macOS in usr/include/mach/machine.h +#define CLS_CPU_SUBTYPE_ARM64E ((cpu_subtype_t)2) + +static void FIRCLSMachOHeaderValues(FIRCLSMachOSliceRef slice, + const struct load_command** cmds, + uint32_t* cmdCount); +static bool FIRCLSMachOSliceIsValid(FIRCLSMachOSliceRef slice); + +bool FIRCLSMachOFileInitWithPath(FIRCLSMachOFileRef file, const char* path) { + if (!file || !path) { + return false; + } + + file->fd = 0; + file->mappedFile = NULL; + file->mappedSize = 0; + + file->fd = open(path, O_RDONLY); + if (file->fd < 0) { + // unable to open mach-o file + return false; + } + + NSError* attributesError; + NSString* objCPath = [NSString stringWithCString:path encoding:NSUTF8StringEncoding]; + NSDictionary* fileAttributes = + [[NSFileManager defaultManager] attributesOfItemAtPath:objCPath error:&attributesError]; + if (attributesError != nil) { + close(file->fd); + return false; + } + NSNumber* fileSizeNumber = [fileAttributes objectForKey:NSFileSize]; + long long currentFileSize = [fileSizeNumber longLongValue]; + NSFileAttributeType fileType = [fileAttributes objectForKey:NSFileType]; + + // We need some minimum size for this to even be a possible mach-o file. I believe + // its probably quite a bit bigger than this, but this at least covers something. + // We also need it to be a regular file. + file->mappedSize = (size_t)currentFileSize; + if (currentFileSize < 16 || ![fileType isEqualToString:NSFileTypeRegular]) { + close(file->fd); + return false; + } + + // Map the file to memory. MAP_SHARED can potentially reduce the amount of actual private + // memory needed to do this mapping. Also, be sure to check for the correct failure result. + file->mappedFile = mmap(0, file->mappedSize, PROT_READ, MAP_FILE | MAP_SHARED, file->fd, 0); + if (!file->mappedFile || (file->mappedFile == MAP_FAILED)) { + close(file->fd); + return false; + } + + return true; +} + +bool FIRCLSMachOFileInitWithCurrent(FIRCLSMachOFileRef file) { + struct FIRCLSMachOSlice slice = FIRCLSMachOSliceGetCurrent(); + + const char* imagePath = FIRCLSMachOSliceGetExecutablePath(&slice); + + return FIRCLSMachOFileInitWithPath(file, imagePath); +} + +void FIRCLSMachOFileDestroy(FIRCLSMachOFileRef file) { + if (!file) { + return; + } + + if (file->mappedFile && file->mappedSize > 0) { + munmap(file->mappedFile, file->mappedSize); + } + + close(file->fd); +} + +void FIRCLSMachOFileEnumerateSlices(FIRCLSMachOFileRef file, FIRCLSMachOSliceIterator block) { + FIRCLSMachOEnumerateSlicesAtAddress(file->mappedFile, block); +} + +void FIRCLSMachOEnumerateSlicesAtAddress(void* executableData, FIRCLSMachOSliceIterator block) { + // check the magic value, to determine if we have a fat header or not + uint32_t magicValue; + uint32_t archCount; + const struct fat_arch* fatArch; + struct FIRCLSMachOSlice slice; + + memset(&slice, 0, sizeof(struct FIRCLSMachOSlice)); + + magicValue = ((struct fat_header*)executableData)->magic; + if ((magicValue != FAT_MAGIC) && (magicValue != FAT_CIGAM)) { + slice.startAddress = executableData; + + // use this to fill in the values + FIRCLSMachOHeaderValues(&slice, NULL, NULL); + + block(&slice); + + return; + } + + archCount = OSSwapBigToHostInt32(((struct fat_header*)executableData)->nfat_arch); + fatArch = executableData + sizeof(struct fat_header); + + for (uint32_t i = 0; i < archCount; ++i) { + slice.cputype = OSSwapBigToHostInt32(fatArch->cputype); + slice.cpusubtype = OSSwapBigToHostInt32(fatArch->cpusubtype); + slice.startAddress = executableData + OSSwapBigToHostInt32(fatArch->offset); + + block(&slice); + + // advance to the next fat_arch structure + fatArch = (struct fat_arch*)((uintptr_t)fatArch + sizeof(struct fat_arch)); + } +} + +struct FIRCLSMachOSlice FIRCLSMachOFileSliceWithArchitectureName(FIRCLSMachOFileRef file, + const char* name) { + __block struct FIRCLSMachOSlice value; + + memset(&value, 0, sizeof(struct FIRCLSMachOSlice)); + + FIRCLSMachOFileEnumerateSlices(file, ^(FIRCLSMachOSliceRef slice) { + if (strcmp(FIRCLSMachOSliceGetArchitectureName(slice), name) == 0) { + value = *slice; + } + }); + + return value; +} + +static void FIRCLSMachOHeaderValues(FIRCLSMachOSliceRef slice, + const struct load_command** cmds, + uint32_t* cmdCount) { + const struct mach_header* header32 = (const struct mach_header*)slice->startAddress; + const struct mach_header_64* header64 = (const struct mach_header_64*)slice->startAddress; + uint32_t commandCount; + const void* commandsAddress; + + if (cmds) { + *cmds = NULL; + } + + if (cmdCount) { + *cmdCount = 0; + } + + if (!slice->startAddress) { + return; + } + + // the 32 and 64 bit versions have an identical structures, so this will work + switch (header32->magic) { + case MH_MAGIC: // 32-bit + case MH_CIGAM: + slice->cputype = header32->cputype; + slice->cpusubtype = header32->cpusubtype; + commandCount = header32->ncmds; + commandsAddress = slice->startAddress + sizeof(struct mach_header); + break; + case MH_MAGIC_64: // 64-bit + case MH_CIGAM_64: + slice->cputype = header64->cputype; + slice->cpusubtype = header64->cpusubtype; + commandCount = header64->ncmds; + commandsAddress = slice->startAddress + sizeof(struct mach_header_64); + break; + default: + // not a valid header + return; + } + + // assign everything back by reference + if (cmds) { + *cmds = commandsAddress; + } + + if (cmdCount) { + *cmdCount = commandCount; + } +} + +static bool FIRCLSMachOSliceIsValid(FIRCLSMachOSliceRef slice) { + if (!slice) { + return false; + } + + if (!slice->startAddress) { + return false; + } + + return true; +} + +void FIRCLSMachOSliceEnumerateLoadCommands_f(FIRCLSMachOSliceRef slice, + void* context, + FIRCLSMachOLoadCommandIteratorFunc function) { + const struct load_command* cmd; + uint32_t cmdCount; + + if (!FIRCLSMachOSliceIsValid(slice)) { + return; + } + + FIRCLSMachOHeaderValues(slice, &cmd, &cmdCount); + + for (uint32_t i = 0; cmd != NULL && i < cmdCount; ++i) { + function(cmd->cmd, cmd->cmdsize, cmd, context); + + cmd = (struct load_command*)((uintptr_t)cmd + cmd->cmdsize); + } +} + +void FIRCLSMachOSliceEnumerateLoadCommands(FIRCLSMachOSliceRef slice, + FIRCLSMachOLoadCommandIterator block) { + const struct load_command* cmd; + uint32_t cmdCount; + + if (!block) { + return; + } + + if (!FIRCLSMachOSliceIsValid(slice)) { + return; + } + + FIRCLSMachOHeaderValues(slice, &cmd, &cmdCount); + + for (uint32_t i = 0; cmd != NULL && i < cmdCount; ++i) { + block(cmd->cmd, cmd->cmdsize, cmd); + + cmd = (struct load_command*)((uintptr_t)cmd + cmd->cmdsize); + } +} + +struct FIRCLSMachOSlice FIRCLSMachOSliceGetCurrent(void) { + struct FIRCLSMachOSlice slice; + void* executableSymbol; + Dl_info dlinfo; + +#if !CLS_TARGET_OS_VISION + const NXArchInfo* archInfo; + archInfo = NXGetLocalArchInfo(); + + if (archInfo) { + slice.cputype = archInfo->cputype; + slice.cpusubtype = archInfo->cpusubtype; + } +#else + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + const char* archname = macho_arch_name_for_mach_header(NULL); + bool hasArchInfo = macho_cpu_type_for_arch_name(archname, &cputype, &cpusubtype); + if (hasArchInfo) { + slice.cputype = cputype; + slice.cpusubtype = cpusubtype; + } +#endif + + slice.startAddress = NULL; + + // This call can fail when Exported Symbols File in Build Settings is missing the symbol value + // defined as _MH_EXECUTE_SYM (if you look in the header the underscored MH_EXECUTE_SYM define is + // there) + executableSymbol = dlsym(RTLD_MAIN_ONLY, MH_EXECUTE_SYM); + + // get the address of the main function + if (dladdr(executableSymbol, &dlinfo) != 0) { + slice.startAddress = dlinfo.dli_fbase; + } + + return slice; +} + +struct FIRCLSMachOSlice FIRCLSMachOSliceWithHeader(void* machHeader) { + struct FIRCLSMachOSlice slice; + + slice.startAddress = machHeader; + + return slice; +} + +const char* FIRCLSMachOSliceGetExecutablePath(FIRCLSMachOSliceRef slice) { + Dl_info info; + + if (!FIRCLSMachOSliceIsValid(slice)) { + return NULL; + } + + // use dladdr here to look up the information we need for a binary image + if (dladdr(slice->startAddress, &info) == 0) { + return NULL; + } + + return info.dli_fname; +} + +const char* FIRCLSMachOSliceGetArchitectureName(FIRCLSMachOSliceRef slice) { + // there are some special cases here for types not handled by earlier OSes + if (slice->cputype == CPU_TYPE_ARM && slice->cpusubtype == CPU_SUBTYPE_ARM_V7S) { + return "armv7s"; + } + + if (slice->cputype == (CPU_TYPE_ARM | CPU_ARCH_ABI64)) { + if (slice->cpusubtype == CLS_CPU_SUBTYPE_ARM64E) { + return "arm64e"; + } else if (slice->cpusubtype == CPU_SUBTYPE_ARM64_ALL) { + return "arm64"; + } + } + + if (slice->cputype == (CPU_TYPE_ARM) && slice->cpusubtype == CPU_SUBTYPE_ARM_V7K) { + return "armv7k"; + } + +#if !CLS_TARGET_OS_VISION + const NXArchInfo* archInfo; + + archInfo = NXGetArchInfoFromCpuType(slice->cputype, slice->cpusubtype); + if (!archInfo) { + return "unknown"; + } + + return archInfo->name; +#else + const char* archname = macho_arch_name_for_mach_header(slice->startAddress); + + if (!archname) { + return "unknown"; + } + return archname; +#endif +} + +bool FIRCLSMachOSliceIs64Bit(FIRCLSMachOSliceRef slice) { + // I'm pretty sure this is sufficient... + return (slice->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64; +} + +// deprecated +bool FIRCLSMachOSliceGetSectionByName(FIRCLSMachOSliceRef slice, + const char* segName, + const char* sectionName, + const void** ptr) { + if (!ptr) { + return false; + } + + *ptr = NULL; // make sure this is set before returning + + FIRCLSMachOSection section; + + if (!FIRCLSMachOSliceInitSectionByName(slice, segName, sectionName, §ion)) { + return false; + } + + // WARNING: this calculation isn't correct, but is here to maintain backwards + // compatibility for now with callers of FIRCLSMachOSliceGetSectionByName. All new + // users should be calling FIRCLSMachOSliceInitSectionByName + *ptr = (const void*)((uintptr_t)slice->startAddress + section.offset); + + return true; +} + +bool FIRCLSMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice, + const char* segName, + const char* sectionName, + FIRCLSMachOSection* section) { + if (!FIRCLSMachOSliceIsValid(slice)) { + return false; + } + + if (!section) { + return false; + } + + memset(section, 0, sizeof(FIRCLSMachOSection)); + +// Deprecated code for vision OS, entire function is not used anywhere +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if (FIRCLSMachOSliceIs64Bit(slice)) { + const struct section_64* sect = + getsectbynamefromheader_64(slice->startAddress, segName, sectionName); + if (!sect) { + return false; + } + + section->addr = sect->addr; + section->size = sect->size; + section->offset = sect->offset; + } else { + const struct section* sect = getsectbynamefromheader(slice->startAddress, segName, sectionName); + if (!sect) { + return false; + } + + section->addr = sect->addr; + section->size = sect->size; + section->offset = sect->offset; + } +#pragma clang diagnostic pop + return true; +} + +// TODO: this is left in-place just to ensure that old crashltyics + new fabric are still compatible +// with each other. As a happy bonus, if that situation does come up, this will also fix the bug +// that was preventing compact unwind on arm64 + iOS 9 from working correctly. +void FIRCLSMachOSliceGetUnwindInformation(FIRCLSMachOSliceRef slice, + const void** ehFrame, + const void** unwindInfo) { + if (!unwindInfo && !ehFrame) { + return; + } + + bool found = false; + intptr_t slide = 0; + + // This is inefficient, but we have no other safe way to do this correctly. Modifying the + // FIRCLSMachOSlice structure is tempting, but could introduce weird binary-compatibility issues + // with version mis-matches. + for (uint32_t i = 0; i < _dyld_image_count(); ++i) { + const struct mach_header* header = _dyld_get_image_header(i); + + if (header == slice->startAddress) { + found = true; + slide = _dyld_get_image_vmaddr_slide(i); + break; + } + } + + // make sure we were able to find a matching value + if (!found) { + return; + } + + FIRCLSMachOSection section; + + if (unwindInfo) { + if (FIRCLSMachOSliceInitSectionByName(slice, SEG_TEXT, "__unwind_info", §ion)) { + *unwindInfo = (void*)(section.addr + slide); + } + } + + if (ehFrame) { + if (FIRCLSMachOSliceInitSectionByName(slice, SEG_TEXT, "__eh_frame", §ion)) { + *ehFrame = (void*)(section.addr + slide); + } + } +} + +uint8_t const* FIRCLSMachOGetUUID(const struct load_command* cmd) { + return ((const struct uuid_command*)cmd)->uuid; +} + +const char* FIRCLSMachOGetDylibPath(const struct load_command* cmd) { + const struct dylib_command* dylibcmd = (const struct dylib_command*)cmd; + + return (const char*)((uintptr_t)cmd + dylibcmd->dylib.name.offset); +} + +bool FIRCLSMachOGetEncrypted(const struct load_command* cmd) { + return ((struct encryption_info_command*)cmd)->cryptid > 0; +} + +static FIRCLSMachOVersion FIRCLSMachOVersionFromEncoded(uint32_t encoded) { + FIRCLSMachOVersion version; + + version.major = (encoded & 0xffff0000) >> 16; + version.minor = (encoded & 0x0000ff00) >> 8; + version.bugfix = encoded & 0x000000ff; + + return version; +} + +FIRCLSMachOVersion FIRCLSMachOGetMinimumOSVersion(const struct load_command* cmd) { + return FIRCLSMachOVersionFromEncoded(((const struct version_min_command*)cmd)->version); +} + +FIRCLSMachOVersion FIRCLSMachOGetLinkedSDKVersion(const struct load_command* cmd) { + return FIRCLSMachOVersionFromEncoded(((const struct version_min_command*)cmd)->sdk); +} + +FIRCLSMachOSegmentCommand FIRCLSMachOGetSegmentCommand(const struct load_command* cmd) { + FIRCLSMachOSegmentCommand segmentCommand; + + memset(&segmentCommand, 0, sizeof(FIRCLSMachOSegmentCommand)); + + if (!cmd) { + return segmentCommand; + } + + if (cmd->cmd == LC_SEGMENT) { + struct segment_command* segCmd = (struct segment_command*)cmd; + + memcpy(segmentCommand.segname, segCmd->segname, 16); + segmentCommand.vmaddr = segCmd->vmaddr; + segmentCommand.vmsize = segCmd->vmsize; + } else if (cmd->cmd == LC_SEGMENT_64) { + struct segment_command_64* segCmd = (struct segment_command_64*)cmd; + + memcpy(segmentCommand.segname, segCmd->segname, 16); + segmentCommand.vmaddr = segCmd->vmaddr; + segmentCommand.vmsize = segCmd->vmsize; + } + + return segmentCommand; +} + +NSString* FIRCLSMachONormalizeUUID(CFUUIDBytes* uuidBytes) { + CFUUIDRef uuid = CFUUIDCreateFromUUIDBytes(kCFAllocatorDefault, *uuidBytes); + + NSString* string = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)); + + CFRelease(uuid); + + return [[string stringByReplacingOccurrencesOfString:@"-" withString:@""] lowercaseString]; +} + +NSString* FIRCLSMachOFormatVersion(FIRCLSMachOVersion* version) { + if (!version) { + return nil; + } + + return [NSString stringWithFormat:@"%d.%d.%d", version->major, version->minor, version->bugfix]; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h new file mode 100644 index 0000000..94c7fa8 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h @@ -0,0 +1,41 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" + +@class FIRCLSMachOSlice; + +@interface FIRCLSMachOBinary : NSObject { + NSURL* _url; + + struct FIRCLSMachOFile _file; + NSMutableArray* _slices; + NSString* _instanceIdentifier; +} + ++ (id)MachOBinaryWithPath:(NSString*)path; + +- (id)initWithURL:(NSURL*)url; + +@property(nonatomic, copy, readonly) NSURL* URL; +@property(nonatomic, copy, readonly) NSString* path; +@property(nonatomic, strong, readonly) NSArray* slices; +@property(nonatomic, copy, readonly) NSString* instanceIdentifier; + +- (void)enumerateUUIDs:(void (^)(NSString* uuid, NSString* architecture))block; + +- (FIRCLSMachOSlice*)sliceForArchitecture:(NSString*)architecture; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m new file mode 100644 index 0000000..02e9125 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.m @@ -0,0 +1,175 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h" + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h" + +#import + +static void FIRCLSSafeHexToString(const uint8_t* value, size_t length, char* outputBuffer); +static NSString* FIRCLSNSDataToNSString(NSData* data); +static NSString* FIRCLSHashBytes(const void* bytes, size_t length); +static NSString* FIRCLSHashNSString(NSString* value); + +@interface FIRCLSMachOBinary () + ++ (NSString*)hashNSString:(NSString*)value; + +@end + +@implementation FIRCLSMachOBinary + ++ (id)MachOBinaryWithPath:(NSString*)path { + return [[self alloc] initWithURL:[NSURL fileURLWithPath:path]]; +} + +@synthesize slices = _slices; + +- (id)initWithURL:(NSURL*)url { + self = [super init]; + if (self) { + _url = [url copy]; + + if (!FIRCLSMachOFileInitWithPath(&_file, [[_url path] fileSystemRepresentation])) { + return nil; + } + + _slices = [NSMutableArray new]; + FIRCLSMachOFileEnumerateSlices(&_file, ^(FIRCLSMachOSliceRef slice) { + FIRCLSMachOSlice* sliceObject; + + sliceObject = [[FIRCLSMachOSlice alloc] initWithSlice:slice]; + + [self->_slices addObject:sliceObject]; + }); + } + + return self; +} + +- (void)dealloc { + FIRCLSMachOFileDestroy(&_file); +} + +- (NSURL*)URL { + return _url; +} + +- (NSString*)path { + return [_url path]; +} + +- (NSString*)instanceIdentifier { + if (_instanceIdentifier) { + return _instanceIdentifier; + } + + NSMutableString* prehashedString = [NSMutableString new]; + + // sort the slices by architecture + NSArray* sortedSlices = + [_slices sortedArrayUsingComparator:^NSComparisonResult(id obj1, id obj2) { + return [[obj1 architectureName] compare:[obj2 architectureName]]; + }]; + + // append them all into a big string + for (FIRCLSMachOSlice* slice in sortedSlices) { + [prehashedString appendString:[slice uuid]]; + } + + _instanceIdentifier = [FIRCLSHashNSString(prehashedString) copy]; + + return _instanceIdentifier; +} + +- (void)enumerateUUIDs:(void (^)(NSString* uuid, NSString* architecture))block { + for (FIRCLSMachOSlice* slice in _slices) { + block([slice uuid], [slice architectureName]); + } +} + +- (FIRCLSMachOSlice*)sliceForArchitecture:(NSString*)architecture { + for (FIRCLSMachOSlice* slice in [self slices]) { + if ([[slice architectureName] isEqualToString:architecture]) { + return slice; + } + } + + return nil; +} + ++ (NSString*)hashNSString:(NSString*)value { + return FIRCLSHashNSString(value); +} + +@end + +// TODO: Functions copied from the SDK. We should figure out a way to share this. +static void FIRCLSSafeHexToString(const uint8_t* value, size_t length, char* outputBuffer) { + const char hex[] = "0123456789abcdef"; + + if (!value) { + outputBuffer[0] = '\0'; + return; + } + + for (size_t i = 0; i < length; ++i) { + unsigned char c = value[i]; + outputBuffer[i * 2] = hex[c >> 4]; + outputBuffer[i * 2 + 1] = hex[c & 0x0F]; + } + + outputBuffer[length * 2] = '\0'; // null terminate +} + +static NSString* FIRCLSNSDataToNSString(NSData* data) { + NSString* string; + char* buffer; + size_t size; + NSUInteger length; + + // we need 2 hex char for every byte of data, plus one more spot for a + // null terminator + length = [data length]; + size = (length * 2) + 1; + buffer = malloc(sizeof(char) * size); + + if (!buffer) { + return nil; + } + + FIRCLSSafeHexToString([data bytes], length, buffer); + + string = [NSString stringWithUTF8String:buffer]; + + free(buffer); + + return string; +} + +static NSString* FIRCLSHashBytes(const void* bytes, size_t length) { + uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; + CC_SHA1(bytes, (CC_LONG)length, digest); + + NSData* result = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; + + return FIRCLSNSDataToNSString(result); +} + +static NSString* FIRCLSHashNSString(NSString* value) { + const char* s = [value cStringUsingEncoding:NSUTF8StringEncoding]; + + return FIRCLSHashBytes(s, strlen(s)); +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h new file mode 100644 index 0000000..eb55ed9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h @@ -0,0 +1,37 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h" + +@interface FIRCLSMachOSlice : NSObject { + struct FIRCLSMachOSlice _slice; + + NSString* _uuidString; + NSArray* _linkedDylibs; + FIRCLSMachOVersion _minimumOSVersion; + FIRCLSMachOVersion _linkedSDKVersion; +} + ++ (id)runningSlice; + +- (id)initWithSlice:(FIRCLSMachOSliceRef)sliceRef; + +@property(nonatomic, copy, readonly) NSString* uuid; +@property(nonatomic, copy, readonly) NSString* architectureName; +@property(nonatomic, strong, readonly) NSArray* linkedDylibs; +@property(nonatomic, assign, readonly) FIRCLSMachOVersion minimumOSVersion; +@property(nonatomic, assign, readonly) FIRCLSMachOVersion linkedSDKVersion; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.m new file mode 100644 index 0000000..d28626b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.m @@ -0,0 +1,93 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h" + +#include + +// this is defined only if __OPEN_SOURCE__ is *not* defined in the TVOS SDK's mach-o/loader.h +// also, it has not yet made it back to the OSX SDKs, for example +#ifndef LC_VERSION_MIN_TVOS +#define LC_VERSION_MIN_TVOS 0x2F +#endif + +@implementation FIRCLSMachOSlice + ++ (id)runningSlice { + struct FIRCLSMachOSlice slice; + + slice = FIRCLSMachOSliceGetCurrent(); + + return [[self alloc] initWithSlice:&slice]; +} + +@synthesize minimumOSVersion = _minimumOSVersion; +@synthesize linkedSDKVersion = _linkedSDKVersion; + +- (id)initWithSlice:(FIRCLSMachOSliceRef)sliceRef { + self = [super init]; + if (self) { + NSMutableArray* dylibs; + + _slice = *sliceRef; + + _minimumOSVersion.major = 0; + _minimumOSVersion.minor = 0; + _minimumOSVersion.bugfix = 0; + + _linkedSDKVersion.major = 0; + _linkedSDKVersion.minor = 0; + _linkedSDKVersion.bugfix = 0; + + dylibs = [NSMutableArray array]; + + FIRCLSMachOSliceEnumerateLoadCommands( + &_slice, ^(uint32_t type, uint32_t size, const struct load_command* cmd) { + switch (type) { + case LC_UUID: + self->_uuidString = + [FIRCLSMachONormalizeUUID((CFUUIDBytes*)FIRCLSMachOGetUUID(cmd)) copy]; + break; + case LC_LOAD_DYLIB: + [dylibs addObject:[NSString stringWithUTF8String:FIRCLSMachOGetDylibPath(cmd)]]; + break; + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_WATCHOS: + case LC_VERSION_MIN_TVOS: + self->_minimumOSVersion = FIRCLSMachOGetMinimumOSVersion(cmd); + self->_linkedSDKVersion = FIRCLSMachOGetLinkedSDKVersion(cmd); + break; + } + }); + + _linkedDylibs = [dylibs copy]; + } + + return self; +} + +- (NSString*)architectureName { + return [NSString stringWithUTF8String:FIRCLSMachOSliceGetArchitectureName(&_slice)]; +} + +- (NSString*)uuid { + return _uuidString; +} + +- (NSArray*)linkedDylibs { + return _linkedDylibs; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.h new file mode 100644 index 0000000..c80ac74 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.h @@ -0,0 +1,38 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FIRCLSMachOBinary; + +@interface FIRCLSdSYM : NSObject + +NS_ASSUME_NONNULL_BEGIN + ++ (id)dSYMWithURL:(NSURL*)url; + +- (id)initWithURL:(NSURL*)url; + +@property(nonatomic, readonly) FIRCLSMachOBinary* binary; +@property(nonatomic, copy, readonly, nullable) NSString* bundleIdentifier; +@property(nonatomic, copy, readonly) NSURL* executableURL; +@property(nonatomic, copy, readonly) NSString* executablePath; +@property(nonatomic, copy, readonly) NSString* bundleVersion; +@property(nonatomic, copy, readonly) NSString* shortBundleVersion; + +- (void)enumerateUUIDs:(void (^)(NSString* uuid, NSString* architecture))block; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.m new file mode 100644 index 0000000..393e9a5 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.m @@ -0,0 +1,109 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.h" + +#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h" + +#define CLS_XCODE_DSYM_PREFIX (@"com.apple.xcode.dsym.") + +@interface FIRCLSdSYM () + +@property(nonatomic, readonly) NSBundle* bundle; + +@end + +@implementation FIRCLSdSYM + ++ (id)dSYMWithURL:(NSURL*)url { + return [[self alloc] initWithURL:url]; +} + +- (id)initWithURL:(NSURL*)url { + self = [super init]; + if (self) { + NSDirectoryEnumerator* enumerator; + NSString* path; + NSFileManager* fileManager; + BOOL isDirectory; + BOOL fileExistsAtPath; + NSArray* itemsInDWARFDir; + + fileManager = [NSFileManager defaultManager]; + + // Is there a file at this path? + if (![fileManager fileExistsAtPath:[url path]]) { + return nil; + } + + _bundle = [NSBundle bundleWithURL:url]; + if (!_bundle) { + return nil; + } + + path = [[url path] stringByAppendingPathComponent:@"Contents/Resources/DWARF"]; + + // Does this path exist and is it a directory? + fileExistsAtPath = [fileManager fileExistsAtPath:path isDirectory:&isDirectory]; + if (!fileExistsAtPath || !isDirectory) { + return nil; + } + + enumerator = [fileManager enumeratorAtPath:path]; + itemsInDWARFDir = [enumerator allObjects]; + // Do we have a Contents/Resources/DWARF dir but no contents? + if ([itemsInDWARFDir count] == 0) { + return nil; + } + + path = [path stringByAppendingPathComponent:[itemsInDWARFDir objectAtIndex:0]]; + + _binary = [[FIRCLSMachOBinary alloc] initWithURL:[NSURL fileURLWithPath:path]]; + } + + return self; +} + +- (NSString*)bundleIdentifier { + NSString* identifier; + + identifier = [_bundle bundleIdentifier]; + if ([identifier hasPrefix:CLS_XCODE_DSYM_PREFIX]) { + return [identifier substringFromIndex:[CLS_XCODE_DSYM_PREFIX length]]; + } + + return identifier; +} + +- (NSURL*)executableURL { + return [_binary URL]; +} + +- (NSString*)executablePath { + return [_binary path]; +} + +- (NSString*)bundleVersion { + return [[_bundle infoDictionary] objectForKey:@"CFBundleVersion"]; +} + +- (NSString*)shortBundleVersion { + return [[_bundle infoDictionary] objectForKey:@"CFBundleShortVersionString"]; +} + +- (void)enumerateUUIDs:(void (^)(NSString* uuid, NSString* architecture))block { + [_binary enumerateUUIDs:block]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h new file mode 100644 index 0000000..ebbd26c --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h @@ -0,0 +1,56 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +OBJC_EXTERN const NSUInteger FIRCLSNetworkMaximumRetryCount; + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^FIRCLSNetworkDataTaskCompletionHandlerBlock)(NSData *__nullable data, + NSURLResponse *__nullable response, + NSError *__nullable error); +typedef void (^FIRCLSNetworkDownloadTaskCompletionHandlerBlock)(NSURL *__nullable location, + NSURLResponse *__nullable response, + NSError *__nullable error); + +@interface FIRCLSFABNetworkClient : NSObject + +- (instancetype)init; +- (instancetype)initWithQueue:(nullable NSOperationQueue *)operationQueue; +- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config + queue:(nullable NSOperationQueue *)operationQueue + NS_DESIGNATED_INITIALIZER; + +- (void)startDataTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler; +- (void)startDownloadTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + completionHandler: + (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler; + +- (void)invalidateAndCancel; + +// Backwards compatibility (we cannot change an interface in Fabric Base that other kits rely on, +// since we have no control of versioning dependencies) +- (void)startDataTaskWithRequest:(NSURLRequest *)request + completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler; +- (void)startDownloadTaskWithRequest:(NSURLRequest *)request + completionHandler: + (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.m new file mode 100644 index 0000000..3e96407 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.m @@ -0,0 +1,267 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSFABNetworkClient.h" + +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h" + +static const float FIRCLSNetworkMinimumRetryJitter = 0.90f; +static const float FIRCLSNetworkMaximumRetryJitter = 1.10f; +const NSUInteger FIRCLSNetworkMaximumRetryCount = 10; + +@interface FIRCLSFABNetworkClient () + +@property(nonatomic, strong, readonly) NSURLSession *session; + +@end + +@implementation FIRCLSFABNetworkClient + +- (instancetype)init { + return [self initWithQueue:nil]; +} + +- (instancetype)initWithQueue:(nullable NSOperationQueue *)operationQueue { + NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; + return [self initWithSessionConfiguration:config queue:operationQueue]; +} + +- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)config + queue:(nullable NSOperationQueue *)operationQueue { + self = [super init]; + if (!self) { + return nil; + } + + _session = [NSURLSession sessionWithConfiguration:config + delegate:self + delegateQueue:operationQueue]; + + if (!_session) { + return nil; + } + + return self; +} + +- (void)dealloc { + [_session finishTasksAndInvalidate]; +} + +#pragma mark - Delay Handling +- (double)randomDoubleWithMin:(double)min max:(double)max { + return min + ((max - min) * drand48()); +} + +- (double)generateRandomJitter { + return [self randomDoubleWithMin:FIRCLSNetworkMinimumRetryJitter + max:FIRCLSNetworkMaximumRetryJitter]; +} + +- (NSTimeInterval)computeDelayForResponse:(NSURLResponse *)response + withRetryCount:(NSUInteger)count { + NSTimeInterval initialValue = [FIRCLSNetworkResponseHandler retryValueForResponse:response]; + + // make sure count is > 0 + count = MAX(count, 1); + // make sure initialValue is >2 for exponential backoff to work reasonably with low count numbers + initialValue = MAX(initialValue, 2.0); + + const double jitter = [self generateRandomJitter]; + + return pow(initialValue, count) * jitter; // exponential backoff +} + +- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response + attempts:(NSUInteger)count + onQueue:(dispatch_queue_t)queue + block:(void (^)(void))block { + const NSTimeInterval delay = [self computeDelayForResponse:response withRetryCount:count]; + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (uint64_t)(delay * NSEC_PER_SEC)), queue, block); +} + +- (void)runAfterRetryValueFromResponse:(NSURLResponse *)response + attempts:(NSUInteger)count + block:(void (^)(void))block { + dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + [self runAfterRetryValueFromResponse:response attempts:count onQueue:queue block:block]; +} + +#pragma mark - Tasks + +- (void)startDataTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + tries:(NSUInteger)tries + completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler { + NSURLSessionTask *task = [self.session + dataTaskWithRequest:request + completionHandler:^(NSData *data, NSURLResponse *response, NSError *taskError) { + [FIRCLSNetworkResponseHandler + handleCompletedResponse:response + forOriginalRequest:request + error:taskError + block:^(BOOL retry, NSError *error) { + if (!retry) { + completionHandler(data, response, error); + return; + } + + if (tries >= retryLimit) { + NSDictionary *userInfo = @{ + @"retryLimit" : @(retryLimit), + NSURLErrorFailingURLStringErrorKey : request.URL + }; + completionHandler( + nil, nil, + [NSError + errorWithDomain:FIRCLSNetworkErrorDomain + code:FIRCLSNetworkErrorMaximumAttemptsReached + userInfo:userInfo]); + return; + } + + [self + runAfterRetryValueFromResponse:response + attempts:tries + block:^{ + [self + startDataTaskWithRequest: + request + retryLimit: + retryLimit + tries: + (tries + + 1) + completionHandler: + completionHandler]; + }]; + }]; + }]; + + [task resume]; + + if (!task) { + completionHandler(nil, nil, + [NSError errorWithDomain:FIRCLSNetworkErrorDomain + code:FIRCLSNetworkErrorFailedToStartOperation + userInfo:nil]); + } +} + +- (void)startDataTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler { + [self startDataTaskWithRequest:request + retryLimit:retryLimit + tries:0 + completionHandler:completionHandler]; +} + +- (void)startDataTaskWithRequest:(NSURLRequest *)request + completionHandler:(FIRCLSNetworkDataTaskCompletionHandlerBlock)completionHandler { + [self startDataTaskWithRequest:request + retryLimit:FIRCLSNetworkMaximumRetryCount + completionHandler:completionHandler]; +} + +- (void)startDownloadTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + tries:(NSUInteger)tries + completionHandler: + (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler { + NSURLSessionTask *task = [self.session + downloadTaskWithRequest:request + completionHandler:^(NSURL *location, NSURLResponse *response, NSError *taskError) { + [FIRCLSNetworkResponseHandler + handleCompletedResponse:response + forOriginalRequest:request + error:taskError + block:^(BOOL retry, NSError *error) { + if (!retry) { + completionHandler(location, response, error); + return; + } + + if (tries >= retryLimit) { + NSDictionary *userInfo = @{ + @"retryLimit" : @(retryLimit), + NSURLErrorFailingURLStringErrorKey : request.URL + }; + completionHandler( + nil, nil, + [NSError + errorWithDomain:FIRCLSNetworkErrorDomain + code: + FIRCLSNetworkErrorMaximumAttemptsReached + userInfo:userInfo]); + return; + } + + [self + runAfterRetryValueFromResponse:response + attempts:tries + block:^{ + [self + startDownloadTaskWithRequest: + request + retryLimit: + retryLimit + tries: + (tries + + 1) + completionHandler: + completionHandler]; + }]; + }]; + }]; + + [task resume]; + + if (!task) { + completionHandler(nil, nil, + [NSError errorWithDomain:FIRCLSNetworkErrorDomain + code:FIRCLSNetworkErrorFailedToStartOperation + userInfo:nil]); + } +} + +- (void)startDownloadTaskWithRequest:(NSURLRequest *)request + retryLimit:(NSUInteger)retryLimit + completionHandler: + (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler { + [self startDownloadTaskWithRequest:request + retryLimit:retryLimit + tries:0 + completionHandler:completionHandler]; +} + +- (void)startDownloadTaskWithRequest:(NSURLRequest *)request + completionHandler: + (FIRCLSNetworkDownloadTaskCompletionHandlerBlock)completionHandler { + [self startDownloadTaskWithRequest:request + retryLimit:FIRCLSNetworkMaximumRetryCount + completionHandler:completionHandler]; +} + +- (void)invalidateAndCancel { + [self.session invalidateAndCancel]; +} + +#pragma mark - NSURLSession Delegate +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h new file mode 100644 index 0000000..42f0bb4 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h @@ -0,0 +1,87 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Type to indicate response status + */ +typedef NS_ENUM(NSInteger, FIRCLSNetworkClientResponseType) { + FIRCLSNetworkClientResponseSuccess, + FIRCLSNetworkClientResponseInvalid, + FIRCLSNetworkClientResponseFailure, + FIRCLSNetworkClientResponseRetry, + FIRCLSNetworkClientResponseBackOff +}; + +typedef NS_ENUM(NSInteger, FIRCLSNetworkErrorType) { + FIRCLSNetworkErrorUnknown = -1, + FIRCLSNetworkErrorFailedToStartOperation = -3, + FIRCLSNetworkErrorResponseInvalid = -4, + FIRCLSNetworkErrorRequestFailed = -5, + FIRCLSNetworkErrorMaximumAttemptsReached = -6, +}; + +extern NSInteger const FIRCLSNetworkErrorUnknownURLCancelReason; + +/** + * This block is an input parameter to handleCompletedResponse: and handleCompletedTask: methods of + * this class. + * @param retryMightSucceed is YES if the request should be retried. + * @param error is the error received back in response. + */ +typedef void (^FIRCLSNetworkResponseCompletionHandlerBlock)(BOOL retryMightSucceed, NSError *error); + +/** + * Error domain for Crashlytics network errors + */ +extern NSString *const FIRCLSNetworkErrorDomain; +/** + * This class handles network responses. + */ +@interface FIRCLSNetworkResponseHandler : NSObject +/** + * Returns the header in the given NSURLResponse with name as key + */ ++ (NSString *)headerForResponse:(NSURLResponse *)response withKey:(NSString *)key; +/** + * Returns Retry-After header value in response, and if absent returns a default retry value + */ ++ (NSTimeInterval)retryValueForResponse:(NSURLResponse *)response; +/** + * Checks if the content type for response matches the request + */ ++ (BOOL)contentTypeForResponse:(NSURLResponse *)response matchesRequest:(NSURLRequest *)request; + ++ (NSInteger)cancelReasonFromURLError:(NSError *)error; + ++ (BOOL)retryableURLError:(NSError *)error; + +/** + * Convenience method that calls back the input block with FIRCLSNetworkClientResponseType after + * checking the response code in response + */ ++ (void)clientResponseType:(NSURLResponse *)response + handler:(void (^)(FIRCLSNetworkClientResponseType type, + NSInteger statusCode))responseTypeAndStatusCodeHandlerBlock; +/** + * Handles a completed response for request and calls back input block. Populates error even if + * error was nil, but response code indicated an error. + */ ++ (void)handleCompletedResponse:(NSURLResponse *)response + forOriginalRequest:(NSURLRequest *)originalRequest + error:(NSError *)error + block:(FIRCLSNetworkResponseCompletionHandlerBlock)completionHandlerBlock; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.m new file mode 100644 index 0000000..cfcf42f --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.m @@ -0,0 +1,290 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSNetworkResponseHandler.h" + +@implementation FIRCLSNetworkResponseHandler + +static const NSTimeInterval kFIRCLSNetworkResponseHandlerDefaultRetryInterval = 2.0; +static NSString *const kFIRCLSNetworkResponseHandlerContentType = @"Content-Type"; +NSString *const FIRCLSNetworkErrorDomain = @"FIRCLSNetworkError"; + +NSInteger const FIRCLSNetworkErrorUnknownURLCancelReason = -1; + +#pragma mark - Header Handling ++ (NSString *)headerForResponse:(NSURLResponse *)response withKey:(NSString *)key { + if (![response respondsToSelector:@selector(allHeaderFields)]) { + return nil; + } + + return [((NSHTTPURLResponse *)response).allHeaderFields objectForKey:key]; +} + ++ (NSTimeInterval)retryValueForResponse:(NSURLResponse *)response { + NSString *retryValueString = [self headerForResponse:response withKey:@"Retry-After"]; + if (!retryValueString) { + return kFIRCLSNetworkResponseHandlerDefaultRetryInterval; + } + + NSTimeInterval value = retryValueString.doubleValue; + if (value < 0.0) { + return kFIRCLSNetworkResponseHandlerDefaultRetryInterval; + } + + return value; +} + ++ (NSString *)requestIdForResponse:(NSURLResponse *)response { + return [self headerForResponse:response withKey:@"X-Request-Id"]; +} + ++ (BOOL)contentTypeForResponse:(NSURLResponse *)response matchesRequest:(NSURLRequest *)request { + NSString *accept = [request.allHTTPHeaderFields objectForKey:@"Accept"]; + if (!accept) { + // An omitted accept header is defined to match everything + return YES; + } + + NSString *contentHeader = [self.class headerForResponse:response + withKey:kFIRCLSNetworkResponseHandlerContentType]; + if (!contentHeader) { + // FIRCLSDeveloperLog("Network", @"Content-Type not present in response"); + return NO; + } + + NSString *acceptCharset = request.allHTTPHeaderFields[@"Accept-Charset"]; + + NSArray *parts = [contentHeader componentsSeparatedByString:@"; charset="]; + if (!parts) { + parts = @[ contentHeader ]; + } + + if ([[parts objectAtIndex:0] caseInsensitiveCompare:accept] != NSOrderedSame) { + // FIRCLSDeveloperLog("Network", @"Content-Type does not match Accept"); + return NO; + } + + if (!acceptCharset) { + return YES; + } + + if (parts.count < 2) { + return YES; + } + + return [[parts objectAtIndex:1] caseInsensitiveCompare:acceptCharset] == NSOrderedSame; +} + ++ (NSInteger)cancelReasonFromURLError:(NSError *)error { + if (![[error domain] isEqualToString:NSURLErrorDomain]) { + return FIRCLSNetworkErrorUnknownURLCancelReason; + } + + if ([error code] != NSURLErrorCancelled) { + return FIRCLSNetworkErrorUnknownURLCancelReason; + } + + NSNumber *reason = [[error userInfo] objectForKey:NSURLErrorBackgroundTaskCancelledReasonKey]; + if (reason == nil) { + return FIRCLSNetworkErrorUnknownURLCancelReason; + } + + return [reason integerValue]; +} + ++ (BOOL)retryableURLError:(NSError *)error { + // So far, the only task errors seen are NSURLErrorDomain. For others, we're not + // sure what to do. + if (![[error domain] isEqualToString:NSURLErrorDomain]) { + return NO; + } + + // cases that we know are definitely not retryable + switch ([error code]) { + case NSURLErrorBadURL: + case NSURLErrorUnsupportedURL: + case NSURLErrorHTTPTooManyRedirects: + case NSURLErrorRedirectToNonExistentLocation: + case NSURLErrorUserCancelledAuthentication: + case NSURLErrorUserAuthenticationRequired: + case NSURLErrorAppTransportSecurityRequiresSecureConnection: + case NSURLErrorFileDoesNotExist: + case NSURLErrorFileIsDirectory: + case NSURLErrorDataLengthExceedsMaximum: + case NSURLErrorSecureConnectionFailed: + case NSURLErrorServerCertificateHasBadDate: + case NSURLErrorServerCertificateUntrusted: + case NSURLErrorServerCertificateHasUnknownRoot: + case NSURLErrorServerCertificateNotYetValid: + case NSURLErrorClientCertificateRejected: + case NSURLErrorClientCertificateRequired: + case NSURLErrorBackgroundSessionRequiresSharedContainer: + return NO; + } + + // All other errors, as far as I can tell, are things that could clear up + // without action on the part of the client. + + // NSURLErrorCancelled is a potential special-case. I believe there are + // situations where a cancelled request cannot be successfully restarted. But, + // until I can prove it, we'll retry. There are definitely many cases where + // a cancelled request definitely can be restarted and will work. + + return YES; +} + +#pragma mark - Error Creation ++ (NSError *)errorForCode:(NSInteger)code userInfo:(NSDictionary *)userInfo { + return [NSError errorWithDomain:FIRCLSNetworkErrorDomain code:code userInfo:userInfo]; +} + ++ (NSError *)errorForResponse:(NSURLResponse *)response + ofType:(FIRCLSNetworkClientResponseType)type + status:(NSInteger)status { + if (type == FIRCLSNetworkClientResponseSuccess) { + return nil; + } + + NSString *requestId = [self requestIdForResponse:response]; + NSString *contentType = [self headerForResponse:response + withKey:kFIRCLSNetworkResponseHandlerContentType]; + + // this could be nil, so be careful + requestId = requestId ? requestId : @""; + contentType = contentType ? contentType : @""; + + NSDictionary *userInfo = @{ + @"type" : @(type), + @"status_code" : @(status), + @"request_id" : requestId, + @"content_type" : contentType + }; + + // compute a reasonable error code type + NSInteger errorCode = FIRCLSNetworkErrorUnknown; + switch (type) { + case FIRCLSNetworkClientResponseFailure: + errorCode = FIRCLSNetworkErrorRequestFailed; + break; + case FIRCLSNetworkClientResponseInvalid: + errorCode = FIRCLSNetworkErrorResponseInvalid; + break; + default: + break; + } + + return [self errorForCode:errorCode userInfo:userInfo]; +} + ++ (void)clientResponseType:(NSURLResponse *)response + handler:(void (^)(FIRCLSNetworkClientResponseType type, + NSInteger statusCode))responseTypeAndStatusCodeHandlerBlock { + if (![response respondsToSelector:@selector(statusCode)]) { + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseInvalid, 0); + return; + } + + NSInteger code = ((NSHTTPURLResponse *)response).statusCode; + + switch (code) { + case 200: + case 201: + case 202: + case 204: + case 304: + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseSuccess, code); + return; + case 420: + case 429: + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseBackOff, code); + return; + case 408: + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseRetry, code); + return; + case 400: + case 401: + case 403: + case 404: + case 406: + case 410: + case 411: + case 413: + case 419: + case 422: + case 431: + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseFailure, code); + return; + } + + // check for a 5xx + if (code >= 500 && code <= 599) { + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseRetry, code); + return; + } + + responseTypeAndStatusCodeHandlerBlock(FIRCLSNetworkClientResponseInvalid, code); +} + ++ (void)handleCompletedResponse:(NSURLResponse *)response + forOriginalRequest:(NSURLRequest *)originalRequest + error:(NSError *)originalError + block: + (FIRCLSNetworkResponseCompletionHandlerBlock)completionHandlerBlock { + // if we have an error, we can just continue + if (originalError) { + BOOL retryable = [self retryableURLError:originalError]; + + completionHandlerBlock(retryable, originalError); + return; + } + + [self.class clientResponseType:response + handler:^(FIRCLSNetworkClientResponseType type, NSInteger statusCode) { + NSError *error = nil; + + switch (type) { + case FIRCLSNetworkClientResponseInvalid: + error = [self errorForResponse:response + ofType:type + status:statusCode]; + break; + case FIRCLSNetworkClientResponseBackOff: + case FIRCLSNetworkClientResponseRetry: + error = [self errorForResponse:response + ofType:type + status:statusCode]; + completionHandlerBlock(YES, error); + return; + case FIRCLSNetworkClientResponseFailure: + error = [self errorForResponse:response + ofType:type + status:statusCode]; + break; + case FIRCLSNetworkClientResponseSuccess: + if (![self contentTypeForResponse:response + matchesRequest:originalRequest]) { + error = [self errorForResponse:response + ofType:FIRCLSNetworkClientResponseInvalid + status:statusCode]; + break; + } + + break; + } + + completionHandlerBlock(NO, error); + }]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h new file mode 100644 index 0000000..c8fbaa9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h @@ -0,0 +1,44 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * This is a convenience class to ease constructing NSURLs. + */ +@interface FIRCLSURLBuilder : NSObject + +/** + * Convenience method that returns a FIRCLSURLBuilder instance with the input base URL appended to + * it. + */ ++ (instancetype)URLWithBase:(NSString *)base; +/** + * Appends the component to the URL being built by FIRCLSURLBuilder instance + */ +- (void)appendComponent:(NSString *)component; +/** + * Escapes and appends the component to the URL being built by FIRCLSURLBuilder instance + */ +- (void)escapeAndAppendComponent:(NSString *)component; +/** + * Adds a query and value to the URL being built + */ +- (void)appendValue:(id)value forQueryParam:(NSString *)param; +/** + * Returns the built URL + */ +- (NSURL *)URL; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.m new file mode 100644 index 0000000..58e6f25 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.m @@ -0,0 +1,104 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSNetworking/FIRCLSURLBuilder.h" + +#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h" + +@interface FIRCLSURLBuilder () + +@property(nonatomic) NSMutableString *URLString; +@property(nonatomic) NSUInteger queryParams; + +- (NSString *)escapeString:(NSString *)string; + +@end + +@implementation FIRCLSURLBuilder + ++ (instancetype)URLWithBase:(NSString *)base { + FIRCLSURLBuilder *url = [[FIRCLSURLBuilder alloc] init]; + + [url appendComponent:base]; + + return url; +} + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _URLString = [[NSMutableString alloc] init]; + _queryParams = 0; + + return self; +} + +- (NSString *)escapeString:(NSString *)string { +#if TARGET_OS_WATCH + // TODO: Question - Why does watchOS use a different encoding from the other platforms and the + // Android SDK? + // This broken the unit test on watchOS: https://github.com/firebase/firebase-ios-sdk/pull/10511 + return + [string stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet + URLPathAllowedCharacterSet]]; +#else + return + [string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet + .URLQueryAllowedCharacterSet]; +#endif +} + +- (void)appendComponent:(NSString *)component { + if (component.length == 0) { + FIRCLSErrorLog(@"URLBuilder parameter component must not be empty"); + return; + } + + [self.URLString appendString:component]; +} + +- (void)escapeAndAppendComponent:(NSString *)component { + [self appendComponent:[self escapeString:component]]; +} + +- (void)appendValue:(id)value forQueryParam:(NSString *)param { + if (!value) { + return; + } + + if (self.queryParams == 0) { + [self appendComponent:@"?"]; + } else { + [self appendComponent:@"&"]; + } + + self.queryParams += 1; + + [self appendComponent:param]; + [self appendComponent:@"="]; + if ([value isKindOfClass:NSString.class]) { + [self escapeAndAppendComponent:value]; + } else { + [self escapeAndAppendComponent:[value description]]; + } +} + +- (NSURL *)URL { + return [NSURL URLWithString:self.URLString]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h new file mode 100644 index 0000000..07be334 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h @@ -0,0 +1,58 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h" + +/** + * If the compound operation is sent a @c -[cancel] message while executing, it will attempt to + * cancel all operations on its internal queue, and will return an error in its @c asyncCompletion + * block with this value as its code. + */ +FOUNDATION_EXPORT const NSUInteger FIRCLSCompoundOperationErrorCodeCancelled; + +/** + * If one or more of the operations on the @c compoundQueue fail, this operation returns an error + * in its @c asyncCompletion block with this code, and an array of @c NSErrors keyed on @c + * FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors in the @c userInfo dictionary. + */ +FOUNDATION_EXPORT const NSUInteger FIRCLSCompoundOperationErrorCodeSuboperationFailed; + +/** + * When all the operations complete, this @c FIRCLSCompoundOperation instance's @c asyncCompletion + * block is called. If any errors were passed by the suboperations' @c asyncCompletion blocks, they + * are put in an array which can be accessed in the @c userInfo dictionary in the error parameter + * for this instance's @c asyncCompletion block. + */ +FOUNDATION_EXPORT NSString *const FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors; + +/** + * An operation that executes a collection of suboperations on an internal private queue. Any + * instance of @c FIRCLSFABAsyncOperation passed into this instance's @c operations property has the + * potential to return an @c NSError in its @c asyncCompletion block. This instance's @c + * asyncCompletion block will put all such errors in an @c NSArray and return an @c NSError whose @c + * userInfo contains that array keyed by @c FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors. + */ +@interface FIRCLSCompoundOperation : FIRCLSFABAsyncOperation + +/** + * An array of @c NSOperations to execute, which can include instances of @c FIRCLSFABAsyncOperation + * or + * @c FIRCLSCompoundOperation. This operation will not be marked as finished until all suboperations + * are marked as finished. + */ +@property(copy, nonatomic) NSArray *operations; + +@property(strong, nonatomic, readonly) NSOperationQueue *compoundQueue; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.m new file mode 100644 index 0000000..92bd06b --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.m @@ -0,0 +1,165 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h" + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h" + +#define FIRCLS_DISPATCH_QUEUES_AS_OBJECTS OS_OBJECT_USE_OBJC_RETAIN_RELEASE + +const NSUInteger FIRCLSCompoundOperationErrorCodeCancelled = UINT_MAX - 1; +const NSUInteger FIRCLSCompoundOperationErrorCodeSuboperationFailed = UINT_MAX - 2; + +NSString *const FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors = + @"com.google.firebase.crashlytics.FIRCLSCompoundOperation.error.user-info-key.underlying-" + @"errors"; + +static NSString *const FIRCLSCompoundOperationErrorDomain = + @"com.google.firebase.crashlytics.FIRCLSCompoundOperation.error"; +static char *const FIRCLSCompoundOperationCountingQueueLabel = + "com.google.firebase.crashlytics.FIRCLSCompoundOperation.dispatch-queue.counting-queue"; + +@interface FIRCLSCompoundOperation () + +@property(strong, nonatomic, readwrite) NSOperationQueue *compoundQueue; +@property(assign, nonatomic) NSUInteger completedOperations; +@property(strong, nonatomic) NSMutableArray *errors; +#if FIRCLS_DISPATCH_QUEUES_AS_OBJECTS +@property(strong, nonatomic) dispatch_queue_t countingQueue; +#else +@property(assign, nonatomic) dispatch_queue_t countingQueue; +#endif + +@end + +@implementation FIRCLSCompoundOperation + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _compoundQueue = [[NSOperationQueue alloc] init]; + _completedOperations = 0; + _errors = [NSMutableArray array]; + _countingQueue = + dispatch_queue_create(FIRCLSCompoundOperationCountingQueueLabel, DISPATCH_QUEUE_SERIAL); + + return self; +} + +#if !FIRCLS_DISPATCH_QUEUES_AS_OBJECTS +- (void)dealloc { + if (_countingQueue) { + dispatch_release(_countingQueue); + } +} +#endif + +- (void)main { + for (FIRCLSFABAsyncOperation *operation in self.operations) { + [self injectCompoundAsyncCompletionInOperation:operation]; + [self injectCompoundSyncCompletionInOperation:operation]; + + [self.compoundQueue addOperation:operation]; + } +} + +- (void)cancel { + if (self.compoundQueue.operations.count > 0) { + [self.compoundQueue cancelAllOperations]; + dispatch_sync(self.countingQueue, ^{ + [self attemptCompoundCompletion]; + }); + } else { + for (NSOperation *operation in self.operations) { + [operation cancel]; + } + + // we have to add the operations to the queue in order for their isFinished property to be set + // to true. + [self.compoundQueue addOperations:self.operations waitUntilFinished:NO]; + } + [super cancel]; +} + +- (void)injectCompoundAsyncCompletionInOperation:(FIRCLSFABAsyncOperation *)operation { + __weak FIRCLSCompoundOperation *weakSelf = self; + FIRCLSFABAsyncOperationCompletionBlock originalAsyncCompletion = [operation.asyncCompletion copy]; + FIRCLSFABAsyncOperationCompletionBlock completion = ^(NSError *error) { + __strong FIRCLSCompoundOperation *strongSelf = weakSelf; + + if (originalAsyncCompletion) { + dispatch_sync(strongSelf.countingQueue, ^{ + originalAsyncCompletion(error); + }); + } + + [strongSelf updateCompletionCountsWithError:error]; + }; + operation.asyncCompletion = completion; +} + +- (void)injectCompoundSyncCompletionInOperation:(FIRCLSFABAsyncOperation *)operation { + __weak FIRCLSCompoundOperation *weakSelf = self; + void (^originalSyncCompletion)(void) = [operation.completionBlock copy]; + void (^completion)(void) = ^{ + __strong FIRCLSCompoundOperation *strongSelf = weakSelf; + + if (originalSyncCompletion) { + dispatch_sync(strongSelf.countingQueue, ^{ + originalSyncCompletion(); + }); + } + + dispatch_sync(strongSelf.countingQueue, ^{ + [strongSelf attemptCompoundCompletion]; + }); + }; + operation.completionBlock = completion; +} + +- (void)updateCompletionCountsWithError:(NSError *)error { + dispatch_sync(self.countingQueue, ^{ + if (!error) { + self.completedOperations += 1; + } else { + [self.errors addObject:error]; + } + }); +} + +- (void)attemptCompoundCompletion { + if (self.isCancelled) { + [self finishWithError:[NSError errorWithDomain:FIRCLSCompoundOperationErrorDomain + code:FIRCLSCompoundOperationErrorCodeCancelled + userInfo:@{ + NSLocalizedDescriptionKey : [NSString + stringWithFormat:@"%@ cancelled", self.name] + }]]; + self.asyncCompletion = nil; + } else if (self.completedOperations + self.errors.count == self.operations.count) { + NSError *error = nil; + if (self.errors.count > 0) { + error = [NSError + errorWithDomain:FIRCLSCompoundOperationErrorDomain + code:FIRCLSCompoundOperationErrorCodeSuboperationFailed + userInfo:@{FIRCLSCompoundOperationErrorUserInfoKeyUnderlyingErrors : self.errors}]; + } + [self finishWithError:error]; + } +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h new file mode 100644 index 0000000..e5d2c7e --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h @@ -0,0 +1,39 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Completion block that can be called in your subclass implementation. It is up to you when you + * want to call it. + */ +typedef void (^FIRCLSFABAsyncOperationCompletionBlock)(NSError *__nullable error); + +/** + * FIRCLSFABAsyncOperation is a subclass of NSOperation that allows for asynchronous work to be + * performed, for things like networking, IPC or UI-driven logic. Create your own subclasses to + * encapsulate custom logic. + * @warning When subclassing to create your own operations, be sure to call -[finishWithError:] at + * some point, or program execution will hang. + * @see -[finishWithError:] in FIRCLSFABAsyncOperation_Private.h + */ +@interface FIRCLSFABAsyncOperation : NSOperation + +/** + * Add a callback method for consumers of your subclasses to set when the asynchronous work is + * marked as complete with -[finishWithError:]. + */ +@property(copy, nonatomic, nullable) FIRCLSFABAsyncOperationCompletionBlock asyncCompletion; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.m new file mode 100644 index 0000000..01365e5 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.m @@ -0,0 +1,146 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h" + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h" + +@interface FIRCLSFABAsyncOperation () { + BOOL _internalExecuting; + BOOL _internalFinished; +} + +@property(nonatomic, strong) NSRecursiveLock *lock; + +@end + +@implementation FIRCLSFABAsyncOperation + +- (instancetype)init { + self = [super init]; + if (!self) { + return nil; + } + + _internalExecuting = NO; + _internalFinished = NO; + + _lock = [[NSRecursiveLock alloc] init]; + _lock.name = [NSString stringWithFormat:@"com.google.firebase.crashlytics.%@-lock", [self class]]; + ; + + return self; +} + +#pragma mark - NSOperation Overrides +- (BOOL)isConcurrent { + return YES; +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (BOOL)isExecuting { + [self.lock lock]; + BOOL result = _internalExecuting; + [self.lock unlock]; + + return result; +} + +- (BOOL)isFinished { + [self.lock lock]; + BOOL result = _internalFinished; + [self.lock unlock]; + + return result; +} + +- (void)start { + if ([self checkForCancellation]) { + return; + } + + [self markStarted]; + + [self main]; +} + +#pragma mark - Utilities +- (void)changeValueForKey:(NSString *)key inBlock:(void (^)(void))block { + [self willChangeValueForKey:key]; + block(); + [self didChangeValueForKey:key]; +} + +- (void)lock:(void (^)(void))block { + [self.lock lock]; + block(); + [self.lock unlock]; +} + +- (BOOL)checkForCancellation { + if ([self isCancelled]) { + [self markDone]; + return YES; + } + + return NO; +} + +#pragma mark - State Management +- (void)unlockedMarkFinished { + [self changeValueForKey:@"isFinished" + inBlock:^{ + self->_internalFinished = YES; + }]; +} + +- (void)unlockedMarkStarted { + [self changeValueForKey:@"isExecuting" + inBlock:^{ + self->_internalExecuting = YES; + }]; +} + +- (void)unlockedMarkComplete { + [self changeValueForKey:@"isExecuting" + inBlock:^{ + self->_internalExecuting = NO; + }]; +} + +- (void)markStarted { + [self lock:^{ + [self unlockedMarkStarted]; + }]; +} + +- (void)markDone { + [self lock:^{ + [self unlockedMarkComplete]; + [self unlockedMarkFinished]; + }]; +} + +#pragma mark - Protected +- (void)finishWithError:(NSError *)error { + if (self.asyncCompletion) { + self.asyncCompletion(error); + } + [self markDone]; +} + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h new file mode 100644 index 0000000..f2fa4aa --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h @@ -0,0 +1,32 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h" + +@interface FIRCLSFABAsyncOperation (Private) + +/** + * Subclasses must call this method when they are done performing work. When it is called is up to + * you; it can be directly after kicking of a network request, say, or in the callback for its + * response. Once this method is called, the operation queue it is on will begin executing the next + * waiting operation. If you directly invoked -[start] on the instance, execution will proceed to + * the next code statement. + * @note as soon as this method is called, @c NSOperation's standard @c completionBlock will be + * executed if one exists, as a result of setting the operation's isFinished property to YES, and + * the asyncCompletion block is called. + * @param error Any error to pass to asyncCompletion, or nil if there is none. + */ +- (void)finishWithError:(NSError *__nullable)error; + +@end diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSOperation.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSOperation.h new file mode 100644 index 0000000..d70dd66 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSOperation/FIRCLSOperation.h @@ -0,0 +1,19 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSCompoundOperation.h" +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation.h" +#import "Crashlytics/Shared/FIRCLSOperation/FIRCLSFABAsyncOperation_Private.h" diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.h b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.h new file mode 100644 index 0000000..87a2151 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.h @@ -0,0 +1,26 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "Crashlytics/Shared/FIRCLSConstants.h" + +/** + * Generates and returns a UUID + */ +NSString *FIRCLSGenerateUUID(void); + +/** + * Converts the input uint8_t UUID to String + */ +NSString *FIRCLSUUIDToNSString(const uint8_t *uuid); diff --git a/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.m b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.m new file mode 100644 index 0000000..47ce771 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/Shared/FIRCLSUUID.m @@ -0,0 +1,39 @@ +// Copyright 2019 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "Crashlytics/Shared/FIRCLSUUID.h" + +#import "Crashlytics/Shared/FIRCLSByteUtility.h" + +static NSInteger const FIRCLSUUIDStringLength = 33; + +#pragma mark Public methods + +NSString *FIRCLSGenerateUUID(void) { + NSString *string; + + CFUUIDRef uuid = CFUUIDCreate(kCFAllocatorDefault); + string = CFBridgingRelease(CFUUIDCreateString(kCFAllocatorDefault, uuid)); + CFRelease(uuid); + + return string; +} + +NSString *FIRCLSUUIDToNSString(const uint8_t *uuid) { + char uuidString[FIRCLSUUIDStringLength]; + + FIRCLSSafeHexToString(uuid, 16, uuidString); + + return [NSString stringWithUTF8String:uuidString]; +} diff --git a/Pods/FirebaseCrashlytics/Crashlytics/third_party/libunwind/dwarf.h b/Pods/FirebaseCrashlytics/Crashlytics/third_party/libunwind/dwarf.h new file mode 100644 index 0000000..9c81868 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Crashlytics/third_party/libunwind/dwarf.h @@ -0,0 +1,256 @@ +/* libunwind - a platform-independent unwind library + Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. + Contributed by David Mosberger-Tang + +This file is part of libunwind. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ + +#pragma once + +// +#define DWARF_EXTENDED_LENGTH_FLAG (0xffffffff) +#define DWARF_CIE_ID_CIE_FLAG (0) + +// Exception Handling Pointer Encoding constants +#define DW_EH_PE_VALUE_MASK (0x0F) +#define DW_EH_PE_RELATIVE_OFFSET_MASK (0x70) + +// Register Definitions +#define DW_EN_MAX_REGISTER_NUMBER (120) + +enum { + DW_EH_PE_ptr = 0x00, + DW_EH_PE_uleb128 = 0x01, + DW_EH_PE_udata2 = 0x02, + DW_EH_PE_udata4 = 0x03, + DW_EH_PE_udata8 = 0x04, + DW_EH_PE_signed = 0x08, + DW_EH_PE_sleb128 = 0x09, + DW_EH_PE_sdata2 = 0x0A, + DW_EH_PE_sdata4 = 0x0B, + DW_EH_PE_sdata8 = 0x0C, + + DW_EH_PE_absptr = 0x00, + DW_EH_PE_pcrel = 0x10, + DW_EH_PE_textrel = 0x20, + DW_EH_PE_datarel = 0x30, + DW_EH_PE_funcrel = 0x40, + DW_EH_PE_aligned = 0x50, + DW_EH_PE_indirect = 0x80, + DW_EH_PE_omit = 0xFF +}; + +// Unwind Instructions + +#define DW_CFA_OPCODE_MASK (0xC0) +#define DW_CFA_OPERAND_MASK (0x3F) + +enum { + DW_CFA_nop = 0x0, + DW_CFA_set_loc = 0x1, + DW_CFA_advance_loc1 = 0x2, + DW_CFA_advance_loc2 = 0x3, + DW_CFA_advance_loc4 = 0x4, + DW_CFA_offset_extended = 0x5, + DW_CFA_restore_extended = 0x6, + DW_CFA_undefined = 0x7, + DW_CFA_same_value = 0x8, + DW_CFA_register = 0x9, + DW_CFA_remember_state = 0xA, + DW_CFA_restore_state = 0xB, + DW_CFA_def_cfa = 0xC, + DW_CFA_def_cfa_register = 0xD, + DW_CFA_def_cfa_offset = 0xE, + DW_CFA_def_cfa_expression = 0xF, + DW_CFA_expression = 0x10, + DW_CFA_offset_extended_sf = 0x11, + DW_CFA_def_cfa_sf = 0x12, + DW_CFA_def_cfa_offset_sf = 0x13, + DW_CFA_val_offset = 0x14, + DW_CFA_val_offset_sf = 0x15, + DW_CFA_val_expression = 0x16, + + // opcode is in high 2 bits, operand in is lower 6 bits + DW_CFA_advance_loc = 0x40, // operand is delta + DW_CFA_offset = 0x80, // operand is register + DW_CFA_restore = 0xC0, // operand is register + + // GNU extensions + DW_CFA_GNU_window_save = 0x2D, + DW_CFA_GNU_args_size = 0x2E, + DW_CFA_GNU_negative_offset_extended = 0x2F +}; + +// Expression Instructions +enum { + DW_OP_addr = 0x03, + DW_OP_deref = 0x06, + DW_OP_const1u = 0x08, + DW_OP_const1s = 0x09, + DW_OP_const2u = 0x0A, + DW_OP_const2s = 0x0B, + DW_OP_const4u = 0x0C, + DW_OP_const4s = 0x0D, + DW_OP_const8u = 0x0E, + DW_OP_const8s = 0x0F, + DW_OP_constu = 0x10, + DW_OP_consts = 0x11, + DW_OP_dup = 0x12, + DW_OP_drop = 0x13, + DW_OP_over = 0x14, + DW_OP_pick = 0x15, + DW_OP_swap = 0x16, + DW_OP_rot = 0x17, + DW_OP_xderef = 0x18, + DW_OP_abs = 0x19, + DW_OP_and = 0x1A, + DW_OP_div = 0x1B, + DW_OP_minus = 0x1C, + DW_OP_mod = 0x1D, + DW_OP_mul = 0x1E, + DW_OP_neg = 0x1F, + DW_OP_not = 0x20, + DW_OP_or = 0x21, + DW_OP_plus = 0x22, + DW_OP_plus_uconst = 0x23, + DW_OP_shl = 0x24, + DW_OP_shr = 0x25, + DW_OP_shra = 0x26, + DW_OP_xor = 0x27, + DW_OP_skip = 0x2F, + DW_OP_bra = 0x28, + DW_OP_eq = 0x29, + DW_OP_ge = 0x2A, + DW_OP_gt = 0x2B, + DW_OP_le = 0x2C, + DW_OP_lt = 0x2D, + DW_OP_ne = 0x2E, + DW_OP_lit0 = 0x30, + DW_OP_lit1 = 0x31, + DW_OP_lit2 = 0x32, + DW_OP_lit3 = 0x33, + DW_OP_lit4 = 0x34, + DW_OP_lit5 = 0x35, + DW_OP_lit6 = 0x36, + DW_OP_lit7 = 0x37, + DW_OP_lit8 = 0x38, + DW_OP_lit9 = 0x39, + DW_OP_lit10 = 0x3A, + DW_OP_lit11 = 0x3B, + DW_OP_lit12 = 0x3C, + DW_OP_lit13 = 0x3D, + DW_OP_lit14 = 0x3E, + DW_OP_lit15 = 0x3F, + DW_OP_lit16 = 0x40, + DW_OP_lit17 = 0x41, + DW_OP_lit18 = 0x42, + DW_OP_lit19 = 0x43, + DW_OP_lit20 = 0x44, + DW_OP_lit21 = 0x45, + DW_OP_lit22 = 0x46, + DW_OP_lit23 = 0x47, + DW_OP_lit24 = 0x48, + DW_OP_lit25 = 0x49, + DW_OP_lit26 = 0x4A, + DW_OP_lit27 = 0x4B, + DW_OP_lit28 = 0x4C, + DW_OP_lit29 = 0x4D, + DW_OP_lit30 = 0x4E, + DW_OP_lit31 = 0x4F, + DW_OP_reg0 = 0x50, + DW_OP_reg1 = 0x51, + DW_OP_reg2 = 0x52, + DW_OP_reg3 = 0x53, + DW_OP_reg4 = 0x54, + DW_OP_reg5 = 0x55, + DW_OP_reg6 = 0x56, + DW_OP_reg7 = 0x57, + DW_OP_reg8 = 0x58, + DW_OP_reg9 = 0x59, + DW_OP_reg10 = 0x5A, + DW_OP_reg11 = 0x5B, + DW_OP_reg12 = 0x5C, + DW_OP_reg13 = 0x5D, + DW_OP_reg14 = 0x5E, + DW_OP_reg15 = 0x5F, + DW_OP_reg16 = 0x60, + DW_OP_reg17 = 0x61, + DW_OP_reg18 = 0x62, + DW_OP_reg19 = 0x63, + DW_OP_reg20 = 0x64, + DW_OP_reg21 = 0x65, + DW_OP_reg22 = 0x66, + DW_OP_reg23 = 0x67, + DW_OP_reg24 = 0x68, + DW_OP_reg25 = 0x69, + DW_OP_reg26 = 0x6A, + DW_OP_reg27 = 0x6B, + DW_OP_reg28 = 0x6C, + DW_OP_reg29 = 0x6D, + DW_OP_reg30 = 0x6E, + DW_OP_reg31 = 0x6F, + DW_OP_breg0 = 0x70, + DW_OP_breg1 = 0x71, + DW_OP_breg2 = 0x72, + DW_OP_breg3 = 0x73, + DW_OP_breg4 = 0x74, + DW_OP_breg5 = 0x75, + DW_OP_breg6 = 0x76, + DW_OP_breg7 = 0x77, + DW_OP_breg8 = 0x78, + DW_OP_breg9 = 0x79, + DW_OP_breg10 = 0x7A, + DW_OP_breg11 = 0x7B, + DW_OP_breg12 = 0x7C, + DW_OP_breg13 = 0x7D, + DW_OP_breg14 = 0x7E, + DW_OP_breg15 = 0x7F, + DW_OP_breg16 = 0x80, + DW_OP_breg17 = 0x81, + DW_OP_breg18 = 0x82, + DW_OP_breg19 = 0x83, + DW_OP_breg20 = 0x84, + DW_OP_breg21 = 0x85, + DW_OP_breg22 = 0x86, + DW_OP_breg23 = 0x87, + DW_OP_breg24 = 0x88, + DW_OP_breg25 = 0x89, + DW_OP_breg26 = 0x8A, + DW_OP_breg27 = 0x8B, + DW_OP_breg28 = 0x8C, + DW_OP_breg29 = 0x8D, + DW_OP_breg30 = 0x8E, + DW_OP_breg31 = 0x8F, + DW_OP_regx = 0x90, + DW_OP_fbreg = 0x91, + DW_OP_bregx = 0x92, + DW_OP_piece = 0x93, + DW_OP_deref_size = 0x94, + DW_OP_xderef_size = 0x95, + DW_OP_nop = 0x96, + DW_OP_push_object_addres = 0x97, + DW_OP_call2 = 0x98, + DW_OP_call4 = 0x99, + DW_OP_call_ref = 0x9A, + DW_OP_lo_user = 0xE0, + DW_OP_APPLE_uninit = 0xF0, + DW_OP_hi_user = 0xFF +}; diff --git a/Pods/FirebaseCrashlytics/CrashlyticsInputFiles.xcfilelist b/Pods/FirebaseCrashlytics/CrashlyticsInputFiles.xcfilelist new file mode 100644 index 0000000..d4926e8 --- /dev/null +++ b/Pods/FirebaseCrashlytics/CrashlyticsInputFiles.xcfilelist @@ -0,0 +1,5 @@ +$(TARGET_BUILD_DIR)/$(UNLOCALIZED_RESOURCES_FOLDER_PATH)/GoogleService-Info.plist +$(TARGET_BUILD_DIR)/$(EXECUTABLE_PATH) +${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME} +${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Info.plist +${DWARF_DSYM_FOLDER_PATH}/${DWARF_DSYM_FILE_NAME}/Contents/Resources/DWARF/${PRODUCT_NAME} diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseCrashlytics/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/Pods/FirebaseCrashlytics/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/Pods/FirebaseCrashlytics/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInterop.h b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInterop.h new file mode 100644 index 0000000..3b49733 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInterop.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol FIRAnalyticsInteropListener; + +NS_ASSUME_NONNULL_BEGIN + +/// Block typedef callback parameter to `getUserProperties(with:)`. +typedef void (^FIRAInteropUserPropertiesCallback)(NSDictionary *userProperties) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Connector for bridging communication between Firebase SDKs and FirebaseAnalytics APIs. +@protocol FIRAnalyticsInterop + +/// Sets user property when trigger event is logged. This API is only available in the SDK. +- (void)setConditionalUserProperty:(NSDictionary *)conditionalUserProperty; + +/// Clears user property if set. +- (void)clearConditionalUserProperty:(NSString *)userPropertyName + forOrigin:(NSString *)origin + clearEventName:(NSString *)clearEventName + clearEventParameters:(NSDictionary *)clearEventParameters; + +/// Returns currently set user properties. +- (NSArray *> *)conditionalUserProperties:(NSString *)origin + propertyNamePrefix: + (NSString *)propertyNamePrefix; + +/// Returns the maximum number of user properties. +- (NSInteger)maxUserProperties:(NSString *)origin; + +/// Returns the user properties to a callback function. +- (void)getUserPropertiesWithCallback: + (void (^)(NSDictionary *userProperties))callback; + +/// Logs events. +- (void)logEventWithOrigin:(NSString *)origin + name:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets user property. +- (void)setUserPropertyWithOrigin:(NSString *)origin name:(NSString *)name value:(id)value; + +/// Registers an Analytics listener for the given origin. +- (void)registerAnalyticsListener:(id)listener + withOrigin:(NSString *)origin; + +/// Unregisters an Analytics listener for the given origin. +- (void)unregisterAnalyticsListenerWithOrigin:(NSString *)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInteropListener.h b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInteropListener.h new file mode 100644 index 0000000..327aefd --- /dev/null +++ b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRAnalyticsInteropListener.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Handles events and messages from Analytics. +@protocol FIRAnalyticsInteropListener + +/// Triggers when an Analytics event happens for the registered origin with +/// FirebaseAnalyticsInterop`s `registerAnalyticsListener(_:withOrigin:)`. +- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters; + +@end diff --git a/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropEventNames.h b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropEventNames.h new file mode 100644 index 0000000..efc54ab --- /dev/null +++ b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropEventNames.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// @file FIRInteropEventNames.h + +#import + +/// Notification open event name. +static NSString *const kFIRIEventNotificationOpen = @"_no"; + +/// Notification foreground event name. +static NSString *const kFIRIEventNotificationForeground = @"_nf"; + +/// Campaign event name. +static NSString *const kFIRIEventFirebaseCampaign = @"_cmp"; diff --git a/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropParameterNames.h b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropParameterNames.h new file mode 100644 index 0000000..f640702 --- /dev/null +++ b/Pods/FirebaseCrashlytics/Interop/Analytics/Public/FIRInteropParameterNames.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// @file FIRInteropParameterNames.h +/// +/// Predefined event parameter names used by Firebase. This file is a subset of the +/// FirebaseAnalytics FIRParameterNames.h public header. +/// +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       kFIRParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Message identifier. +static NSString *const kFIRIParameterMessageIdentifier = @"_nmid"; + +/// Message name. +static NSString *const kFIRIParameterMessageName = @"_nmn"; + +/// Message send time. +static NSString *const kFIRIParameterMessageTime = @"_nmt"; + +/// Message device time. +static NSString *const kFIRIParameterMessageDeviceTime = @"_ndt"; + +/// Topic message. +static NSString *const kFIRIParameterTopic = @"_nt"; + +/// Stores the message_id of the last notification opened by the app. +static NSString *const kFIRIUserPropertyLastNotification = @"_ln"; diff --git a/Pods/FirebaseCrashlytics/README.md b/Pods/FirebaseCrashlytics/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseCrashlytics/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseCrashlytics/run b/Pods/FirebaseCrashlytics/run new file mode 100755 index 0000000..93a6f11 --- /dev/null +++ b/Pods/FirebaseCrashlytics/run @@ -0,0 +1,72 @@ +#!/bin/sh + +# Copyright 2019 Google +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# run +# +# This script is meant to be run as a Run Script in the "Build Phases" section +# of your Xcode project. It sends debug symbols to symbolicate stacktraces, +# sends build events to track versions, and onboards apps for Crashlytics. +# +# This script calls upload-symbols twice: +# +# 1) First it calls upload-symbols synchronously in "validation" mode. If the +# script finds issues with the build environment, it will report errors to Xcode. +# In validation mode it exits before doing any time consuming work. +# +# 2) Then it calls upload-symbols in the background to actually send the build +# event and upload symbols. It does this in the background so that it doesn't +# slow down your builds. If an error happens here, you won't see it in Xcode. +# +# You can find the output for the background execution in Console.app, by +# searching for "upload-symbols". +# +# If you want verbose output, you can pass the --debug flag to this script +# + +# Figure out where we're being called from +DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd ) + +# Build up the arguments list, passing through any flags added, and quoting +# every argument in case there are spaces in any of the paths. +ARGUMENTS='' +for i in "$@"; do + ARGUMENTS="$ARGUMENTS \"$i\"" +done + +VALIDATE_ARGUMENTS="$ARGUMENTS --build-phase --validate" +UPLOAD_ARGUMENTS="$ARGUMENTS --build-phase" + +# Quote the path to handle folders with special characters +COMMAND_PATH="\"$DIR/upload-symbols\" " + +# Ensure params are as expected, run in sync mode to validate, +# and cause a build error if validation fails +eval $COMMAND_PATH$VALIDATE_ARGUMENTS +return_code=$? + +if [[ $return_code != 0 ]]; then + exit $return_code +fi + +# Verification passed, convert and upload dSYMs in the background to prevent +# build delays +# +# Note: Validation is performed again at this step before upload +# +# Note: Output can still be found in Console.app, by searching for +# "upload-symbols" +# +eval $COMMAND_PATH$UPLOAD_ARGUMENTS > /dev/null 2>&1 & diff --git a/Pods/FirebaseCrashlytics/upload-symbols b/Pods/FirebaseCrashlytics/upload-symbols new file mode 100755 index 0000000..481428e Binary files /dev/null and b/Pods/FirebaseCrashlytics/upload-symbols differ diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h new file mode 100644 index 0000000..8aed7b1 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h" + +@class FIRInstallationsHTTPError; +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer); + +@interface FIRInstallationsErrorUtil : NSObject + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception; ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error; + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status; + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName; + ++ (NSError *)JSONSerializationError:(NSError *)error; + ++ (NSError *)networkErrorWithError:(NSError *)error; + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName; + ++ (NSError *)corruptedIIDTokenData; + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data; ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode; + ++ (NSError *)backoffIntervalWaitError; + +/** + * Returns the passed error if it is already in the public domain or a new error with the passed + * error at `NSUnderlyingErrorKey`. + */ ++ (NSError *)publicDomainErrorWithError:(NSError *)error; + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error; + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m new file mode 100644 index 0000000..5673600 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.m @@ -0,0 +1,145 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +NSString *const kFirebaseInstallationsErrorDomain = @"com.firebase.installations"; + +void FIRInstallationsItemSetErrorToPointer(NSError *error, NSError **pointer) { + if (pointer != NULL) { + *pointer = error; + } +} + +@implementation FIRInstallationsErrorUtil + ++ (NSError *)keyedArchiverErrorWithException:(NSException *)exception { + NSString *failureReason = [NSString + stringWithFormat:@"NSKeyedArchiver exception with name: %@, reason: %@, userInfo: %@", + exception.name, exception.reason, exception.userInfo]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)keyedArchiverErrorWithError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"NSKeyedArchiver error."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:error]; +} + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeKeychain + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)installationItemNotFoundForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *failureReason = + [NSString stringWithFormat:@"Installation for appID %@ appName %@ not found", appID, appName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)corruptedIIDTokenData { + NSString *failureReason = + @"IID token data stored in Keychain is corrupted or in an incompatible format."; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (FIRInstallationsHTTPError *)APIErrorWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:HTTPResponse data:data]; +} + ++ (BOOL)isAPIError:(NSError *)error withHTTPCode:(NSInteger)HTTPCode { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + return [(FIRInstallationsHTTPError *)error HTTPResponse].statusCode == HTTPCode; +} + ++ (NSError *)JSONSerializationError:(NSError *)error { + NSString *failureReason = [NSString stringWithFormat:@"Failed to serialize JSON data."]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)FIDRegistrationErrorWithResponseMissingField:(NSString *)missingFieldName { + NSString *failureReason = [NSString + stringWithFormat:@"A required response field with name %@ is missing", missingFieldName]; + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; +} + ++ (NSError *)networkErrorWithError:(NSError *)error { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Network connection error." + underlyingError:error]; +} + ++ (NSError *)backoffIntervalWaitError { + return [self installationsErrorWithCode:FIRInstallationsErrorCodeServerUnreachable + failureReason:@"Too many server requests." + underlyingError:nil]; +} + ++ (NSError *)publicDomainErrorWithError:(NSError *)error { + if ([error.domain isEqualToString:kFirebaseInstallationsErrorDomain]) { + return error; + } + + return [self installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:nil + underlyingError:error]; +} + ++ (NSError *)installationsErrorWithCode:(FIRInstallationsErrorCode)code + failureReason:(nullable NSString *)failureReason + underlyingError:(nullable NSError *)underlyingError { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSUnderlyingErrorKey] = underlyingError; + userInfo[NSLocalizedFailureReasonErrorKey] = + failureReason + ?: [NSString + stringWithFormat:@"Underlying error: %@", underlyingError.localizedDescription]; + + return [NSError errorWithDomain:kFirebaseInstallationsErrorDomain code:code userInfo:userInfo]; +} + ++ (FBLPromise *)rejectedPromiseWithError:(NSError *)error { + FBLPromise *rejectedPromise = [FBLPromise pendingPromise]; + [rejectedPromise reject:error]; + return rejectedPromise; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h new file mode 100644 index 0000000..b978b77 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Represents an error caused by an unexpected API response. */ +@interface FIRInstallationsHTTPError : NSError + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, readonly, nonnull) NSData *data; + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse data:(nullable NSData *)data; + +@end + +NS_ASSUME_NONNULL_END + +typedef NS_ENUM(NSInteger, FIRInstallationsHTTPCodes) { + FIRInstallationsHTTPCodesTooManyRequests = 429, + FIRInstallationsHTTPCodesServerInternalError = 500, +}; + +/** Possible response HTTP codes for `CreateInstallation` API request. */ +typedef NS_ENUM(NSInteger, FIRInstallationsRegistrationHTTPCode) { + FIRInstallationsRegistrationHTTPCodeSuccess = 201, + FIRInstallationsRegistrationHTTPCodeInvalidArgument = 400, + FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch = 403, + FIRInstallationsRegistrationHTTPCodeProjectNotFound = 404, + FIRInstallationsRegistrationHTTPCodeTooManyRequests = 429, + FIRInstallationsRegistrationHTTPCodeServerInternalError = 500 +}; + +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenHTTPCode) { + FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication = 401, + FIRInstallationsAuthTokenHTTPCodeFIDNotFound = 404, +}; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m new file mode 100644 index 0000000..4236f45 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.m @@ -0,0 +1,79 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsHTTPError + +- (instancetype)initWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSDictionary *userInfo = [FIRInstallationsHTTPError userInfoWithHTTPResponse:HTTPResponse + data:data]; + self = [super + initWithDomain:kFirebaseInstallationsErrorDomain + code:[FIRInstallationsHTTPError errorCodeWithHTTPCode:HTTPResponse.statusCode] + userInfo:userInfo]; + if (self) { + _HTTPResponse = HTTPResponse; + _data = data; + } + return self; +} + ++ (FIRInstallationsErrorCode)errorCodeWithHTTPCode:(NSInteger)HTTPCode { + return FIRInstallationsErrorCodeUnknown; +} + ++ (NSDictionary *)userInfoWithHTTPResponse:(NSHTTPURLResponse *)HTTPResponse + data:(nullable NSData *)data { + NSString *responseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + NSString *failureReason = + [NSString stringWithFormat:@"The server responded with an error: \n - URL: %@ \n - HTTP " + @"status code: %ld \n - Response body: %@", + HTTPResponse.URL, (long)HTTPResponse.statusCode, responseString]; + return @{NSLocalizedFailureReasonErrorKey : failureReason}; +} + +#pragma mark - NSCopying + +- (id)copyWithZone:(NSZone *)zone { + return [[FIRInstallationsHTTPError alloc] initWithHTTPResponse:self.HTTPResponse data:self.data]; +} + +#pragma mark - NSSecureCoding + +- (nullable instancetype)initWithCoder:(NSCoder *)coder { + NSHTTPURLResponse *HTTPResponse = [coder decodeObjectOfClass:[NSHTTPURLResponse class] + forKey:@"HTTPResponse"]; + if (!HTTPResponse) { + return nil; + } + NSData *data = [coder decodeObjectOfClass:[NSData class] forKey:@"data"]; + + return [self initWithHTTPResponse:HTTPResponse data:data]; +} + +- (void)encodeWithCoder:(NSCoder *)coder { + [coder encodeObject:self.HTTPResponse forKey:@"HTTPResponse"]; + [coder encodeObject:self.data forKey:@"data"]; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m new file mode 100644 index 0000000..4ee099e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallations.m @@ -0,0 +1,284 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NS_ASSUME_NONNULL_BEGIN + +static const NSUInteger kExpectedAPIKeyLength = 39; + +@protocol FIRInstallationsInstanceProvider +@end + +@interface FIRInstallations () +@property(nonatomic, readonly) FIROptions *appOptions; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsIDController *installationsIDController; + +@end + +@implementation FIRInstallations + +#pragma mark - Firebase component + ++ (void)load { + [FIRApp registerInternalLibrary:(Class)self withName:@"fire-install"]; +} + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + *isCacheable = YES; + FIRInstallations *installations = [[FIRInstallations alloc] initWithApp:container.app]; + return installations; + }; + + FIRComponent *installationsProvider = + [FIRComponent componentWithProtocol:@protocol(FIRInstallationsInstanceProvider) + instantiationTiming:FIRInstantiationTimingAlwaysEager + creationBlock:creationBlock]; + return @[ installationsProvider ]; +} + +- (instancetype)initWithApp:(FIRApp *)app { + FIRInstallationsIDController *IDController = + [[FIRInstallationsIDController alloc] initWithApp:app]; + + // `prefetchAuthToken` is disabled due to b/156746574. + return [self initWithAppOptions:app.options + appName:app.name + installationsIDController:IDController + prefetchAuthToken:NO]; +} + +/// This designated initializer can be exposed for testing. +- (instancetype)initWithAppOptions:(FIROptions *)appOptions + appName:(NSString *)appName + installationsIDController:(FIRInstallationsIDController *)installationsIDController + prefetchAuthToken:(BOOL)prefetchAuthToken { + self = [super init]; + if (self) { + [[self class] validateAppOptions:appOptions appName:appName]; + [[self class] assertCompatibleIIDVersion]; + + _appOptions = [appOptions copy]; + _appName = [appName copy]; + _installationsIDController = installationsIDController; + + // Pre-fetch auth token. + if (prefetchAuthToken) { + [self authTokenWithCompletion:^(FIRInstallationsAuthTokenResult *_Nullable tokenResult, + NSError *_Nullable error){ + }]; + } + } + return self; +} + ++ (void)validateAppOptions:(FIROptions *)appOptions appName:(NSString *)appName { + NSMutableArray *missingFields = [NSMutableArray array]; + if (appName.length < 1) { + [missingFields addObject:@"`FirebaseApp.name`"]; + } + if (appOptions.APIKey.length < 1) { + [missingFields addObject:@"`FirebaseOptions.APIKey`"]; + } + if (appOptions.googleAppID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.googleAppID`"]; + } + + if (appOptions.projectID.length < 1) { + [missingFields addObject:@"`FirebaseOptions.projectID`"]; + } + + if (missingFields.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. The following parameters are nil or empty: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [missingFields componentsJoinedByString:@", "]]; + } + + [self validateAPIKey:appOptions.APIKey]; +} + ++ (void)validateAPIKey:(nullable NSString *)APIKey { + NSMutableArray *validationIssues = [[NSMutableArray alloc] init]; + + if (APIKey.length != kExpectedAPIKeyLength) { + [validationIssues addObject:[NSString stringWithFormat:@"API Key length must be %lu characters", + (unsigned long)kExpectedAPIKeyLength]]; + } + + if (![[APIKey substringToIndex:1] isEqualToString:@"A"]) { + [validationIssues addObject:@"API Key must start with `A`"]; + } + + NSMutableCharacterSet *allowedCharacters = [NSMutableCharacterSet alphanumericCharacterSet]; + [allowedCharacters + formUnionWithCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"-_"]]; + + NSCharacterSet *characters = [NSCharacterSet characterSetWithCharactersInString:APIKey]; + if (![allowedCharacters isSupersetOfSet:characters]) { + [validationIssues addObject:@"API Key must contain only base64 url-safe characters characters"]; + } + + if (validationIssues.count > 0) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format: + @"%@[%@] Could not configure Firebase Installations due to invalid FirebaseApp " + @"options. `FirebaseOptions.APIKey` doesn't match the expected format: %@. If you use " + @"GoogleServices-Info.plist please download the most recent version from the Firebase " + @"Console. If you configure Firebase in code, please make sure you specify all " + @"required parameters.", + kFIRLoggerInstallations, kFIRInstallationsMessageCodeInvalidFirebaseAppOptions, + [validationIssues componentsJoinedByString:@", "]]; + } +} + +#pragma mark - Public + ++ (FIRInstallations *)installations { + FIRApp *defaultApp = [FIRApp defaultApp]; + if (!defaultApp) { + [NSException raise:kFirebaseInstallationsErrorDomain + format:@"The default FirebaseApp instance must be configured before the default" + @"FirebaseApp instance can be initialized. One way to ensure this is to " + @"call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` " + @"(or the `@main` struct's initializer in SwiftUI)."]; + } + + return [self installationsWithApp:defaultApp]; +} + ++ (FIRInstallations *)installationsWithApp:(FIRApp *)app { + id installations = + FIR_COMPONENT(FIRInstallationsInstanceProvider, app.container); + return (FIRInstallations *)installations; +} + +- (void)installationIDWithCompletion:(FIRInstallationsIDHandler)completion { + [self.installationsIDController getInstallationItem] + .then(^id(FIRInstallationsItem *installation) { + completion(installation.firebaseInstallationID, nil); + return nil; + }) + .catch(^(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)authTokenWithCompletion:(FIRInstallationsTokenHandler)completion { + [self authTokenForcingRefresh:NO completion:completion]; +} + +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(FIRInstallationsTokenHandler)completion { + [self.installationsIDController getAuthTokenForcingRefresh:forceRefresh] + .then(^FIRInstallationsAuthTokenResult *(FIRInstallationsItem *installation) { + FIRInstallationsAuthTokenResult *result = [[FIRInstallationsAuthTokenResult alloc] + initWithToken:installation.authToken.token + expirationDate:installation.authToken.expirationDate]; + return result; + }) + .then(^id(FIRInstallationsAuthTokenResult *token) { + completion(token, nil); + return nil; + }) + .catch(^void(NSError *error) { + completion(nil, [FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion { + [self.installationsIDController deleteInstallation] + .then(^id(id result) { + completion(nil); + return nil; + }) + .catch(^void(NSError *error) { + completion([FIRInstallationsErrorUtil publicDomainErrorWithError:error]); + }); +} + +#pragma mark - IID version compatibility + ++ (void)assertCompatibleIIDVersion { + // We use this flag to disable IID compatibility exception for unit tests. +#ifdef FIR_INSTALLATIONS_ALLOWS_INCOMPATIBLE_IID_VERSION + return; +#else + if (![self isIIDVersionCompatible]) { + [NSException + raise:kFirebaseInstallationsErrorDomain + format:@"Firebase Instance ID is not compatible with Firebase 8.x+. Please remove the " + @"dependency from the app. See the documentation at " + @"https://firebase.google.com/docs/cloud-messaging/ios/" + @"client#fetching-the-current-registration-token."]; + } +#endif +} + ++ (BOOL)isIIDVersionCompatible { + Class IIDClass = NSClassFromString(@"FIRInstanceID"); + if (IIDClass == nil) { + // It is OK if there is no IID at all. + return YES; + } + // We expect a compatible version having the method `+[FIRInstanceID usesFIS]` defined. + BOOL isCompatibleVersion = [IIDClass respondsToSelector:NSSelectorFromString(@"usesFIS")]; + return isCompatibleVersion; +} + +#pragma mark - Force Category Linking + +extern void FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m new file mode 100644 index 0000000..47a71e8 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResult.m @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h" + +@implementation FIRInstallationsAuthTokenResult + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationDate { + self = [super init]; + if (self) { + _authToken = [token copy]; + _expirationDate = expirationDate; + } + return self; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h new file mode 100644 index 0000000..662802e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsAuthTokenResultInternal.h @@ -0,0 +1,27 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsAuthTokenResult (Internal) + +- (instancetype)initWithToken:(NSString *)token expirationDate:(NSDate *)expirationTime; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h new file mode 100644 index 0000000..8aa3a5e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.h @@ -0,0 +1,93 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredItem; +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class represents the required installation ID and auth token data including possible states. + * The data is stored to Keychain via `FIRInstallationsStoredItem` which has only the storage + * relevant data and does not contain any logic. `FIRInstallationsItem` must be used on the logic + * level (not `FIRInstallationsStoredItem`). + */ +@interface FIRInstallationsItem : NSObject + +/// A `FirebaseApp` identifier. +@property(nonatomic, readonly) NSString *appID; +/// A `FirebaseApp` name. +@property(nonatomic, readonly) NSString *firebaseAppName; +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic, assign) FIRInstallationsStatus registrationStatus; + +/// Instance ID default token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName; + +/** + * Populates `FIRInstallationsItem` properties with data from `FIRInstallationsStoredItem`. + * @param item An instance of `FIRInstallationsStoredItem` to get data from. + */ +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item; + +/** + * Creates a stored item with data from the object. + * @return Returns a `FIRInstallationsStoredItem` instance with the data from the object. + */ +- (FIRInstallationsStoredItem *)storedItem; + +/** + * The installation identifier. + * @return Returns a string uniquely identifying the installation. + */ +- (NSString *)identifier; + +/** Validates if all the required item fields are populated and values don't explicitly conflict + * with each other. + * @param outError A reference to be populated with an error containing validation failure details. + * @return `YES` if the item it valid, `NO` otherwise. + */ +- (BOOL)isValid:(NSError *_Nullable *)outError; + +/** + * The installation identifier. + * @param appID A `FirebaseApp` identifier. + * @param appName A `FirebaseApp` name. + * @return Returns a string uniquely identifying the installation. + */ ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName; + +/** + * Generate a new Firebase Installation Identifier. + * @return Returns a 22 characters long globally unique string created based on UUID. + */ ++ (NSString *)generateFID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m new file mode 100644 index 0000000..0316e45 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsItem.m @@ -0,0 +1,161 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +@implementation FIRInstallationsItem + +- (instancetype)initWithAppID:(NSString *)appID firebaseAppName:(NSString *)firebaseAppName { + self = [super init]; + if (self) { + _appID = [appID copy]; + _firebaseAppName = [firebaseAppName copy]; + } + return self; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsItem *clone = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.firebaseAppName]; + clone.firebaseInstallationID = [self.firebaseInstallationID copy]; + clone.refreshToken = [self.refreshToken copy]; + clone.authToken = [self.authToken copy]; + clone.registrationStatus = self.registrationStatus; + clone.IIDDefaultToken = [self.IIDDefaultToken copy]; + + return clone; +} + +- (void)updateWithStoredItem:(FIRInstallationsStoredItem *)item { + self.firebaseInstallationID = item.firebaseInstallationID; + self.refreshToken = item.refreshToken; + self.authToken = item.authToken; + self.registrationStatus = item.registrationStatus; + self.IIDDefaultToken = item.IIDDefaultToken; +} + +- (FIRInstallationsStoredItem *)storedItem { + FIRInstallationsStoredItem *storedItem = [[FIRInstallationsStoredItem alloc] init]; + storedItem.firebaseInstallationID = self.firebaseInstallationID; + storedItem.refreshToken = self.refreshToken; + storedItem.authToken = self.authToken; + storedItem.registrationStatus = self.registrationStatus; + storedItem.IIDDefaultToken = self.IIDDefaultToken; + return storedItem; +} + +- (nonnull NSString *)identifier { + return [[self class] identifierWithAppID:self.appID appName:self.firebaseAppName]; +} + +- (BOOL)isValid:(NSError *_Nullable *)outError { + NSMutableArray *validationIssues = [NSMutableArray array]; + + if (self.appID.length == 0) { + [validationIssues addObject:@"`appID` must not be empty"]; + } + + if (self.firebaseAppName.length == 0) { + [validationIssues addObject:@"`firebaseAppName` must not be empty"]; + } + + if (self.firebaseInstallationID.length == 0) { + [validationIssues addObject:@"`firebaseInstallationID` must not be empty"]; + } + + switch (self.registrationStatus) { + case FIRInstallationStatusUnknown: + [validationIssues addObject:@"invalid `registrationStatus`"]; + break; + + case FIRInstallationStatusRegistered: + if (self.refreshToken == 0) { + [validationIssues addObject:@"registered installation must have non-empty `refreshToken`"]; + } + + if (self.authToken.token == 0) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.token`"]; + } + + if (self.authToken.expirationDate == nil) { + [validationIssues + addObject:@"registered installation must have non-empty `authToken.expirationDate`"]; + } + + case FIRInstallationStatusUnregistered: + break; + } + + BOOL isValid = validationIssues.count == 0; + + if (!isValid && outError) { + NSString *failureReason = + [NSString stringWithFormat:@"FIRInstallationsItem validation errors: %@", + [validationIssues componentsJoinedByString:@", "]]; + *outError = + [FIRInstallationsErrorUtil installationsErrorWithCode:FIRInstallationsErrorCodeUnknown + failureReason:failureReason + underlyingError:nil]; + } + + return isValid; +} + ++ (NSString *)identifierWithAppID:(NSString *)appID appName:(NSString *)appName { + return [appID stringByAppendingString:appName]; +} + ++ (NSString *)generateFID { + NSUUID *UUID = [NSUUID UUID]; + uuid_t UUIDBytes; + [UUID getUUIDBytes:UUIDBytes]; + + NSUInteger UUIDLength = sizeof(uuid_t); + NSData *UUIDData = [NSData dataWithBytes:UUIDBytes length:UUIDLength]; + + uint8_t UUIDLast4Bits = UUIDBytes[UUIDLength - 1] & 0b00001111; + + // FID first 4 bits must be `0111`. The last 4 UUID bits will be cut later to form a proper FID. + // To keep 16 random bytes we copy these last 4 UUID to the FID 1st byte after `0111` prefix. + uint8_t FIDPrefix = 0b01110000 | UUIDLast4Bits; + NSMutableData *FIDData = [NSMutableData dataWithBytes:&FIDPrefix length:1]; + + [FIDData appendData:UUIDData]; + NSString *FIDString = [self base64URLEncodedStringWithData:FIDData]; + + // A valid FID has exactly 22 base64 characters, which is 132 bits, or 16.5 bytes. + // Our generated ID has 16 bytes UUID + 1 byte prefix which after encoding with base64 will become + // 23 characters plus 1 character for "=" padding. + + // Remove the 23rd character that was added because of the extra 4 bits at the + // end of our 17 byte data and the '=' padding. + return [FIDString substringWithRange:NSMakeRange(0, 22)]; +} + ++ (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + return string; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h new file mode 100644 index 0000000..7ad9967 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.h @@ -0,0 +1,52 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +extern FIRLoggerService kFIRLoggerInstallations; + +// FIRInstallationsAPIService.m +extern NSString *const kFIRInstallationsMessageCodeSendAPIRequest; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError; +extern NSString *const kFIRInstallationsMessageCodeAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse; +extern NSString *const kFIRInstallationsMessageCodeParsingAPIResponse; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed; +extern NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed; + +// FIRInstallationsIDController.m +extern NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated; +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration; +extern NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation; + +// FIRInstallationsStoredItem.m +extern NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch; + +// FIRInstallationsStoredAuthToken.m +extern NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch; + +// FIRInstallationsStoredIIDCheckin.m +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch; +extern NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode; + +// FIRInstallations.m +extern NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m new file mode 100644 index 0000000..5187f97 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/FIRInstallationsLogger.m @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +FIRLoggerService kFIRLoggerInstallations = @"[FirebaseInstallations]"; + +// FIRInstallationsAPIService.m +NSString *const kFIRInstallationsMessageCodeSendAPIRequest = @"I-FIS001001"; +NSString *const kFIRInstallationsMessageCodeAPIRequestNetworkError = @"I-FIS001002"; +NSString *const kFIRInstallationsMessageCodeAPIRequestResponse = @"I-FIS001003"; +NSString *const kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse = @"I-FIS001004"; +NSString *const kFIRInstallationsMessageCodeParsingAPIResponse = @"I-FIS001005"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed = @"I-FIS001006"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed = @"I-FIS001007"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed = @"I-FIS001008"; +NSString *const kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed = @"I-FIS001009"; + +// FIRInstallationsIDController.m +NSString *const kFIRInstallationsMessageCodeNewGetInstallationOperationCreated = @"I-FIS002000"; +NSString *const kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated = @"I-FIS002001"; +NSString *const kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated = @"I-FIS002002"; +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseConfiguration = @"I-FIS002003"; +NSString *const kFIRInstallationsMessageCodeCorruptedStoredInstallation = @"I-FIS002004"; + +// FIRInstallationsStoredItem.m +NSString *const kFIRInstallationsMessageCodeInstallationCoderVersionMismatch = @"I-FIS003000"; + +// FIRInstallationsStoredAuthToken.m +NSString *const kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch = @"I-FIS004000"; + +// FIRInstallationsStoredIIDCheckin.m +NSString *const kFIRInstallationsMessageCodeIIDCheckinCoderVersionMismatch = @"I-FIS007000"; +NSString *const kFIRInstallationsMessageCodeIIDCheckinFailedToDecode = @"I-FIS007001"; + +// FIRInstallations.m +NSString *const kFIRInstallationsMessageCodeInvalidFirebaseAppOptions = @"I-FIS008000"; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h new file mode 100644 index 0000000..e2408ca --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** The class encapsulates a port of a piece FirebaseInstanceID logic required to migrate IID. */ +@interface FIRInstallationsIIDStore : NSObject + +/** + * Retrieves existing IID if present. + * @return Returns a promise that is resolved with IID string if IID has been found or rejected with + * an error otherwise. + */ +- (FBLPromise *)existingIID; + +/** + * Deletes existing IID if present. + * @return Returns a promise that is resolved with `[NSNull null]` if the IID was successfully. + * deleted or was not found. The promise is rejected otherwise. + */ +- (FBLPromise *)deleteExistingIID; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m new file mode 100644 index 0000000..1c2f5d3 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.m @@ -0,0 +1,242 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDKeyPairPublicTagPrefix = + @"com.google.iid.keypair.public-"; +static NSString *const kFIRInstallationsIIDKeyPairPrivateTagPrefix = + @"com.google.iid.keypair.private-"; +static NSString *const kFIRInstallationsIIDCreationTimePlistKey = @"|S|cre"; + +@implementation FIRInstallationsIIDStore + +- (FBLPromise *)existingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + if (![self hasPlistIIDFlag]) { + return nil; + } + + NSData *IIDPublicKeyData = [self IIDPublicKeyData]; + return [self IIDWithPublicKeyData:IIDPublicKeyData]; + }] + .validate(^BOOL(NSString *_Nullable IID) { + return IID.length > 0; + }); +} + +- (FBLPromise *)deleteExistingIID { + return [FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + NSError *error; + if (![self deleteIIDFlagFromPlist:&error]) { + return error; + } + + if (![self deleteIID:&error]) { + return error; + } + + return [NSNull null]; + }]; +} + +#pragma mark - IID decoding + +- (NSString *)IIDWithPublicKeyData:(NSData *)publicKeyData { + NSData *publicKeySHA1 = [self sha1WithData:publicKeyData]; + + const uint8_t *bytes = publicKeySHA1.bytes; + NSMutableData *identityData = [NSMutableData dataWithData:publicKeySHA1]; + + uint8_t b0 = bytes[0]; + // Take the first byte and make the initial four 7 by initially making the initial 4 bits 0 + // and then adding 0x70 to it. + b0 = 0x70 + (0xF & b0); + // failsafe should give you back b0 itself + b0 = (b0 & 0xFF); + [identityData replaceBytesInRange:NSMakeRange(0, 1) withBytes:&b0]; + NSData *data = [identityData subdataWithRange:NSMakeRange(0, 8 * sizeof(Byte))]; + return [self base64URLEncodedStringWithData:data]; +} + +/** FirebaseInstallations SDK uses the SHA1 hash for backwards compatibility with the legacy + * FirebaseInstanceID SDK. The SHA1 hash is used to access Instance IDs stored on the device and not + * for any security-relevant process. This is a one-time step that allows migration of old client + * identifiers. Cryptographic security is not needed here, so potential hash collisions are not a + * problem. + */ +- (NSData *)sha1WithData:(NSData *)data { + unsigned char output[CC_SHA1_DIGEST_LENGTH]; + unsigned int length = (unsigned int)[data length]; + + CC_SHA1(data.bytes, length, output); + return [NSData dataWithBytes:output length:CC_SHA1_DIGEST_LENGTH]; +} + +- (NSString *)base64URLEncodedStringWithData:(NSData *)data { + NSString *string = [data base64EncodedStringWithOptions:0]; + string = [string stringByReplacingOccurrencesOfString:@"/" withString:@"_"]; + string = [string stringByReplacingOccurrencesOfString:@"+" withString:@"-"]; + string = [string stringByReplacingOccurrencesOfString:@"=" withString:@""]; + return string; +} + +#pragma mark - Keychain + +- (NSData *)IIDPublicKeyData { + NSString *tag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *query = [self keyPairQueryWithTag:tag returnData:YES]; + + CFTypeRef keyRef = NULL; + OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&keyRef); + + if (status != noErr) { + if (keyRef) { + CFRelease(keyRef); + } + return nil; + } + + return (__bridge NSData *)keyRef; +} + +- (BOOL)deleteIID:(NSError **)outError { + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix + error:outError]) { + return NO; + } + + if (![self deleteKeychainKeyWithTagPrefix:kFIRInstallationsIIDKeyPairPrivateTagPrefix + error:outError]) { + return NO; + } + + return YES; +} + +- (BOOL)deleteKeychainKeyWithTagPrefix:(NSString *)tagPrefix error:(NSError **)outError { + NSString *keyTag = [self keychainKeyTagWithPrefix:kFIRInstallationsIIDKeyPairPublicTagPrefix]; + NSDictionary *keyQuery = [self keyPairQueryWithTag:keyTag returnData:NO]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)keyQuery); + + // When item is not found, it should NOT be considered as an error. The operation should + // continue. + if (status != noErr && status != errSecItemNotFound) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil keychainErrorWithFunction:@"SecItemDelete" status:status], + outError); + return NO; + } + + return YES; +} + +- (NSDictionary *)keyPairQueryWithTag:(NSString *)tag returnData:(BOOL)shouldReturnData { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding]; + + query[(__bridge id)kSecClass] = (__bridge id)kSecClassKey; + query[(__bridge id)kSecAttrApplicationTag] = tagData; + query[(__bridge id)kSecAttrKeyType] = (__bridge id)kSecAttrKeyTypeRSA; + if (shouldReturnData) { + query[(__bridge id)kSecReturnData] = @(YES); + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OSX + + return query; +} + +- (NSString *)keychainKeyTagWithPrefix:(NSString *)prefix { + NSString *mainAppBundleID = [[NSBundle mainBundle] bundleIdentifier]; + if (mainAppBundleID.length == 0) { + return nil; + } + return [NSString stringWithFormat:@"%@%@", prefix, mainAppBundleID]; +} + +- (NSString *)mainbundleIdentifier { + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + if (!bundleIdentifier.length) { + return nil; + } + return bundleIdentifier; +} + +#pragma mark - Plist + +- (BOOL)deleteIIDFlagFromPlist:(NSError **)outError { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return YES; + } + + NSMutableDictionary *plistContent = [[NSMutableDictionary alloc] initWithContentsOfFile:path]; + plistContent[kFIRInstallationsIIDCreationTimePlistKey] = nil; + + if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) { + return [plistContent writeToURL:[NSURL fileURLWithPath:path] error:outError]; + } + + return [plistContent writeToFile:path atomically:YES]; +} + +- (BOOL)hasPlistIIDFlag { + NSString *path = [self plistPath]; + if (![[NSFileManager defaultManager] fileExistsAtPath:path]) { + return NO; + } + + NSDictionary *plistContent = [[NSDictionary alloc] initWithContentsOfFile:path]; + return plistContent[kFIRInstallationsIIDCreationTimePlistKey] != nil; +} + +- (NSString *)plistPath { + NSString *plistNameWithExtension = @"com.google.iid-keypair.plist"; + NSString *_subDirectoryName = @"Google/FirebaseInstanceID"; + + NSArray *directoryPaths = + NSSearchPathForDirectoriesInDomains([self supportedDirectory], NSUserDomainMask, YES); + NSArray *components = @[ directoryPaths.lastObject, _subDirectoryName, plistNameWithExtension ]; + + return [NSString pathWithComponents:components]; +} + +- (NSSearchPathDirectory)supportedDirectory { +#if TARGET_OS_TV + return NSCachesDirectory; +#else + return NSApplicationSupportDirectory; +#endif +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h new file mode 100644 index 0000000..ed98e3d --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class reads a default IID token from IID store if available. + */ +@interface FIRInstallationsIIDTokenStore : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID; + +- (FBLPromise *)existingIIDDefaultToken; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m new file mode 100644 index 0000000..5ef3331 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.m @@ -0,0 +1,158 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" + +static NSString *const kFIRInstallationsIIDTokenKeychainId = @"com.google.iid-tokens"; + +@interface FIRInstallationsIIDTokenInfo : NSObject +@property(nonatomic, nullable, copy) NSString *token; +@end + +@implementation FIRInstallationsIIDTokenInfo + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + self = [super init]; + if (self) { + _token = [coder decodeObjectOfClass:[NSString class] forKey:@"token"]; + } + return self; +} + +@end + +@interface FIRInstallationsIIDTokenStore () +@property(nonatomic, readonly) NSString *GCMSenderID; +@end + +@implementation FIRInstallationsIIDTokenStore + +- (instancetype)initWithGCMSenderID:(NSString *)GCMSenderID { + self = [super init]; + if (self) { + _GCMSenderID = GCMSenderID; + } + return self; +} + +- (FBLPromise *)existingIIDDefaultToken { + return [[FBLPromise onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + return [self IIDDefaultTokenData]; + }] onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + then:^id _Nullable(NSData *_Nullable keychainData) { + return [self IIDCheckinWithData:keychainData]; + }]; +} + +- (FBLPromise *)IIDCheckinWithData:(NSData *)data { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSError *archiverError; + NSKeyedUnarchiver *unarchiver; + if (@available(iOS 11.0, tvOS 11.0, macOS 10.13, *)) { + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingFromData:data error:&archiverError]; + } else { + @try { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; +#pragma clang diagnostic pop + } @catch (NSException *exception) { + archiverError = [FIRInstallationsErrorUtil keyedArchiverErrorWithException:exception]; + } + } + + if (!unarchiver) { + NSError *error = archiverError ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:error]; + return resultPromise; + } + + [unarchiver setClass:[FIRInstallationsIIDTokenInfo class] forClassName:@"FIRInstanceIDTokenInfo"]; + FIRInstallationsIIDTokenInfo *IIDTokenInfo = + [unarchiver decodeObjectOfClass:[FIRInstallationsIIDTokenInfo class] + forKey:NSKeyedArchiveRootObjectKey]; + + if (IIDTokenInfo.token.length < 1) { + [resultPromise reject:[FIRInstallationsErrorUtil corruptedIIDTokenData]]; + return resultPromise; + } + + [resultPromise fulfill:IIDTokenInfo.token]; + + return resultPromise; +} + +- (FBLPromise *)IIDDefaultTokenData { + FBLPromise *resultPromise = [FBLPromise pendingPromise]; + + NSMutableDictionary *keychainQuery = [self IIDDefaultTokenDataKeychainQuery]; + NSError *error; + NSData *data = [GULKeychainUtils getItemWithQuery:keychainQuery error:&error]; + + if (data) { + [resultPromise fulfill:data]; + return resultPromise; + } else { + NSError *outError = error ?: [FIRInstallationsErrorUtil corruptedIIDTokenData]; + [resultPromise reject:outError]; + return resultPromise; + } +} + +- (NSMutableDictionary *)IIDDefaultTokenDataKeychainQuery { + NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword}; + + NSMutableDictionary *finalQuery = [NSMutableDictionary dictionaryWithDictionary:query]; + finalQuery[(__bridge NSString *)kSecAttrGeneric] = kFIRInstallationsIIDTokenKeychainId; + + NSString *account = [self IIDAppIdentifier]; + if ([account length]) { + finalQuery[(__bridge NSString *)kSecAttrAccount] = account; + } + + finalQuery[(__bridge NSString *)kSecAttrService] = + [self serviceKeyForAuthorizedEntity:self.GCMSenderID scope:@"*"]; + return finalQuery; +} + +- (NSString *)IIDAppIdentifier { + return [[NSBundle mainBundle] bundleIdentifier] ?: @""; +} + +- (NSString *)serviceKeyForAuthorizedEntity:(NSString *)authorizedEntity scope:(NSString *)scope { + return [NSString stringWithFormat:@"%@:%@", authorizedEntity, scope]; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h new file mode 100644 index 0000000..1601bdc --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h @@ -0,0 +1,65 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; +@class FIRInstallationsItem; + +@protocol FIRHeartbeatLoggerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kFIRInstallationsHeartbeatKey; + +/** + * The class is responsible for interacting with HTTP REST API for Installations. + */ +@interface FIRInstallationsAPIService : NSObject + +/** + * The default initializer. + * @param APIKey The Firebase project API key (see `FIROptions.APIKey`). + * @param projectID The Firebase project ID (see `FIROptions.projectID`). + * @param heartbeatLogger The heartbeat logger used to populate heartbeat data in request headers. + */ +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger; + +/** + * Sends a request to register a new FID to get auth and refresh tokens. + * @param installation The `FIRInstallationsItem` instance with the FID to register. + * @return A promise that is resolved with a new `FIRInstallationsItem` instance with valid tokens. + * It is rejected with an error in case of a failure. + */ +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation; + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation; + +/** + * Sends a request to delete the installation, related auth tokens and all related data from the + * server. + * @param installation The installation to delete. + * @return Returns a promise that is resolved with the passed installation on successful deletion or + * is rejected with an error otherwise. + */ +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m new file mode 100644 index 0000000..99dd215 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.m @@ -0,0 +1,382 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +NSString *const kFIRInstallationsAPIBaseURL = @"https://firebaseinstallations.googleapis.com"; +NSString *const kFIRInstallationsAPIKey = @"X-Goog-Api-Key"; +NSString *const kFIRInstallationsBundleId = @"X-Ios-Bundle-Identifier"; +NSString *const kFIRInstallationsIIDMigrationAuthHeader = @"x-goog-fis-ios-iid-migration-auth"; +NSString *const kFIRInstallationsHeartbeatKey = @"X-firebase-client"; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsURLSessionResponse : NSObject +@property(nonatomic) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic) NSData *data; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data; +@end + +@implementation FIRInstallationsURLSessionResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response data:(nullable NSData *)data { + self = [super init]; + if (self) { + _HTTPResponse = response; + _data = data ?: [NSData data]; + } + return self; +} + +@end + +@interface FIRInstallationsAPIService () +@property(nonatomic, readonly) NSURLSession *URLSession; +@property(nonatomic, readonly) NSString *APIKey; +@property(nonatomic, readonly) NSString *projectID; +@property(readonly) id heartbeatLogger; +@end + +NS_ASSUME_NONNULL_END + +@implementation FIRInstallationsAPIService + +- (instancetype)initWithAPIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + NSURLSession *URLSession = [NSURLSession + sessionWithConfiguration:[NSURLSessionConfiguration ephemeralSessionConfiguration]]; + return [self initWithURLSession:URLSession + APIKey:APIKey + projectID:projectID + heartbeatLogger:heartbeatLogger]; +} + +/// The initializer for tests. +- (instancetype)initWithURLSession:(NSURLSession *)URLSession + APIKey:(NSString *)APIKey + projectID:(NSString *)projectID + heartbeatLogger:(id)heartbeatLogger { + self = [super init]; + if (self) { + _URLSession = URLSession; + _APIKey = [APIKey copy]; + _projectID = [projectID copy]; + _heartbeatLogger = heartbeatLogger; + } + return self; +} + +#pragma mark - Public + +- (FBLPromise *)registerInstallation:(FIRInstallationsItem *)installation { + return [self validateInstallation:installation] + .then(^id _Nullable(FIRInstallationsItem *_Nullable validInstallation) { + return [self registerRequestWithInstallation:validInstallation]; + }) + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self registeredInstallationWithInstallation:installation serverResponse:response]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + return [self authTokenRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^FBLPromise *( + FIRInstallationsURLSessionResponse *response) { + return [self authTokenWithServerResponse:response]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsStoredAuthToken *authToken) { + FIRInstallationsItem *updatedInstallation = [installation copy]; + updatedInstallation.authToken = authToken; + return updatedInstallation; + }); +} + +- (FBLPromise *)deleteInstallation:(FIRInstallationsItem *)installation { + return [self deleteInstallationRequestWithInstallation:installation] + .then(^id _Nullable(NSURLRequest *_Nullable request) { + return [self sendURLRequest:request]; + }) + .then(^id _Nullable(FIRInstallationsURLSessionResponse *_Nullable value) { + // Return the original installation on success. + return installation; + }); +} + +#pragma mark - Register Installation + +- (FBLPromise *)registerRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/", + kFIRInstallationsAPIBaseURL, self.projectID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{ + // `firebaseInstallationID` is validated before but let's make sure it is not `nil` one more + // time to prevent a crash. + @"fid" : installation.firebaseInstallationID ?: @"", + @"authVersion" : @"FIS_v2", + @"appId" : installation.appID, + @"sdkVersion" : [self SDKVersion] + }; + + NSDictionary *headers; + if (installation.IIDDefaultToken) { + headers = @{kFIRInstallationsIIDMigrationAuthHeader : installation.IIDDefaultToken}; + } + + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:nil + additionalHeaders:headers]; +} + +- (FBLPromise *) + registeredInstallationWithInstallation:(FIRInstallationsItem *)installation + serverResponse:(FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsItem *registeredInstallation = + [installation registeredInstallationWithJSONData:response.data + date:[NSDate date] + error:&error]; + if (registeredInstallation == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationFailed, + @"Failed to parse FIRInstallationsItem: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingInstallationSucceed, + @"FIRInstallationsItem parsed successfully."); + return registeredInstallation; + }]; +} + +#pragma mark - Auth token + +- (FBLPromise *)authTokenRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = + [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/authTokens:generate", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + NSDictionary *bodyDict = @{@"installation" : @{@"sdkVersion" : [self SDKVersion]}}; + return [self requestWithURL:URL + HTTPMethod:@"POST" + bodyDict:bodyDict + refreshToken:installation.refreshToken]; +} + +- (FBLPromise *)authTokenWithServerResponse: + (FIRInstallationsURLSessionResponse *)response { + return [FBLPromise do:^id { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeParsingAPIResponse, + @"Parsing server response for %@.", response.HTTPResponse.URL); + NSError *error; + FIRInstallationsStoredAuthToken *token = + [FIRInstallationsItem authTokenWithGenerateTokenAPIJSONData:response.data + date:[NSDate date] + error:&error]; + if (token == nil) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenFailed, + @"Failed to parse FIRInstallationsStoredAuthToken: %@.", error); + return error; + } + + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIResponseParsingAuthTokenSucceed, + @"FIRInstallationsStoredAuthToken parsed successfully."); + return token; + }]; +} + +#pragma mark - Delete Installation + +- (FBLPromise *)deleteInstallationRequestWithInstallation: + (FIRInstallationsItem *)installation { + NSString *URLString = [NSString stringWithFormat:@"%@/v1/projects/%@/installations/%@/", + kFIRInstallationsAPIBaseURL, self.projectID, + installation.firebaseInstallationID]; + NSURL *URL = [NSURL URLWithString:URLString]; + + return [self requestWithURL:URL + HTTPMethod:@"DELETE" + bodyDict:@{} + refreshToken:installation.refreshToken]; +} + +#pragma mark - URL Request +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken { + return [self requestWithURL:requestURL + HTTPMethod:HTTPMethod + bodyDict:bodyDict + refreshToken:refreshToken + additionalHeaders:nil]; +} + +- (FBLPromise *)requestWithURL:(NSURL *)requestURL + HTTPMethod:(NSString *)HTTPMethod + bodyDict:(NSDictionary *)bodyDict + refreshToken:(nullable NSString *)refreshToken + additionalHeaders:(nullable NSDictionary *) + additionalHeaders { + return [FBLPromise + onQueue:dispatch_get_global_queue(QOS_CLASS_UTILITY, 0) + do:^id _Nullable { + __block NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:requestURL]; + request.HTTPMethod = HTTPMethod; + NSString *bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + [request addValue:self.APIKey forHTTPHeaderField:kFIRInstallationsAPIKey]; + [request addValue:bundleIdentifier forHTTPHeaderField:kFIRInstallationsBundleId]; + [self setJSONHTTPBody:bodyDict forRequest:request]; + if (refreshToken) { + NSString *authHeader = [NSString stringWithFormat:@"FIS_v2 %@", refreshToken]; + [request setValue:authHeader forHTTPHeaderField:@"Authorization"]; + } + // Heartbeat Header. + [request setValue:[self.heartbeatLogger headerValue] + forHTTPHeaderField:kFIRInstallationsHeartbeatKey]; + + [additionalHeaders + enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull obj, + BOOL *_Nonnull stop) { + [request setValue:obj forHTTPHeaderField:key]; + }]; + + return [request copy]; + }]; +} + +- (FBLPromise *)URLRequestPromise:(NSURLRequest *)request { + return [[FBLPromise async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeSendAPIRequest, + @"Sending request: %@, body:%@, headers: %@.", request, + [[NSString alloc] initWithData:request.HTTPBody encoding:NSUTF8StringEncoding], + request.allHTTPHeaderFields); + [[self.URLSession + dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAPIRequestNetworkError, + @"Request failed: %@, error: %@.", request, error); + reject(error); + } else { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeAPIRequestResponse, + @"Request response received: %@, error: %@, body: %@.", request, error, + [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + fulfill([[FIRInstallationsURLSessionResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + data:data]); + } + }] resume]; + }] then:^id _Nullable(FIRInstallationsURLSessionResponse *response) { + return [self validateHTTPResponseStatusCode:response]; + }]; +} + +- (FBLPromise *)validateHTTPResponseStatusCode: + (FIRInstallationsURLSessionResponse *)response { + NSInteger statusCode = response.HTTPResponse.statusCode; + return [FBLPromise do:^id _Nullable { + if (statusCode < 200 || statusCode >= 300) { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeUnexpectedAPIRequestResponse, + @"Unexpected API response: %@, body: %@.", response.HTTPResponse, + [[NSString alloc] initWithData:response.data encoding:NSUTF8StringEncoding]); + return [FIRInstallationsErrorUtil APIErrorWithHTTPResponse:response.HTTPResponse + data:response.data]; + } + return response; + }]; +} + +- (FBLPromise *)sendURLRequest:(NSURLRequest *)request { + return [FBLPromise attempts:1 + delay:1 + condition:^BOOL(NSInteger remainingAttempts, NSError *_Nonnull error) { + return [FIRInstallationsErrorUtil isAPIError:error + withHTTPCode:FIRInstallationsHTTPCodesServerInternalError]; + } + retry:^id _Nullable { + return [self URLRequestPromise:request]; + }]; +} + +- (NSString *)SDKVersion { + return [NSString stringWithFormat:@"i:%@", FIRFirebaseVersion()]; +} + +#pragma mark - Validation + +- (FBLPromise *)validateInstallation:(FIRInstallationsItem *)installation { + FBLPromise *result = [FBLPromise pendingPromise]; + + NSError *validationError; + if ([installation isValid:&validationError]) { + [result fulfill:installation]; + } else { + [result reject:validationError]; + } + return result; +} + +#pragma mark - JSON + +- (void)setJSONHTTPBody:(NSDictionary *)body + forRequest:(NSMutableURLRequest *)request { + [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; + + NSError *error; + NSData *JSONData = [NSJSONSerialization dataWithJSONObject:body options:0 error:&error]; + if (JSONData == nil) { + // TODO: Log or return an error. + } + request.HTTPBody = JSONData; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h new file mode 100644 index 0000000..ec0217f --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" + +@class FIRInstallationsStoredAuthToken; + +NS_ASSUME_NONNULL_BEGIN + +@interface FIRInstallationsItem (RegisterInstallationAPI) + +/** + * Parses and validates the Register Installation API response and returns a corresponding + * `FIRInstallationsItem` instance on success. + * @param JSONData The data with JSON encoded API response. + * @param date The installation auth token expiration date will be calculated as `date` + + * `response.authToken.expiresIn`. For most of the cases `[NSDate date]` should be passed there. A + * different value may be passed e.g. for unit tests. + * @param outError A pointer to assign a specific `NSError` instance in case of failure. No error is + * assigned in case of success. + * @return Returns a new `FIRInstallationsItem` instance in the success case or `nil` otherwise. + */ +- (nullable FIRInstallationsItem *)registeredInstallationWithJSONData:(NSData *)JSONData + date:(NSDate *)date + error: + (NSError *_Nullable *)outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError; + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m new file mode 100644 index 0000000..90696f0 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.m @@ -0,0 +1,146 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsItem+RegisterInstallationAPI.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +@implementation FIRInstallationsItem (RegisterInstallationAPI) + +- (nullable FIRInstallationsItem *) + registeredInstallationWithJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError *__autoreleasing _Nullable *_Nullable)outError { + NSDictionary *responseJSON = [FIRInstallationsItem dictionaryFromJSONData:data error:outError]; + if (!responseJSON) { + return nil; + } + + NSString *refreshToken = [FIRInstallationsItem validStringOrNilForKey:@"refreshToken" + fromDict:responseJSON]; + if (refreshToken == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"refreshToken"], + outError); + return nil; + } + + NSDictionary *authTokenDict = responseJSON[@"authToken"]; + if (![authTokenDict isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken"], + outError); + return nil; + } + + FIRInstallationsStoredAuthToken *authToken = + [FIRInstallationsItem authTokenWithJSONDict:authTokenDict date:date error:outError]; + if (authToken == nil) { + return nil; + } + + FIRInstallationsItem *installation = + [[FIRInstallationsItem alloc] initWithAppID:self.appID firebaseAppName:self.firebaseAppName]; + NSString *installationID = [FIRInstallationsItem validStringOrNilForKey:@"fid" + fromDict:responseJSON]; + installation.firebaseInstallationID = installationID ?: self.firebaseInstallationID; + installation.refreshToken = refreshToken; + installation.authToken = authToken; + installation.registrationStatus = FIRInstallationStatusRegistered; + + return installation; +} + +#pragma mark - Auth token + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithGenerateTokenAPIJSONData:(NSData *)data + date:(NSDate *)date + error:(NSError **) + outError { + NSDictionary *dict = [self dictionaryFromJSONData:data error:outError]; + if (!dict) { + return nil; + } + + return [self authTokenWithJSONDict:dict date:date error:outError]; +} + ++ (nullable FIRInstallationsStoredAuthToken *)authTokenWithJSONDict: + (NSDictionary *)dict + date:(NSDate *)date + error:(NSError **)outError { + NSString *token = [self validStringOrNilForKey:@"token" fromDict:dict]; + if (token == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil FIDRegistrationErrorWithResponseMissingField:@"authToken.token"], + outError); + return nil; + } + + NSString *expiresInString = [self validStringOrNilForKey:@"expiresIn" fromDict:dict]; + if (expiresInString == nil) { + FIRInstallationsItemSetErrorToPointer( + [FIRInstallationsErrorUtil + FIDRegistrationErrorWithResponseMissingField:@"authToken.expiresIn"], + outError); + return nil; + } + + // The response should contain the string in format like "604800s". + // The server should never response with anything else except seconds. + // Just drop the last character and parse a number from string. + NSString *expiresInSeconds = [expiresInString substringToIndex:expiresInString.length - 1]; + NSTimeInterval expiresIn = [expiresInSeconds doubleValue]; + NSDate *expirationDate = [date dateByAddingTimeInterval:expiresIn]; + + FIRInstallationsStoredAuthToken *authToken = [[FIRInstallationsStoredAuthToken alloc] init]; + authToken.status = FIRInstallationsAuthTokenStatusTokenReceived; + authToken.token = token; + authToken.expirationDate = expirationDate; + + return authToken; +} + +#pragma mark - JSON + ++ (nullable NSDictionary *)dictionaryFromJSONData:(NSData *)data + error:(NSError **)outError { + NSError *error; + NSDictionary *responseJSON = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; + + if (![responseJSON isKindOfClass:[NSDictionary class]]) { + FIRInstallationsItemSetErrorToPointer([FIRInstallationsErrorUtil JSONSerializationError:error], + outError); + return nil; + } + + return responseJSON; +} + ++ (NSString *)validStringOrNilForKey:(NSString *)key fromDict:(NSDictionary *)dict { + NSString *string = dict[key]; + if ([string isKindOfClass:[NSString class]] && string.length > 0) { + return string; + } + return nil; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void FIRInclude_FIRInstallationsItem_RegisterInstallationAPI_Category(void) { +} diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h new file mode 100644 index 0000000..4d40338 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** A block returning current date. */ +typedef NSDate *_Nonnull (^FIRCurrentDateProvider)(void); + +/** The function returns a `FIRCurrentDateProvider` block that returns a real current date. */ +FIRCurrentDateProvider FIRRealCurrentDateProvider(void); + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m new file mode 100644 index 0000000..d2a1d40 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.m @@ -0,0 +1,23 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +FIRCurrentDateProvider FIRRealCurrentDateProvider(void) { + return ^NSDate *(void) { + return [NSDate date]; + }; +} diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h new file mode 100644 index 0000000..5760618 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h @@ -0,0 +1,54 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRCurrentDateProvider.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRInstallationsBackoffEvent) { + FIRInstallationsBackoffEventSuccess, + FIRInstallationsBackoffEventRecoverableFailure, + FIRInstallationsBackoffEventUnrecoverableFailure +}; + +/** The protocol defines API for a class that encapsulates backoff logic that prevents the SDK from + * sending unnecessary server requests. See API docs for the methods for more details. */ + +@protocol FIRInstallationsBackoffControllerProtocol + +/** The client must call the method each time a protected server request succeeds of fails. It will + * affect the `isNextRequestAllowed` method result for the current time, e.g. when 3 recoverable + * errors were logged in a row, then `isNextRequestAllowed` will return `YES` only in `pow(2, 3)` + * seconds. */ +- (void)registerEvent:(FIRInstallationsBackoffEvent)event; + +/** Returns if sending a next protected is recommended based on the time and the sequence of logged + * events and the current time. See also `registerEvent:`. */ +- (BOOL)isNextRequestAllowed; + +@end + +/** An implementation of `FIRInstallationsBackoffControllerProtocol` with exponential backoff for + * recoverable errors and constant backoff for recoverable errors. */ +@interface FIRInstallationsBackoffController : NSObject + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m new file mode 100644 index 0000000..25f9b42 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.m @@ -0,0 +1,132 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" + +static const NSTimeInterval k24Hours = 24 * 60 * 60; +static const NSTimeInterval k30Minutes = 30 * 60; + +/** The class represents `FIRInstallationsBackoffController` state required to calculate next + allowed request time. The properties of the class are intentionally immutable because changing them + separately leads to an inconsistent state. */ +@interface FIRInstallationsBackoffEventData : NSObject + +@property(nonatomic, readonly) FIRInstallationsBackoffEvent eventType; +@property(nonatomic, readonly) NSDate *lastEventDate; +@property(nonatomic, readonly) NSInteger eventCount; + +@property(nonatomic, readonly) NSTimeInterval backoffTimeInterval; + +@end + +@implementation FIRInstallationsBackoffEventData + +- (instancetype)initWithEvent:(FIRInstallationsBackoffEvent)eventType + lastEventDate:(NSDate *)lastEventDate + eventCount:(NSInteger)eventCount { + self = [super init]; + if (self) { + _eventType = eventType; + _lastEventDate = lastEventDate; + _eventCount = eventCount; + + _backoffTimeInterval = [[self class] backoffTimeIntervalWithEvent:eventType + eventCount:eventCount]; + } + return self; +} + ++ (NSTimeInterval)backoffTimeIntervalWithEvent:(FIRInstallationsBackoffEvent)eventType + eventCount:(NSInteger)eventCount { + switch (eventType) { + case FIRInstallationsBackoffEventSuccess: + return 0; + break; + + case FIRInstallationsBackoffEventRecoverableFailure: + return [self recoverableErrorBackoffTimeForAttemptNumber:eventCount]; + break; + + case FIRInstallationsBackoffEventUnrecoverableFailure: + return k24Hours; + break; + } +} + ++ (NSTimeInterval)recoverableErrorBackoffTimeForAttemptNumber:(NSInteger)attemptNumber { + NSTimeInterval exponentialInterval = pow(2, attemptNumber) + [self randomMilliseconds]; + return MIN(exponentialInterval, k30Minutes); +} + ++ (NSTimeInterval)randomMilliseconds { + int32_t random_millis = ABS(arc4random() % 1000); + return (double)random_millis * 0.001; +} + +@end + +@interface FIRInstallationsBackoffController () + +@property(nonatomic, readonly) FIRCurrentDateProvider currentDateProvider; + +@property(nonatomic, nullable) FIRInstallationsBackoffEventData *lastEventData; + +@end + +@implementation FIRInstallationsBackoffController + +- (instancetype)init { + return [self initWithCurrentDateProvider:FIRRealCurrentDateProvider()]; +} + +- (instancetype)initWithCurrentDateProvider:(FIRCurrentDateProvider)currentDateProvider { + self = [super init]; + if (self) { + _currentDateProvider = [currentDateProvider copy]; + } + return self; +} + +- (BOOL)isNextRequestAllowed { + @synchronized(self) { + if (self.lastEventData == nil) { + return YES; + } + + NSTimeInterval timeSinceLastEvent = + [self.currentDateProvider() timeIntervalSinceDate:self.lastEventData.lastEventDate]; + return timeSinceLastEvent >= self.lastEventData.backoffTimeInterval; + } +} + +- (void)registerEvent:(FIRInstallationsBackoffEvent)event { + @synchronized(self) { + // Event of the same type as was registered before. + if (self.lastEventData && self.lastEventData.eventType == event) { + self.lastEventData = [[FIRInstallationsBackoffEventData alloc] + initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:self.lastEventData.eventCount + 1]; + } else { // A different event. + self.lastEventData = + [[FIRInstallationsBackoffEventData alloc] initWithEvent:event + lastEventDate:self.currentDateProvider() + eventCount:1]; + } + } +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h new file mode 100644 index 0000000..8e66af9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h @@ -0,0 +1,40 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FBLPromise; +@class FIRApp; +@class FIRInstallationsItem; + +/** + * The class is responsible for managing FID for a given `FIRApp`. + */ +@interface FIRInstallationsIDController : NSObject + +- (instancetype)initWithApp:(FIRApp *)app; + +- (FBLPromise *)getInstallationItem; + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh; + +- (FBLPromise *)deleteInstallation; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m new file mode 100644 index 0000000..6ade8cc --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.m @@ -0,0 +1,530 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsIDController.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDStore.h" +#import "FirebaseInstallations/Source/Library/IIDMigration/FIRInstallationsIIDTokenStore.h" +#import "FirebaseInstallations/Source/Library/InstallationsAPI/FIRInstallationsAPIService.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsBackoffController.h" +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsHTTPError.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +const NSNotificationName FIRInstallationIDDidChangeNotification = + @"FIRInstallationIDDidChangeNotification"; +NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey = + @"FIRInstallationIDDidChangeNotification"; + +NSTimeInterval const kFIRInstallationsTokenExpirationThreshold = 60 * 60; // 1 hour. + +static NSString *const kKeychainService = @"com.firebase.FIRInstallations.installations"; + +@interface FIRInstallationsIDController () +@property(nonatomic, readonly) NSString *appID; +@property(nonatomic, readonly) NSString *appName; + +@property(nonatomic, readonly) FIRInstallationsStore *installationsStore; +@property(nonatomic, readonly) FIRInstallationsIIDStore *IIDStore; +@property(nonatomic, readonly) FIRInstallationsIIDTokenStore *IIDTokenStore; + +@property(nonatomic, readonly) FIRInstallationsAPIService *APIService; + +@property(nonatomic, readonly) id backoffController; + +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *getInstallationPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *authTokenPromiseCache; +@property(nonatomic, readonly) FIRInstallationsSingleOperationPromiseCache + *authTokenForcingRefreshPromiseCache; +@property(nonatomic, readonly) + FIRInstallationsSingleOperationPromiseCache *deleteInstallationPromiseCache; +@end + +@implementation FIRInstallationsIDController + +- (instancetype)initWithApp:(FIRApp *)app { + NSString *serviceName = + [FIRInstallationsIDController keychainServiceWithAppID:app.options.googleAppID]; + GULKeychainStorage *secureStorage = [[GULKeychainStorage alloc] initWithService:serviceName]; + FIRInstallationsStore *installationsStore = + [[FIRInstallationsStore alloc] initWithSecureStorage:secureStorage + accessGroup:app.options.appGroupID]; + + FIRInstallationsAPIService *apiService = + [[FIRInstallationsAPIService alloc] initWithAPIKey:app.options.APIKey + projectID:app.options.projectID + heartbeatLogger:app.heartbeatLogger]; + + FIRInstallationsIIDStore *IIDStore = [[FIRInstallationsIIDStore alloc] init]; + FIRInstallationsIIDTokenStore *IIDCheckingStore = + [[FIRInstallationsIIDTokenStore alloc] initWithGCMSenderID:app.options.GCMSenderID]; + + FIRInstallationsBackoffController *backoffController = + [[FIRInstallationsBackoffController alloc] init]; + + return [self initWithGoogleAppID:app.options.googleAppID + appName:app.name + installationsStore:installationsStore + APIService:apiService + IIDStore:IIDStore + IIDTokenStore:IIDCheckingStore + backoffController:backoffController]; +} + +/// The initializer is supposed to be used by tests to inject `installationsStore`. +- (instancetype)initWithGoogleAppID:(NSString *)appID + appName:(NSString *)appName + installationsStore:(FIRInstallationsStore *)installationsStore + APIService:(FIRInstallationsAPIService *)APIService + IIDStore:(FIRInstallationsIIDStore *)IIDStore + IIDTokenStore:(FIRInstallationsIIDTokenStore *)IIDTokenStore + backoffController: + (id)backoffController { + self = [super init]; + if (self) { + _appID = appID; + _appName = appName; + _installationsStore = installationsStore; + _APIService = APIService; + _IIDStore = IIDStore; + _IIDTokenStore = IIDTokenStore; + _backoffController = backoffController; + + __weak FIRInstallationsIDController *weakSelf = self; + + _getInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createGetInstallationItemPromise]; + }]; + + _authTokenPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:NO]; + }]; + + _authTokenForcingRefreshPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf installationWithValidAuthTokenForcingRefresh:YES]; + }]; + + _deleteInstallationPromiseCache = [[FIRInstallationsSingleOperationPromiseCache alloc] + initWithNewOperationHandler:^FBLPromise *_Nonnull { + FIRInstallationsIDController *strongSelf = weakSelf; + return [strongSelf createDeleteInstallationPromise]; + }]; + } + return self; +} + +#pragma mark - Get Installation. + +- (FBLPromise *)getInstallationItem { + return [self.getInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createGetInstallationItemPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewGetInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + FBLPromise *installationItemPromise = + [self getStoredInstallation].recover(^id(NSError *error) { + return [self createAndSaveFID]; + }); + + // Initiate registration process on success if needed, but return the installation without waiting + // for it. + installationItemPromise.then(^id(FIRInstallationsItem *installation) { + [self getAuthTokenForcingRefresh:NO]; + return nil; + }); + + return installationItemPromise; +} + +- (FBLPromise *)getStoredInstallation { + return [self.installationsStore installationForAppID:self.appID appName:self.appName].validate( + ^BOOL(FIRInstallationsItem *installation) { + NSError *validationError; + BOOL isValid = [installation isValid:&validationError]; + + if (!isValid) { + FIRLogWarning( + kFIRLoggerInstallations, kFIRInstallationsMessageCodeCorruptedStoredInstallation, + @"Stored installation validation error: %@", validationError.localizedDescription); + } + + return isValid; + }); +} + +- (FBLPromise *)createAndSaveFID { + return [self migrateOrGenerateInstallation] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self saveInstallation:installation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *installation) { + [self postFIDDidChangeNotification]; + return installation; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installation { + return [self.installationsStore saveInstallation:installation].then( + ^FIRInstallationsItem *(NSNull *result) { + return installation; + }); +} + +/** + * Tries to migrate IID data stored by FirebaseInstanceID SDK or generates a new Installation ID if + * not found. + */ +- (FBLPromise *)migrateOrGenerateInstallation { + if (![self isDefaultApp]) { + // Existing IID should be used only for default FirebaseApp. + FIRInstallationsItem *installation = + [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + return [FBLPromise resolvedWith:installation]; + } + + return [[[FBLPromise + all:@[ [self.IIDStore existingIID], [self.IIDTokenStore existingIIDDefaultToken] ]] + then:^id _Nullable(NSArray *_Nullable results) { + NSString *existingIID = results[0]; + NSString *IIDDefaultToken = results[1]; + + return [self createInstallationWithFID:existingIID IIDDefaultToken:IIDDefaultToken]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + return [self createInstallationWithFID:[FIRInstallationsItem generateFID] IIDDefaultToken:nil]; + }]; +} + +- (FIRInstallationsItem *)createInstallationWithFID:(NSString *)FID + IIDDefaultToken:(nullable NSString *)IIDDefaultToken { + FIRInstallationsItem *installation = [[FIRInstallationsItem alloc] initWithAppID:self.appID + firebaseAppName:self.appName]; + installation.firebaseInstallationID = FID; + installation.IIDDefaultToken = IIDDefaultToken; + installation.registrationStatus = FIRInstallationStatusUnregistered; + return installation; +} + +#pragma mark - FID registration + +- (FBLPromise *)registerInstallationIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusRegistered: + // Already registered. Do nothing. + return [FBLPromise resolvedWith:installation]; + + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // Registration required. Proceed. + break; + } + + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [self.APIService registerInstallation:installation] + .catch(^(NSError *_Nonnull error) { + [self updateBackoffWithSuccess:NO APIError:error]; + + if ([self doesRegistrationErrorRequireConfigChange:error]) { + FIRLogError(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInvalidFirebaseConfiguration, + @"Firebase Installation registration failed for app with name: %@, error:\n" + @"%@\nPlease make sure you use valid GoogleService-Info.plist", + self.appName, error.userInfo[NSLocalizedFailureReasonErrorKey]); + } + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:registeredInstallation]; + }) + .then(^FIRInstallationsItem *(FIRInstallationsItem *registeredInstallation) { + // Server may respond with a different FID if the sent one cannot be accepted. + if (![registeredInstallation.firebaseInstallationID + isEqualToString:installation.firebaseInstallationID]) { + [self postFIDDidChangeNotification]; + } + return registeredInstallation; + }); +} + +- (BOOL)doesRegistrationErrorRequireConfigChange:(NSError *)error { + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + if (![HTTPError isKindOfClass:[FIRInstallationsHTTPError class]]) { + return NO; + } + + switch (HTTPError.HTTPResponse.statusCode) { + // These are the errors that require Firebase configuration change. + case FIRInstallationsRegistrationHTTPCodeInvalidArgument: + case FIRInstallationsRegistrationHTTPCodeAPIKeyToProjectIDMismatch: + case FIRInstallationsRegistrationHTTPCodeProjectNotFound: + return YES; + + default: + return NO; + } +} + +#pragma mark - Auth Token + +- (FBLPromise *)getAuthTokenForcingRefresh:(BOOL)forceRefresh { + if (forceRefresh || [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] != nil) { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingOrCreateNewPromise]; + } else { + return [self.authTokenPromiseCache getExistingPendingOrCreateNewPromise]; + } +} + +- (FBLPromise *)installationWithValidAuthTokenForcingRefresh: + (BOOL)forceRefresh { + FIRLogDebug(kFIRLoggerInstallations, kFIRInstallationsMessageCodeNewGetAuthTokenOperationCreated, + @"-[FIRInstallationsIDController installationWithValidAuthTokenForcingRefresh:%@], " + @"appName: %@", + @(forceRefresh), self.appName); + + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self registerInstallationIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *registeredInstallation) { + BOOL isTokenExpiredOrExpiresSoon = + [registeredInstallation.authToken.expirationDate timeIntervalSinceDate:[NSDate date]] < + kFIRInstallationsTokenExpirationThreshold; + if (forceRefresh || isTokenExpiredOrExpiresSoon) { + return [self refreshAuthTokenForInstallation:registeredInstallation]; + } else { + return registeredInstallation; + } + }) + .recover(^id(NSError *error) { + return [self regenerateFIDOnRefreshTokenErrorIfNeeded:error]; + }); +} + +- (FBLPromise *)refreshAuthTokenForInstallation: + (FIRInstallationsItem *)installation { + // Check for backoff. + if (![self.backoffController isNextRequestAllowed]) { + return [FIRInstallationsErrorUtil + rejectedPromiseWithError:[FIRInstallationsErrorUtil backoffIntervalWaitError]]; + } + + return [[[self.APIService refreshAuthTokenForInstallation:installation] + then:^id _Nullable(FIRInstallationsItem *_Nullable refreshedInstallation) { + [self updateBackoffWithSuccess:YES APIError:nil]; + return [self saveInstallation:refreshedInstallation]; + }] recover:^id _Nullable(NSError *_Nonnull error) { + // Pass the error to the backoff controller. + [self updateBackoffWithSuccess:NO APIError:error]; + return error; + }]; +} + +- (id)regenerateFIDOnRefreshTokenErrorIfNeeded:(NSError *)error { + if (![error isKindOfClass:[FIRInstallationsHTTPError class]]) { + // No recovery possible. Return the same error. + return error; + } + + FIRInstallationsHTTPError *HTTPError = (FIRInstallationsHTTPError *)error; + switch (HTTPError.HTTPResponse.statusCode) { + case FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication: + case FIRInstallationsAuthTokenHTTPCodeFIDNotFound: + // The stored installation was damaged or blocked by the server. + // Delete the stored installation then generate and register a new one. + return [self getInstallationItem] + .then(^FBLPromise *(FIRInstallationsItem *installation) { + return [self deleteInstallationLocally:installation]; + }) + .then(^FBLPromise *(id result) { + return [self installationWithValidAuthTokenForcingRefresh:NO]; + }); + + default: + // No recovery possible. Return the same error. + return error; + } +} + +#pragma mark - Delete FID + +- (FBLPromise *)deleteInstallation { + return [self.deleteInstallationPromiseCache getExistingPendingOrCreateNewPromise]; +} + +- (FBLPromise *)createDeleteInstallationPromise { + FIRLogDebug(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeNewDeleteInstallationOperationCreated, @"%s, appName: %@", + __PRETTY_FUNCTION__, self.appName); + + // Check for ongoing requests first, if there is no a request, then check local storage for + // existing installation. + FBLPromise *currentInstallationPromise = + [self mostRecentInstallationOperation] ?: [self getStoredInstallation]; + + return currentInstallationPromise + .then(^id(FIRInstallationsItem *installation) { + return [self sendDeleteInstallationRequestIfNeeded:installation]; + }) + .then(^id(FIRInstallationsItem *installation) { + // Remove the installation from the local storage. + return [self deleteInstallationLocally:installation]; + }); +} + +- (FBLPromise *)deleteInstallationLocally:(FIRInstallationsItem *)installation { + return [self.installationsStore removeInstallationForAppID:installation.appID + appName:installation.firebaseAppName] + .then(^FBLPromise *(NSNull *result) { + return [self deleteExistingIIDIfNeeded]; + }) + .then(^NSNull *(NSNull *result) { + [self postFIDDidChangeNotification]; + return result; + }); +} + +- (FBLPromise *)sendDeleteInstallationRequestIfNeeded: + (FIRInstallationsItem *)installation { + switch (installation.registrationStatus) { + case FIRInstallationStatusUnknown: + case FIRInstallationStatusUnregistered: + // The installation is not registered, so it is safe to be deleted as is, so return early. + return [FBLPromise resolvedWith:installation]; + break; + + case FIRInstallationStatusRegistered: + // Proceed to de-register the installation on the server. + break; + } + + return [self.APIService deleteInstallation:installation].recover(^id(NSError *APIError) { + if ([FIRInstallationsErrorUtil isAPIError:APIError withHTTPCode:404]) { + // The installation was not found on the server. + // Return success. + return installation; + } else { + // Re-throw the error otherwise. + return APIError; + } + }); +} + +- (FBLPromise *)deleteExistingIIDIfNeeded { + if ([self isDefaultApp]) { + return [self.IIDStore deleteExistingIID]; + } else { + return [FBLPromise resolvedWith:[NSNull null]]; + } +} + +- (nullable FBLPromise *)mostRecentInstallationOperation { + return [self.authTokenForcingRefreshPromiseCache getExistingPendingPromise] + ?: [self.authTokenPromiseCache getExistingPendingPromise] + ?: [self.getInstallationPromiseCache getExistingPendingPromise]; +} + +#pragma mark - Backoff + +- (void)updateBackoffWithSuccess:(BOOL)success APIError:(nullable NSError *)APIError { + if (success) { + [self.backoffController registerEvent:FIRInstallationsBackoffEventSuccess]; + } else if ([APIError isKindOfClass:[FIRInstallationsHTTPError class]]) { + FIRInstallationsHTTPError *HTTPResponseError = (FIRInstallationsHTTPError *)APIError; + NSInteger statusCode = HTTPResponseError.HTTPResponse.statusCode; + + if (statusCode == FIRInstallationsAuthTokenHTTPCodeInvalidAuthentication || + statusCode == FIRInstallationsAuthTokenHTTPCodeFIDNotFound) { + // These errors are explicitly excluded because they are handled by FIS SDK itself so don't + // require backoff. + } else if (statusCode == 400 || statusCode == 403) { // Explicitly unrecoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventUnrecoverableFailure]; + } else if (statusCode == 429 || + (statusCode >= 500 && statusCode < 600)) { // Explicitly recoverable errors. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } else { // Treat all unknown errors as recoverable. + [self.backoffController registerEvent:FIRInstallationsBackoffEventRecoverableFailure]; + } + } + + // If the error class is not `FIRInstallationsHTTPError` it indicates a connection error. Such + // errors should not change backoff interval. +} + +#pragma mark - Notifications + +- (void)postFIDDidChangeNotification { + [[NSNotificationCenter defaultCenter] + postNotificationName:FIRInstallationIDDidChangeNotification + object:nil + userInfo:@{kFIRInstallationIDDidChangeNotificationAppNameKey : self.appName}]; +} + +#pragma mark - Default App + +- (BOOL)isDefaultApp { + return [self.appName isEqualToString:kFIRDefaultAppName]; +} + +#pragma mark - Keychain + ++ (NSString *)keychainServiceWithAppID:(NSString *)appID { +#if TARGET_OS_MACCATALYST || TARGET_OS_OSX + // We need to keep service name unique per application on macOS. + // Applications on macOS may request access to Keychain items stored by other applications. It + // means that when the app looks up for a relevant Keychain item in the service scope it will + // request user password to grant access to the Keychain if there are other Keychain items from + // other applications stored under the same Keychain Service. + return [kKeychainService stringByAppendingFormat:@".%@", appID]; +#else + // Use a constant Keychain service for non-macOS because: + // 1. Keychain items cannot be shared between apps until configured specifically so the service + // name collisions are not a concern + // 2. We don't want to change the service name to avoid doing a migration. + return kKeychainService; +#endif +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h new file mode 100644 index 0000000..aeb54e5 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class makes sure the a single operation (represented by a promise) is performed at a time. If + * there is an ongoing operation, then its existing corresponding promise will be returned instead + * of starting a new operation. + */ +@interface FIRInstallationsSingleOperationPromiseCache<__covariant ResultType> : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * The designated initializer. + * @param newOperationHandler The block that must return a new promise representing the + * single-at-a-time operation. The promise should be fulfilled when the operation is completed. The + * factory block will be used to create a new promise when needed. + */ +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler NS_DESIGNATED_INITIALIZER; + +/** + * Creates a new promise or returns an existing pending one. + * @return Returns and existing pending promise if exists. If the pending promise does not exist + * then a new one will be created using the `factory` block passed in the initializer. Once the + * pending promise gets resolved, it is removed, so calling the method again will lead to creating + * and caching another promise. + */ +- (FBLPromise *)getExistingPendingOrCreateNewPromise; + +/** + * Returns an existing pending promise or `nil`. + * @return Returns an existing pending promise if there is one or `nil` otherwise. + */ +- (nullable FBLPromise *)getExistingPendingPromise; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m new file mode 100644 index 0000000..7ae8781 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.m @@ -0,0 +1,75 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsSingleOperationPromiseCache.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +@interface FIRInstallationsSingleOperationPromiseCache () +@property(nonatomic, readonly) FBLPromise *_Nonnull (^newOperationHandler)(void); +@property(nonatomic, nullable) FBLPromise *pendingPromise; +@end + +@implementation FIRInstallationsSingleOperationPromiseCache + +- (instancetype)initWithNewOperationHandler: + (FBLPromise *_Nonnull (^)(void))newOperationHandler { + if (newOperationHandler == nil) { + [NSException raise:NSInvalidArgumentException + format:@"`newOperationHandler` must not be `nil`."]; + } + + self = [super init]; + if (self) { + _newOperationHandler = [newOperationHandler copy]; + } + return self; +} + +- (FBLPromise *)getExistingPendingOrCreateNewPromise { + @synchronized(self) { + if (!self.pendingPromise) { + self.pendingPromise = self.newOperationHandler(); + + self.pendingPromise + .then(^id(id result) { + @synchronized(self) { + self.pendingPromise = nil; + return nil; + } + }) + .catch(^void(NSError *error) { + @synchronized(self) { + self.pendingPromise = nil; + } + }); + } + + return self.pendingPromise; + } +} + +- (nullable FBLPromise *)getExistingPendingPromise { + @synchronized(self) { + return self.pendingPromise; + } +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h new file mode 100644 index 0000000..3edc692 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * The enum represent possible states of the installation ID. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredItem`. Modification + * of it can lead to incompatibility with previous version. Any modification must be evaluated and, + * if it is really needed, the `storageVersion` must be bumped and proper migration code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsStatus) { + /** Represents either an initial status when a FIRInstallationsItem instance was created but not + * stored to Keychain or an undefined status (e.g. when the status failed to deserialize). + */ + FIRInstallationStatusUnknown, + /// The Firebase Installation has not yet been registered with FIS. + FIRInstallationStatusUnregistered, + /// The Firebase Installation has successfully been registered with FIS. + FIRInstallationStatusRegistered, +}; diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h new file mode 100644 index 0000000..b86fb39 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h @@ -0,0 +1,71 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FBLPromise; +@class FIRInstallationsItem; +@class GULKeychainStorage; + +NS_ASSUME_NONNULL_BEGIN + +/// The user defaults suite name used to store data. +extern NSString *const kFIRInstallationsStoreUserDefaultsID; + +/// The class is responsible for storing and accessing the installations data. +@interface FIRInstallationsStore : NSObject + +/** + * The default initializer. + * @param storage The secure storage to save installations data. + * @param accessGroup The Keychain Access Group to store and request the installations data. + */ +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(nullable NSString *)accessGroup; + +/** + * Retrieves existing installation ID if there is. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a `FBLPromise` instance. The promise is resolved with a FIRInstallationsItem + * instance if there is a valid installation stored for `appID` and `appName`. The promise is + * rejected with a specific error when the installation has not been found or with another possible + * error. + */ +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName; + +/** + * Saves the given installation. + * + * @param installationItem The installation data. + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem; + +/** + * Removes installation data for the given app parameters. + * @param appID The Firebase(Google) Application ID. + * @param appName The Firebase Application Name. + * + * @return Returns a promise that is resolved with `[NSNull null]` on success. + */ +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m new file mode 100644 index 0000000..617b2d9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.m @@ -0,0 +1,140 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStore.h" + +#import + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import + +#import "FirebaseInstallations/Source/Library/Errors/FIRInstallationsErrorUtil.h" +#import "FirebaseInstallations/Source/Library/FIRInstallationsItem.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +NSString *const kFIRInstallationsStoreUserDefaultsID = @"com.firebase.FIRInstallations"; + +@interface FIRInstallationsStore () +@property(nonatomic, readonly) GULKeychainStorage *secureStorage; +@property(nonatomic, readonly, nullable) NSString *accessGroup; +@property(nonatomic, readonly) dispatch_queue_t queue; +@property(nonatomic, readonly) GULUserDefaults *userDefaults; +@end + +@implementation FIRInstallationsStore + +- (instancetype)initWithSecureStorage:(GULKeychainStorage *)storage + accessGroup:(NSString *)accessGroup { + self = [super init]; + if (self) { + _secureStorage = storage; + _accessGroup = [accessGroup copy]; + _queue = dispatch_queue_create("com.firebase.FIRInstallationsStore", DISPATCH_QUEUE_SERIAL); + + NSString *userDefaultsSuiteName = _accessGroup ?: kFIRInstallationsStoreUserDefaultsID; + _userDefaults = [[GULUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName]; + } + return self; +} + +- (FBLPromise *)installationForAppID:(NSString *)appID + appName:(NSString *)appName { + NSString *itemID = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [self installationExistsForAppID:appID appName:appName] + .then(^id(id result) { + return [FBLPromise + wrapObjectOrErrorCompletion:^(FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [self.secureStorage getObjectForKey:itemID + objectClass:[FIRInstallationsStoredItem class] + accessGroup:self.accessGroup + completionHandler:handler]; + }]; + }) + .then(^id(FIRInstallationsStoredItem *_Nullable storedItem) { + if (storedItem == nil) { + return [FIRInstallationsErrorUtil installationItemNotFoundForAppID:appID appName:appName]; + } + + FIRInstallationsItem *item = [[FIRInstallationsItem alloc] initWithAppID:appID + firebaseAppName:appName]; + [item updateWithStoredItem:storedItem]; + return item; + }); +} + +- (FBLPromise *)saveInstallation:(FIRInstallationsItem *)installationItem { + FIRInstallationsStoredItem *storedItem = [installationItem storedItem]; + NSString *identifier = [installationItem identifier]; + + return + [FBLPromise wrapObjectOrErrorCompletion:^( + FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [self.secureStorage setObject:storedItem + forKey:identifier + accessGroup:self.accessGroup + completionHandler:handler]; + }].then(^id(id __unused unusedResult) { + return [self setInstallationExists:YES forItemWithIdentifier:identifier]; + }); +} + +- (FBLPromise *)removeInstallationForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + + return + [FBLPromise wrapErrorCompletion:^(FBLPromiseErrorCompletion _Nonnull handler) { + [self.secureStorage removeObjectForKey:identifier + accessGroup:self.accessGroup + completionHandler:handler]; + }].then(^id(id __unused result) { + return [self setInstallationExists:NO forItemWithIdentifier:identifier]; + }); +} + +#pragma mark - User defaults + +- (FBLPromise *)installationExistsForAppID:(NSString *)appID appName:(NSString *)appName { + NSString *identifier = [FIRInstallationsItem identifierWithAppID:appID appName:appName]; + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + return [[self userDefaults] objectForKey:identifier] != nil + ? [NSNull null] + : [FIRInstallationsErrorUtil + installationItemNotFoundForAppID:appID + appName:appName]; + }]; +} + +- (FBLPromise *)setInstallationExists:(BOOL)exists + forItemWithIdentifier:(NSString *)identifier { + return [FBLPromise onQueue:self.queue + do:^id _Nullable { + if (exists) { + [[self userDefaults] setBool:YES forKey:identifier]; + } else { + [[self userDefaults] removeObjectForKey:identifier]; + } + + return [NSNull null]; + }]; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h new file mode 100644 index 0000000..4da2337 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h @@ -0,0 +1,58 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The enum represent possible states of the installation auth token. + * + * WARNING: The enum is stored to Keychain as a part of `FIRInstallationsStoredAuthToken`. + * Modification of it can lead to incompatibility with previous version. Any modification must be + * evaluated and, if it is really needed, the `storageVersion` must be bumped and proper migration + * code added. + */ +typedef NS_ENUM(NSInteger, FIRInstallationsAuthTokenStatus) { + /// An initial status or an undefined value. + FIRInstallationsAuthTokenStatusUnknown, + /// The auth token has been received from the server. + FIRInstallationsAuthTokenStatusTokenReceived +}; + +/** + * This class serializes and deserializes the installation data into/from `NSData` to be stored in + * Keychain. This class is primarily used by `FIRInstallationsStore`. It is also used on the logic + * level as a data object (see `FIRInstallationsItem.authToken`). + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredAuthToken : NSObject +@property FIRInstallationsAuthTokenStatus status; + +/// The installation auth token string that can be used to authorize requests to Firebase backend. +@property(nullable, copy) NSString *token; +/// The installation auth token expiration date. +@property(nullable, copy) NSDate *expirationDate; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m new file mode 100644 index 0000000..8236f2a --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.m @@ -0,0 +1,77 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" + +NSString *const kFIRInstallationsStoredAuthTokenStatusKey = @"status"; +NSString *const kFIRInstallationsStoredAuthTokenTokenKey = @"token"; +NSString *const kFIRInstallationsStoredAuthTokenExpirationDateKey = @"expirationDate"; +NSString *const kFIRInstallationsStoredAuthTokenStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredAuthTokenStorageVersion = 1; + +@implementation FIRInstallationsStoredAuthToken + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredAuthTokenStorageVersion; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + FIRInstallationsStoredAuthToken *clone = [[FIRInstallationsStoredAuthToken alloc] init]; + clone.status = self.status; + clone.token = [self.token copy]; + clone.expirationDate = self.expirationDate; + return clone; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeInteger:self.status forKey:kFIRInstallationsStoredAuthTokenStatusKey]; + [aCoder encodeObject:self.token forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + [aCoder encodeObject:self.expirationDate + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + [aCoder encodeInteger:self.storageVersion + forKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStorageVersionKey]; + if (storageVersion > kFIRInstallationsStoredAuthTokenStorageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeAuthTokenCoderVersionMismatch, + @"FIRInstallationsStoredAuthToken was encoded by a newer coder version %ld. " + @"Current coder version is %ld. Some auth token data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredAuthTokenStorageVersion); + } + + FIRInstallationsStoredAuthToken *object = [[FIRInstallationsStoredAuthToken alloc] init]; + object.status = [aDecoder decodeIntegerForKey:kFIRInstallationsStoredAuthTokenStatusKey]; + object.token = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredAuthTokenTokenKey]; + object.expirationDate = + [aDecoder decodeObjectOfClass:[NSDate class] + forKey:kFIRInstallationsStoredAuthTokenExpirationDateKey]; + + return object; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h new file mode 100644 index 0000000..0126eb0 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseInstallations/Source/Library/InstallationsIDController/FIRInstallationsStatus.h" + +@class FIRInstallationsStoredAuthToken; +@class FIRInstallationsStoredIIDCheckin; + +NS_ASSUME_NONNULL_BEGIN + +/** + * The class is supposed to be used by `FIRInstallationsStore` only. It is required to + * serialize/deserialize the installation data into/from `NSData` to be stored in Keychain. + * + * WARNING: Modification of the class properties can lead to incompatibility with the stored data + * encoded by the previous class versions. Any modification must be evaluated and, if it is really + * needed, the `storageVersion` must be bumped and proper migration code added. + */ +@interface FIRInstallationsStoredItem : NSObject + +/// A stable identifier that uniquely identifies the app instance. +@property(nonatomic, copy, nullable) NSString *firebaseInstallationID; +/// The `refreshToken` is used to authorize the installation auth token requests. +@property(nonatomic, copy, nullable) NSString *refreshToken; + +@property(nonatomic, nullable) FIRInstallationsStoredAuthToken *authToken; +@property(nonatomic) FIRInstallationsStatus registrationStatus; + +/// Instance ID default auth token imported from IID store as a part of IID migration. +@property(nonatomic, nullable) NSString *IIDDefaultToken; + +/// The version of local storage. +@property(nonatomic, readonly) NSInteger storageVersion; +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m new file mode 100644 index 0000000..4e19955 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.m @@ -0,0 +1,80 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredItem.h" + +#import "FirebaseInstallations/Source/Library/FIRInstallationsLogger.h" +#import "FirebaseInstallations/Source/Library/InstallationsStore/FIRInstallationsStoredAuthToken.h" + +NSString *const kFIRInstallationsStoredItemFirebaseInstallationIDKey = @"firebaseInstallationID"; +NSString *const kFIRInstallationsStoredItemRefreshTokenKey = @"refreshToken"; +NSString *const kFIRInstallationsStoredItemAuthTokenKey = @"authToken"; +NSString *const kFIRInstallationsStoredItemRegistrationStatusKey = @"registrationStatus"; +NSString *const kFIRInstallationsStoredItemIIDDefaultTokenKey = @"IIDDefaultToken"; +NSString *const kFIRInstallationsStoredItemStorageVersionKey = @"storageVersion"; + +NSInteger const kFIRInstallationsStoredItemStorageVersion = 1; + +@implementation FIRInstallationsStoredItem + +- (NSInteger)storageVersion { + return kFIRInstallationsStoredItemStorageVersion; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)aCoder { + [aCoder encodeObject:self.firebaseInstallationID + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + [aCoder encodeObject:self.refreshToken forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + [aCoder encodeObject:self.authToken forKey:kFIRInstallationsStoredItemAuthTokenKey]; + [aCoder encodeInteger:self.registrationStatus + forKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + [aCoder encodeObject:self.IIDDefaultToken forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + [aCoder encodeInteger:self.storageVersion forKey:kFIRInstallationsStoredItemStorageVersionKey]; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)aDecoder { + NSInteger storageVersion = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemStorageVersionKey]; + if (storageVersion > self.storageVersion) { + FIRLogWarning(kFIRLoggerInstallations, + kFIRInstallationsMessageCodeInstallationCoderVersionMismatch, + @"FIRInstallationsStoredItem was encoded by a newer coder version %ld. Current " + @"coder version is %ld. Some installation data may be lost.", + (long)storageVersion, (long)kFIRInstallationsStoredItemStorageVersion); + } + + FIRInstallationsStoredItem *item = [[FIRInstallationsStoredItem alloc] init]; + item.firebaseInstallationID = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemFirebaseInstallationIDKey]; + item.refreshToken = [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemRefreshTokenKey]; + item.authToken = [aDecoder decodeObjectOfClass:[FIRInstallationsStoredAuthToken class] + forKey:kFIRInstallationsStoredItemAuthTokenKey]; + item.registrationStatus = + [aDecoder decodeIntegerForKey:kFIRInstallationsStoredItemRegistrationStatusKey]; + item.IIDDefaultToken = + [aDecoder decodeObjectOfClass:[NSString class] + forKey:kFIRInstallationsStoredItemIIDDefaultTokenKey]; + + return item; +} + ++ (BOOL)supportsSecureCoding { + return YES; +} + +@end diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h new file mode 100644 index 0000000..1811d2b --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallations.h @@ -0,0 +1,127 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRInstallationsAuthTokenResult; + +NS_ASSUME_NONNULL_BEGIN + +/** A notification with this name is sent each time an installation is created or deleted. */ +// clang-format off +// clang-format12 merges the next two lines. +FOUNDATION_EXPORT const NSNotificationName FIRInstallationIDDidChangeNotification + NS_SWIFT_NAME(InstallationIDDidChange); +/** `userInfo` key for the `FirebaseApp.name` in `InstallationIDDidChangeNotification`. */ +FOUNDATION_EXPORT NSString *const kFIRInstallationIDDidChangeNotificationAppNameKey + NS_SWIFT_NAME(InstallationIDDidChangeAppNameKey); +// clang-format on + +/** + * An installation ID handler block. + * @param identifier The installation ID string if exists or `nil` otherwise. + * @param error The error when `identifier == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsIDHandler)(NSString *__nullable identifier, + NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * An authorization token handler block. + * @param tokenResult An instance of `InstallationsAuthTokenResult` in case of success or `nil` + * otherwise. + * @param error The error when `tokenResult == nil` or `nil` otherwise. + */ +typedef void (^FIRInstallationsTokenHandler)( + FIRInstallationsAuthTokenResult *__nullable tokenResult, NSError *__nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/** + * The class provides API for Firebase Installations. + * Each configured `FirebaseApp` has a corresponding single instance of `Installations`. + * An instance of the class provides access to the installation info for the `FirebaseApp` as well + * as the ability to delete it. A Firebase Installation is unique by `FirebaseApp.name` and + * `FirebaseApp.options.googleAppID` . + */ +NS_SWIFT_NAME(Installations) +@interface FIRInstallations : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Returns a default instance of `Installations`. + * @return An instance of `Installations` for `FirebaseApp.defaultApp(). + * @throw Throws an exception if the default app is not configured yet or required `FirebaseApp` + * options are missing. + */ ++ (FIRInstallations *)installations NS_SWIFT_NAME(installations()); + +/** + * Returns an instance of `Installations` for an application. + * @param application A configured `FirebaseApp` instance. + * @return An instance of `Installations` corresponding to the passed application. + * @throw Throws an exception if required `FirebaseApp` options are missing. + */ ++ (FIRInstallations *)installationsWithApp:(FIRApp *)application NS_SWIFT_NAME(installations(app:)); + +/** + * The method creates or retrieves an installation ID. The installation ID is a stable identifier + * that uniquely identifies the app instance. NOTE: If the application already has an existing + * FirebaseInstanceID then the InstanceID identifier will be used. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)installationIDWithCompletion:(void (^)(NSString *__nullable identifier, + NSError *__nullable error))completion; + +/** + * Retrieves (locally if it exists or from the server) a valid installation auth token. An existing + * token may be invalidated or expired, so it is recommended to fetch the installation auth token + * before each server request. The method does the same as + * `Installations.authToken(forcingRefresh:completion:)` with forcing refresh `false`. + * @param completion A completion handler which is invoked when the operation completes. + */ +- (void)authTokenWithCompletion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Retrieves (locally or from the server depending on `forceRefresh` value) a valid installation + * auth token. An existing token may be invalidated or expire, so it is recommended to fetch the + * installation auth token before each server request. This method should be used with `forceRefresh + * == true` when e.g. a request with the previously fetched installation auth token failed with "Not + * Authorized" error. + * @param forceRefresh If `true` then the locally cached installation auth token will be ignored and + * a new one will be requested from the server. If `false`, then the locally cached installation + * auth token will be returned if exists and has not expired yet. + * @param completion A completion handler which is invoked when the operation completes. See + * `InstallationsTokenHandler` for additional details. + */ +- (void)authTokenForcingRefresh:(BOOL)forceRefresh + completion:(void (^)(FIRInstallationsAuthTokenResult *__nullable tokenResult, + NSError *__nullable error))completion; + +/** + * Deletes all the installation data including the unique identifier, auth tokens and + * all related data on the server side. A network connection is required for the method to + * succeed. If fails, the existing installation data remains untouched. + * @param completion A completion handler which is invoked when the operation completes. `error == + * nil` indicates success. + */ +- (void)deleteWithCompletion:(void (^)(NSError *__nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h new file mode 100644 index 0000000..501ac4e --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsAuthTokenResult.h @@ -0,0 +1,33 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents a result of the installation auth token request. */ +NS_SWIFT_NAME(InstallationsAuthTokenResult) +@interface FIRInstallationsAuthTokenResult : NSObject + +/** The installation auth token string. */ +@property(nonatomic, readonly) NSString *authToken; + +/** The installation auth token expiration date. */ +@property(nonatomic, readonly) NSDate *expirationDate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h new file mode 100644 index 0000000..939ca0a --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FIRInstallationsErrors.h @@ -0,0 +1,35 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +extern NSString *const kFirebaseInstallationsErrorDomain NS_SWIFT_NAME(InstallationsErrorDomain); + +typedef NS_ERROR_ENUM(kFirebaseInstallationsErrorDomain, FIRInstallationsErrorCode){ + /** Unknown error. See `userInfo` for details. */ + FIRInstallationsErrorCodeUnknown = 0, + + /** Keychain error. See `userInfo` for details. */ + FIRInstallationsErrorCodeKeychain = 1, + + /** Server unreachable. A network error or server is unavailable. See `userInfo` for details. */ + FIRInstallationsErrorCodeServerUnreachable = 2, + + /** FirebaseApp configuration issues e.g. invalid GMP-App-ID, etc. See `userInfo` for details. + */ + FIRInstallationsErrorCodeInvalidConfiguration = 3, + +} NS_SWIFT_NAME(InstallationsErrorCode); diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h new file mode 100644 index 0000000..8a9b3c1 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Public/FirebaseInstallations/FirebaseInstallations.h @@ -0,0 +1,19 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRInstallations.h" +#import "FIRInstallationsAuthTokenResult.h" +#import "FIRInstallationsErrors.h" diff --git a/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1e83fa6 --- /dev/null +++ b/Pods/FirebaseInstallations/FirebaseInstallations/Source/Library/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,30 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/Pods/FirebaseInstallations/LICENSE b/Pods/FirebaseInstallations/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseInstallations/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseInstallations/README.md b/Pods/FirebaseInstallations/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseInstallations/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebasePerformance/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebasePerformance/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebasePerformance/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/Pods/FirebasePerformance/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h new file mode 100644 index 0000000..a24949e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h @@ -0,0 +1,64 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h" + +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppStartTraceName; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppStartStageNameTimeToUI; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppStartStageNameTimeToFirstDraw; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppStartStageNameTimeToUserInteraction; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppTraceNameForegroundSession; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppTraceNameBackgroundSession; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppCounterNameTraceEventsRateLimited; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppCounterNameNetworkTraceEventsRateLimited; +FOUNDATION_EXTERN NSString *__nonnull const kFPRAppCounterNameTraceNotStopped; + +/** Different states of the current application. */ +typedef NS_ENUM(NSInteger, FPRApplicationState) { + FPRApplicationStateUnknown, + + /** Application in foreground. */ + FPRApplicationStateForeground, + + /** Application in background. */ + FPRApplicationStateBackground, +}; + +/** This class is used to track the app activity and create internal traces to capture the + * performance metrics. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRAppActivityTracker : NSObject + +/** The trace that tracks the currently active session of the app. *Do not stop this trace*. This is + * an active trace that needs to be running. Stopping this trace might impact the overall + * performance metrics captured for the active session. All other operations can be performed. + */ +@property(nonatomic, nullable, readonly) FIRTrace *activeTrace; + +/** Current running state of the application. */ +@property(nonatomic, readonly) FPRApplicationState applicationState; + +/** Current network connection type of the application. */ +@property(nonatomic, readonly) firebase_perf_v1_NetworkConnectionInfo_NetworkType networkType; + +/** Accesses the singleton instance. + * @return Reference to the shared object if successful; nil if not. + */ ++ (nullable instancetype)sharedInstance; + +- (nullable instancetype)init NS_UNAVAILABLE; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.m new file mode 100644 index 0000000..f6efa09 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.m @@ -0,0 +1,334 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" + +#import +#import +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector+Private.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector+Private.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h" + +static NSDate *appStartTime = nil; +static NSDate *doubleDispatchTime = nil; +static NSDate *applicationDidFinishLaunchTime = nil; +static NSTimeInterval gAppStartMaxValidDuration = 60 * 60; // 60 minutes. +static FPRCPUGaugeData *gAppStartCPUGaugeData = nil; +static FPRMemoryGaugeData *gAppStartMemoryGaugeData = nil; +static BOOL isActivePrewarm = NO; + +NSString *const kFPRAppStartTraceName = @"_as"; +NSString *const kFPRAppStartStageNameTimeToUI = @"_astui"; +NSString *const kFPRAppStartStageNameTimeToFirstDraw = @"_astfd"; +NSString *const kFPRAppStartStageNameTimeToUserInteraction = @"_asti"; +NSString *const kFPRAppTraceNameForegroundSession = @"_fs"; +NSString *const kFPRAppTraceNameBackgroundSession = @"_bs"; +NSString *const kFPRAppCounterNameTraceEventsRateLimited = @"_fstec"; +NSString *const kFPRAppCounterNameNetworkTraceEventsRateLimited = @"_fsntc"; +NSString *const kFPRAppCounterNameTraceNotStopped = @"_tsns"; +NSString *const kFPRAppCounterNameActivePrewarm = @"_fsapc"; + +@interface FPRAppActivityTracker () + +/** The foreground session trace. Will be set only when the app is in the foreground. */ +@property(nonatomic, readwrite) FIRTrace *foregroundSessionTrace; + +/** The background session trace. Will be set only when the app is in the background. */ +@property(nonatomic, readwrite) FIRTrace *backgroundSessionTrace; + +/** Current running state of the application. */ +@property(nonatomic, readwrite) FPRApplicationState applicationState; + +/** Current network connection type of the application. */ +@property(nonatomic, readwrite) firebase_perf_v1_NetworkConnectionInfo_NetworkType networkType; + +/** Network monitor object to track network movements. */ +@property(nonatomic, readwrite) nw_path_monitor_t monitor; + +/** Queue used to track the network monitoring changes. */ +@property(nonatomic, readwrite) dispatch_queue_t monitorQueue; + +/** Trace to measure the app start performance. */ +@property(nonatomic) FIRTrace *appStartTrace; + +/** Tracks if the gauge metrics are dispatched. */ +@property(nonatomic) BOOL appStartGaugeMetricDispatched; + +/** Firebase Performance Configuration object */ +@property(nonatomic) FPRConfigurations *configurations; + +/** Starts tracking app active sessions. */ +- (void)startAppActivityTracking; + +@end + +@implementation FPRAppActivityTracker + ++ (void)load { + // This is an approximation of the app start time. + appStartTime = [NSDate date]; + + // When an app is prewarmed, Apple sets env variable ActivePrewarm to 1, then the env variable is + // deleted after didFinishLaunching + isActivePrewarm = [NSProcessInfo.processInfo.environment[@"ActivePrewarm"] isEqualToString:@"1"]; + + gAppStartCPUGaugeData = fprCollectCPUMetric(); + gAppStartMemoryGaugeData = fprCollectMemoryMetric(); + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(windowDidBecomeVisible:) + name:UIWindowDidBecomeVisibleNotification + object:nil]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidFinishLaunching:) + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +} + ++ (void)windowDidBecomeVisible:(NSNotification *)notification { + FPRAppActivityTracker *activityTracker = [self sharedInstance]; + [activityTracker startAppActivityTracking]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIWindowDidBecomeVisibleNotification + object:nil]; +} + ++ (void)applicationDidFinishLaunching:(NSNotification *)notification { + applicationDidFinishLaunchTime = [NSDate date]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationDidFinishLaunchingNotification + object:nil]; +} + ++ (instancetype)sharedInstance { + static FPRAppActivityTracker *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] initAppActivityTracker]; + }); + return instance; +} + +/** + * Custom initializer to create an app activity tracker. + */ +- (instancetype)initAppActivityTracker { + self = [super init]; + if (self != nil) { + _applicationState = FPRApplicationStateUnknown; + _appStartGaugeMetricDispatched = NO; + _configurations = [FPRConfigurations sharedInstance]; + [self startTrackingNetwork]; + } + return self; +} + +- (void)startAppActivityTracking { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActiveNotification:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appWillResignActiveNotification:) + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; +} + +- (FIRTrace *)activeTrace { + if (self.foregroundSessionTrace) { + return self.foregroundSessionTrace; + } + return self.backgroundSessionTrace; +} + +- (void)startTrackingNetwork { + self.networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE; + + dispatch_queue_attr_t attrs = dispatch_queue_attr_make_with_qos_class( + DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, DISPATCH_QUEUE_PRIORITY_DEFAULT); + self.monitorQueue = dispatch_queue_create("com.google.firebase.perf.network.monitor", attrs); + + self.monitor = nw_path_monitor_create(); + nw_path_monitor_set_queue(self.monitor, self.monitorQueue); + __weak FPRAppActivityTracker *weakSelf = self; + nw_path_monitor_set_update_handler(self.monitor, ^(nw_path_t _Nonnull path) { + BOOL isWiFi = nw_path_uses_interface_type(path, nw_interface_type_wifi); + BOOL isCellular = nw_path_uses_interface_type(path, nw_interface_type_cellular); + BOOL isEthernet = nw_path_uses_interface_type(path, nw_interface_type_wired); + + if (isWiFi) { + weakSelf.networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIFI; + } else if (isCellular) { + weakSelf.networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE; + } else if (isEthernet) { + weakSelf.networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_ETHERNET; + } + }); + + nw_path_monitor_start(self.monitor); +} + +/** + * Checks if the prewarming feature is available on the current device. + * + * @return true if the OS could prewarm apps on the current device + */ +- (BOOL)isPrewarmAvailable { + return YES; +} + +/** + RC flag for dropping all app start events + */ +- (BOOL)isAppStartEnabled { + return [self.configurations prewarmDetectionMode] != PrewarmDetectionModeKeepNone; +} + +/** + RC flag for enabling prewarm-detection using ActivePrewarm environment variable + */ +- (BOOL)isActivePrewarmEnabled { + PrewarmDetectionMode mode = [self.configurations prewarmDetectionMode]; + return (mode == PrewarmDetectionModeActivePrewarm); +} + +/** + Checks if the current app start is a prewarmed app start + */ +- (BOOL)isApplicationPreWarmed { + if (![self isPrewarmAvailable]) { + return NO; + } + + BOOL isPrewarmed = NO; + + if (isActivePrewarm == YES) { + isPrewarmed = isPrewarmed || [self isActivePrewarmEnabled]; + [self.activeTrace incrementMetric:kFPRAppCounterNameActivePrewarm byInt:1]; + } else { + [self.activeTrace incrementMetric:kFPRAppCounterNameActivePrewarm byInt:0]; + } + + return isPrewarmed; +} + +/** + * This gets called whenever the app becomes active. A new trace will be created to track the active + * foreground session. Any background session trace that was running in the past will be stopped. + * + * @param notification Notification received during app launch. + */ +- (void)appDidBecomeActiveNotification:(NSNotification *)notification { + self.applicationState = FPRApplicationStateForeground; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + self.appStartTrace = [[FIRTrace alloc] initInternalTraceWithName:kFPRAppStartTraceName]; + [self.appStartTrace startWithStartTime:appStartTime]; + [self.appStartTrace startStageNamed:kFPRAppStartStageNameTimeToUI startTime:appStartTime]; + + // Start measuring time to first draw on the App start trace. + [self.appStartTrace startStageNamed:kFPRAppStartStageNameTimeToFirstDraw]; + }); + + // If ever the app start trace had it life in background stage, do not send the trace. + if (self.appStartTrace.backgroundTraceState != FPRTraceStateForegroundOnly) { + self.appStartTrace = nil; + } + + // Stop the active background session trace. + [self.backgroundSessionTrace stop]; + self.backgroundSessionTrace = nil; + + // Start foreground session trace. + FIRTrace *appTrace = + [[FIRTrace alloc] initInternalTraceWithName:kFPRAppTraceNameForegroundSession]; + [appTrace start]; + self.foregroundSessionTrace = appTrace; + + // Start measuring time to make the app interactive on the App start trace. + static BOOL TTIStageStarted = NO; + if (!TTIStageStarted) { + [self.appStartTrace startStageNamed:kFPRAppStartStageNameTimeToUserInteraction]; + TTIStageStarted = YES; + + // Assumption here is that - the app becomes interactive in the next runloop cycle. + // It is possible that the app does more things later, but for now we are not measuring that. + dispatch_async(dispatch_get_main_queue(), ^{ + NSTimeInterval startTimeSinceEpoch = [self.appStartTrace startTimeSinceEpoch]; + NSTimeInterval currentTimeSinceEpoch = [[NSDate date] timeIntervalSince1970]; + + // The below check is to account for 2 scenarios. + // 1. The app gets started in the background and might come to foreground a lot later. + // 2. The app is launched, but immediately backgrounded for some reason and the actual launch + // happens a lot later. + // Dropping the app start trace in such situations where the launch time is taking more than + // 60 minutes. This is an approximation, but a more agreeable timelimit for app start. + if ((currentTimeSinceEpoch - startTimeSinceEpoch < gAppStartMaxValidDuration) && + [self isAppStartEnabled] && ![self isApplicationPreWarmed]) { + [self.appStartTrace stop]; + } else { + [self.appStartTrace cancel]; + } + }); + } +} + +/** + * This gets called whenever the app resigns its active status. The currently active foreground + * session trace will be stopped and a background session trace will be started. + * + * @param notification Notification received during app resigning active status. + */ +- (void)appWillResignActiveNotification:(NSNotification *)notification { + // Dispatch the collected gauge metrics. + if (!self.appStartGaugeMetricDispatched) { + [[FPRGaugeManager sharedInstance] dispatchMetric:gAppStartCPUGaugeData]; + [[FPRGaugeManager sharedInstance] dispatchMetric:gAppStartMemoryGaugeData]; + self.appStartGaugeMetricDispatched = YES; + } + + self.applicationState = FPRApplicationStateBackground; + + // Stop foreground session trace. + [self.foregroundSessionTrace stop]; + self.foregroundSessionTrace = nil; + + // Start background session trace. + self.backgroundSessionTrace = + [[FIRTrace alloc] initInternalTraceWithName:kFPRAppTraceNameBackgroundSession]; + [self.backgroundSessionTrace start]; +} + +- (void)dealloc { + nw_path_monitor_cancel(self.monitor); + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h new file mode 100644 index 0000000..9cbb868 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h @@ -0,0 +1,117 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h" + +#import +#import +#import + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" + +@class UIViewController; + +NS_ASSUME_NONNULL_BEGIN + +/** Prefix string for screen traces. */ +FOUNDATION_EXTERN NSString *const kFPRPrefixForScreenTraceName; + +/** Counter name for frozen frames. */ +FOUNDATION_EXTERN NSString *const kFPRFrozenFrameCounterName; + +/** Counter name for slow frames. */ +FOUNDATION_EXTERN NSString *const kFPRSlowFrameCounterName; + +/** Counter name for total frames. */ +FOUNDATION_EXTERN NSString *const kFPRTotalFramesCounterName; + +/** Slow frame threshold (for time difference between current and previous frame render time) + * in sec. + */ +FOUNDATION_EXTERN CFTimeInterval const kFPRSlowFrameThreshold; + +/** Frozen frame threshold (for time difference between current and previous frame render time) + * in sec. + */ +FOUNDATION_EXTERN CFTimeInterval const kFPRFrozenFrameThreshold; + +@interface FPRScreenTraceTracker () + +/** A map table of that has the viewControllers as the keys and their associated trace as the value. + * The key is weakly retained and the value is strongly retained. + */ +@property(nonatomic) NSMapTable *activeScreenTraces; + +/** A list of all UIViewController instances that were visible before app was backgrounded. The + * viewControllers are reatined weakly. + */ +@property(nonatomic, nullable) NSPointerArray *previouslyVisibleViewControllers; + +/** Serial queue on which all operations that need to be thread safe in this class take place. */ +@property(nonatomic) dispatch_queue_t screenTraceTrackerSerialQueue; + +/** The display link that provides us with the frame rate data. */ +@property(nonatomic) CADisplayLink *displayLink; + +/** Dispatch group which allows us to make this class testable. Instead of waiting an arbitrary + * amount of time for an asynchronous task to finish before asserting its behavior, we can wait + * on this dispatch group to finish executing before testing the behavior of any asynchronous + * task. Consequently, all asynchronous tasks in this class should use this dispatch group. + */ +@property(nonatomic) dispatch_group_t screenTraceTrackerDispatchGroup; + +/** The frozen frames counter. */ +@property(atomic) int_fast64_t frozenFramesCount; + +/** The total frames counter. */ +@property(atomic) int_fast64_t totalFramesCount; + +/** The slow frames counter. */ +@property(atomic) int_fast64_t slowFramesCount; + +/** Handles the appDidBecomeActive notification. Restores the screen traces that were active before + * the app was backgrounded. + * + * @param notification The NSNotification object. + */ +- (void)appDidBecomeActiveNotification:(NSNotification *)notification; + +/** Handles the appWillResignActive notification. Saves the names of the screen traces that are + * currently active and stops all of them. + * + * @param notification The NSNotification object. + */ +- (void)appWillResignActiveNotification:(NSNotification *)notification; + +/** The method that is invoked by the CADisplayLink when a new frame is rendered. */ +- (void)displayLinkStep; + +/** Tells the screen trace tracker that the given viewController appeared. This should be called + * from the main thread. + * + * @param viewController The UIViewController instance that appeared. + */ +- (void)viewControllerDidAppear:(UIViewController *)viewController; + +/** Tells the screen trace tracker that the given viewController disappeared. This should be called + * from the main thread. + * + * @param viewController The UIViewController instance that disappeared. + */ +- (void)viewControllerDidDisappear:(id)viewController; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h new file mode 100644 index 0000000..dcfa382 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h @@ -0,0 +1,34 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This class manages all the screen traces. If initialized, it records the total frames, frozen + * frames and slow frames, and if it has been registered as a delegate of FIRAScreenViewReporter, + * it also automatically creates screen traces for each UIViewController. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRScreenTraceTracker : NSObject + +/** Singleton instance of FPRScreenTraceTracker. + * + * @return The shared instance of FPRScreenTraceTracker. + */ ++ (instancetype)sharedInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.m new file mode 100644 index 0000000..5137776 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.m @@ -0,0 +1,403 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h" +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h" + +#import +#import + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" + +NSString *const kFPRPrefixForScreenTraceName = @"_st_"; +NSString *const kFPRFrozenFrameCounterName = @"_fr_fzn"; +NSString *const kFPRSlowFrameCounterName = @"_fr_slo"; +NSString *const kFPRTotalFramesCounterName = @"_fr_tot"; + +// Note: This was previously 60 FPS, but that resulted in 90% + of all frames collected to be +// flagged as slow frames, and so the threshold for iOS is being changed to 59 FPS. +// TODO(b/73498642): Make these configurable. +CFTimeInterval const kFPRSlowFrameThreshold = 1.0 / 59.0; // Anything less than 59 FPS is slow. +CFTimeInterval const kFPRFrozenFrameThreshold = 700.0 / 1000.0; + +/** Constant that indicates an invalid time. */ +CFAbsoluteTime const kFPRInvalidTime = -1.0; + +/** Returns the class name without the prefixed module name present in Swift classes + * (e.g. MyModule.MyViewController -> MyViewController). + */ +static NSString *FPRUnprefixedClassName(Class theClass) { + NSString *className = NSStringFromClass(theClass); + NSRange periodRange = [className rangeOfString:@"." options:NSBackwardsSearch]; + if (periodRange.location == NSNotFound) { + return className; + } + return periodRange.location < className.length - 1 + ? [className substringFromIndex:periodRange.location + 1] + : className; +} + +/** Returns the name for the screen trace for a given UIViewController. It does the following: + * - Removes module name from swift classes - (e.g. MyModule.MyViewController -> MyViewController) + * - Prepends "_st_" to the class name + * - Truncates the length if it exceeds the maximum trace length. + * + * @param viewController The view controller whose screen trace name we want. Cannot be nil. + * @return An NSString containing the trace name, or a string containing an error if the + * class was nil. + */ +static NSString *FPRScreenTraceNameForViewController(UIViewController *viewController) { + NSString *unprefixedClassName = FPRUnprefixedClassName([viewController class]); + if (unprefixedClassName.length != 0) { + NSString *traceName = + [NSString stringWithFormat:@"%@%@", kFPRPrefixForScreenTraceName, unprefixedClassName]; + return traceName.length > kFPRMaxNameLength ? [traceName substringToIndex:kFPRMaxNameLength] + : traceName; + } else { + // This is unlikely, but might happen if there's a regression on iOS where the class name + // returned for a non-nil class is nil or empty. + return @"_st_ERROR_NIL_CLASS_NAME"; + } +} + +@implementation FPRScreenTraceTracker { + /** Instance variable storing the total frames observed so far. */ + atomic_int_fast64_t _totalFramesCount; + + /** Instance variable storing the slow frames observed so far. */ + atomic_int_fast64_t _slowFramesCount; + + /** Instance variable storing the frozen frames observed so far. */ + atomic_int_fast64_t _frozenFramesCount; +} + +@dynamic totalFramesCount; +@dynamic frozenFramesCount; +@dynamic slowFramesCount; + ++ (instancetype)sharedInstance { + static FPRScreenTraceTracker *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[self alloc] init]; + }); + return instance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + // Weakly retain viewController, use pointer hashing. + NSMapTableOptions keyOptions = NSMapTableWeakMemory | NSMapTableObjectPointerPersonality; + // Strongly retain the FIRTrace. + NSMapTableOptions valueOptions = NSMapTableStrongMemory; + _activeScreenTraces = [NSMapTable mapTableWithKeyOptions:keyOptions valueOptions:valueOptions]; + + _previouslyVisibleViewControllers = nil; // Will be set when there is data. + _screenTraceTrackerSerialQueue = + dispatch_queue_create("com.google.FPRScreenTraceTracker", DISPATCH_QUEUE_SERIAL); + _screenTraceTrackerDispatchGroup = dispatch_group_create(); + + atomic_store_explicit(&_totalFramesCount, 0, memory_order_relaxed); + atomic_store_explicit(&_frozenFramesCount, 0, memory_order_relaxed); + atomic_store_explicit(&_slowFramesCount, 0, memory_order_relaxed); + _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(displayLinkStep)]; + [_displayLink addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; + + // We don't receive background and foreground events from analytics and so we have to listen to + // them ourselves. + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appDidBecomeActiveNotification:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appWillResignActiveNotification:) + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; + } + return self; +} + +- (void)dealloc { + [_displayLink invalidate]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; +} + +- (void)appDidBecomeActiveNotification:(NSNotification *)notification { + // To get the most accurate numbers of total, frozen and slow frames, we need to capture them as + // soon as we're notified of an event. + int64_t currentTotalFrames = atomic_load_explicit(&_totalFramesCount, memory_order_relaxed); + int64_t currentFrozenFrames = atomic_load_explicit(&_frozenFramesCount, memory_order_relaxed); + int64_t currentSlowFrames = atomic_load_explicit(&_slowFramesCount, memory_order_relaxed); + + dispatch_group_async(self.screenTraceTrackerDispatchGroup, self.screenTraceTrackerSerialQueue, ^{ + for (id viewController in self.previouslyVisibleViewControllers) { + [self startScreenTraceForViewController:viewController + currentTotalFrames:currentTotalFrames + currentFrozenFrames:currentFrozenFrames + currentSlowFrames:currentSlowFrames]; + } + self.previouslyVisibleViewControllers = nil; + }); +} + +- (void)appWillResignActiveNotification:(NSNotification *)notification { + // To get the most accurate numbers of total, frozen and slow frames, we need to capture them as + // soon as we're notified of an event. + int64_t currentTotalFrames = atomic_load_explicit(&_totalFramesCount, memory_order_relaxed); + int64_t currentFrozenFrames = atomic_load_explicit(&_frozenFramesCount, memory_order_relaxed); + int64_t currentSlowFrames = atomic_load_explicit(&_slowFramesCount, memory_order_relaxed); + + dispatch_group_async(self.screenTraceTrackerDispatchGroup, self.screenTraceTrackerSerialQueue, ^{ + self.previouslyVisibleViewControllers = [NSPointerArray weakObjectsPointerArray]; + id visibleViewControllersEnumerator = [self.activeScreenTraces keyEnumerator]; + id visibleViewController = nil; + while (visibleViewController = [visibleViewControllersEnumerator nextObject]) { + [self.previouslyVisibleViewControllers addPointer:(__bridge void *)(visibleViewController)]; + } + + for (id visibleViewController in self.previouslyVisibleViewControllers) { + [self stopScreenTraceForViewController:visibleViewController + currentTotalFrames:currentTotalFrames + currentFrozenFrames:currentFrozenFrames + currentSlowFrames:currentSlowFrames]; + } + }); +} + +#pragma mark - Frozen, slow and good frames + +- (void)displayLinkStep { + static CFAbsoluteTime previousTimestamp = kFPRInvalidTime; + CFAbsoluteTime currentTimestamp = self.displayLink.timestamp; + RecordFrameType(currentTimestamp, previousTimestamp, &_slowFramesCount, &_frozenFramesCount, + &_totalFramesCount); + previousTimestamp = currentTimestamp; +} + +/** This function increments the relevant frame counters based on the current and previous + * timestamp provided by the displayLink. + * + * @param currentTimestamp The current timestamp of the displayLink. + * @param previousTimestamp The previous timestamp of the displayLink. + * @param slowFramesCounter The value of the slowFramesCount before this function was called. + * @param frozenFramesCounter The value of the frozenFramesCount before this function was called. + * @param totalFramesCounter The value of the totalFramesCount before this function was called. + */ +FOUNDATION_STATIC_INLINE +void RecordFrameType(CFAbsoluteTime currentTimestamp, + CFAbsoluteTime previousTimestamp, + atomic_int_fast64_t *slowFramesCounter, + atomic_int_fast64_t *frozenFramesCounter, + atomic_int_fast64_t *totalFramesCounter) { + CFTimeInterval frameDuration = currentTimestamp - previousTimestamp; + if (previousTimestamp == kFPRInvalidTime) { + return; + } + if (frameDuration > kFPRSlowFrameThreshold) { + atomic_fetch_add_explicit(slowFramesCounter, 1, memory_order_relaxed); + } + if (frameDuration > kFPRFrozenFrameThreshold) { + atomic_fetch_add_explicit(frozenFramesCounter, 1, memory_order_relaxed); + } + atomic_fetch_add_explicit(totalFramesCounter, 1, memory_order_relaxed); +} + +#pragma mark - Helper methods + +/** Starts a screen trace for the given UIViewController instance if it doesn't exist. This method + * does NOT ensure thread safety - the caller is responsible for making sure that this is invoked + * in a thread safe manner. + * + * @param viewController The UIViewController instance for which the trace is to be started. + * @param currentTotalFrames The value of the totalFramesCount before this method was called. + * @param currentFrozenFrames The value of the frozenFramesCount before this method was called. + * @param currentSlowFrames The value of the slowFramesCount before this method was called. + */ +- (void)startScreenTraceForViewController:(UIViewController *)viewController + currentTotalFrames:(int64_t)currentTotalFrames + currentFrozenFrames:(int64_t)currentFrozenFrames + currentSlowFrames:(int64_t)currentSlowFrames { + if (![self shouldCreateScreenTraceForViewController:viewController]) { + return; + } + + // If there's a trace for this viewController, don't do anything. + if (![self.activeScreenTraces objectForKey:viewController]) { + NSString *traceName = FPRScreenTraceNameForViewController(viewController); + FIRTrace *newTrace = [[FIRTrace alloc] initInternalTraceWithName:traceName]; + [newTrace start]; + [newTrace setIntValue:currentTotalFrames forMetric:kFPRTotalFramesCounterName]; + [newTrace setIntValue:currentFrozenFrames forMetric:kFPRFrozenFrameCounterName]; + [newTrace setIntValue:currentSlowFrames forMetric:kFPRSlowFrameCounterName]; + [self.activeScreenTraces setObject:newTrace forKey:viewController]; + } +} + +/** Stops a screen trace for the given UIViewController instance if it exist. This method does NOT + * ensure thread safety - the caller is responsible for making sure that this is invoked in a + * thread safe manner. + * + * @param viewController The UIViewController instance for which the trace is to be stopped. + * @param currentTotalFrames The value of the totalFramesCount before this method was called. + * @param currentFrozenFrames The value of the frozenFramesCount before this method was called. + * @param currentSlowFrames The value of the slowFramesCount before this method was called. + */ +- (void)stopScreenTraceForViewController:(UIViewController *)viewController + currentTotalFrames:(int64_t)currentTotalFrames + currentFrozenFrames:(int64_t)currentFrozenFrames + currentSlowFrames:(int64_t)currentSlowFrames { + FIRTrace *previousScreenTrace = [self.activeScreenTraces objectForKey:viewController]; + + // Get a diff between the counters now and what they were at trace start. + int64_t actualTotalFrames = + currentTotalFrames - [previousScreenTrace valueForIntMetric:kFPRTotalFramesCounterName]; + int64_t actualFrozenFrames = + currentFrozenFrames - [previousScreenTrace valueForIntMetric:kFPRFrozenFrameCounterName]; + int64_t actualSlowFrames = + currentSlowFrames - [previousScreenTrace valueForIntMetric:kFPRSlowFrameCounterName]; + + // Update the values in the trace. + if (actualTotalFrames != 0) { + [previousScreenTrace setIntValue:actualTotalFrames forMetric:kFPRTotalFramesCounterName]; + } else { + [previousScreenTrace deleteMetric:kFPRTotalFramesCounterName]; + } + + if (actualFrozenFrames != 0) { + [previousScreenTrace setIntValue:actualFrozenFrames forMetric:kFPRFrozenFrameCounterName]; + } else { + [previousScreenTrace deleteMetric:kFPRFrozenFrameCounterName]; + } + + if (actualSlowFrames != 0) { + [previousScreenTrace setIntValue:actualSlowFrames forMetric:kFPRSlowFrameCounterName]; + } else { + [previousScreenTrace deleteMetric:kFPRSlowFrameCounterName]; + } + + if (previousScreenTrace.numberOfCounters > 0) { + [previousScreenTrace stop]; + } else { + // The trace did not collect any data. Don't log it. + [previousScreenTrace cancel]; + } + [self.activeScreenTraces removeObjectForKey:viewController]; +} + +#pragma mark - Filtering for screen traces + +/** Determines whether to create a screen trace for the given UIViewController instance. + * + * @param viewController The UIViewController instance. + * @return YES if a screen trace should be created for the given UIViewController instance, + NO otherwise. + */ +- (BOOL)shouldCreateScreenTraceForViewController:(UIViewController *)viewController { + if (viewController == nil) { + return NO; + } + + // Ignore non-main bundle view controllers whose class or superclass is an internal iOS view + // controller. This is borrowed from the logic for tracking screens in Firebase Analytics. + NSBundle *bundle = [NSBundle bundleForClass:[viewController class]]; + if (bundle != [NSBundle mainBundle]) { + NSString *className = FPRUnprefixedClassName([viewController class]); + if ([className hasPrefix:@"_"]) { + return NO; + } + NSString *superClassName = FPRUnprefixedClassName([viewController superclass]); + if ([superClassName hasPrefix:@"_"]) { + return NO; + } + } + + // We are not creating screen traces for these view controllers because they're container view + // controllers. They always have a child view controller which will provide better context for a + // screen trace. We are however capturing traces if a developer subclasses these as there may be + // some context. Special case: We are not capturing screen traces for any input view + // controllers. + return !([viewController isMemberOfClass:[UINavigationController class]] || + [viewController isMemberOfClass:[UITabBarController class]] || + [viewController isMemberOfClass:[UISplitViewController class]] || + [viewController isMemberOfClass:[UIPageViewController class]] || + [viewController isKindOfClass:[UIInputViewController class]]); +} + +#pragma mark - Screen Traces swizzling hooks + +- (void)viewControllerDidAppear:(UIViewController *)viewController { + // To get the most accurate numbers of total, frozen and slow frames, we need to capture them as + // soon as we're notified of an event. + int64_t currentTotalFrames = atomic_load_explicit(&_totalFramesCount, memory_order_relaxed); + int64_t currentFrozenFrames = atomic_load_explicit(&_frozenFramesCount, memory_order_relaxed); + int64_t currentSlowFrames = atomic_load_explicit(&_slowFramesCount, memory_order_relaxed); + + dispatch_sync(self.screenTraceTrackerSerialQueue, ^{ + [self startScreenTraceForViewController:viewController + currentTotalFrames:currentTotalFrames + currentFrozenFrames:currentFrozenFrames + currentSlowFrames:currentSlowFrames]; + }); +} + +- (void)viewControllerDidDisappear:(id)viewController { + // To get the most accurate numbers of total, frozen and slow frames, we need to capture them as + // soon as we're notified of an event. + int64_t currentTotalFrames = atomic_load_explicit(&_totalFramesCount, memory_order_relaxed); + int64_t currentFrozenFrames = atomic_load_explicit(&_frozenFramesCount, memory_order_relaxed); + int64_t currentSlowFrames = atomic_load_explicit(&_slowFramesCount, memory_order_relaxed); + + dispatch_sync(self.screenTraceTrackerSerialQueue, ^{ + [self stopScreenTraceForViewController:viewController + currentTotalFrames:currentTotalFrames + currentFrozenFrames:currentFrozenFrames + currentSlowFrames:currentSlowFrames]; + }); +} + +#pragma mark - Test Helper Methods + +- (int_fast64_t)totalFramesCount { + return atomic_load_explicit(&_totalFramesCount, memory_order_relaxed); +} + +- (void)setTotalFramesCount:(int_fast64_t)count { + atomic_store_explicit(&_totalFramesCount, count, memory_order_relaxed); +} + +- (int_fast64_t)slowFramesCount { + return atomic_load_explicit(&_slowFramesCount, memory_order_relaxed); +} + +- (void)setSlowFramesCount:(int_fast64_t)count { + atomic_store_explicit(&_slowFramesCount, count, memory_order_relaxed); +} + +- (int_fast64_t)frozenFramesCount { + return atomic_load_explicit(&_frozenFramesCount, memory_order_relaxed); +} + +- (void)setFrozenFramesCount:(int_fast64_t)count { + atomic_store_explicit(&_frozenFramesCount, count, memory_order_relaxed); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h new file mode 100644 index 0000000..6a07a4d --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h @@ -0,0 +1,56 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/* List of options the session cares about. */ +typedef NS_OPTIONS(NSUInteger, FPRSessionOptions) { + FPRSessionOptionsNone = 0, + FPRSessionOptionsGauges = (1 << 0), + FPRSessionOptionsEvents = (1 << 1), +}; + +/* Class that contains the details of a session including the sessionId and session options. */ +@interface FPRSessionDetails : NSObject + +/* The sessionId with which the session details is initialized with. */ +@property(nonatomic, nonnull, readonly) NSString *sessionId; + +/* List of options enabled for the session. */ +@property(nonatomic, readonly) FPRSessionOptions options; + +/* Length of the session in minutes. */ +- (NSUInteger)sessionLengthInMinutesFromDate:(nonnull NSDate *)now; + +/** + * Creates an instance of FPRSessionDetails with the provided sessionId and the list of available + * options. + * + * @param sessionId Session Id for which the object is created. + * @param options Options enabled for the session. + * @return Instance of the object FPRSessionDetails. + */ +- (nonnull instancetype)initWithSessionId:(nonnull NSString *)sessionId + options:(FPRSessionOptions)options NS_DESIGNATED_INITIALIZER; + +- (nullable instancetype)init NS_UNAVAILABLE; + +/** + * Checks and returns if the session is verbose. + * + * @return Return YES if verbose, NO otherwise. + */ +- (BOOL)isVerbose; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.m new file mode 100644 index 0000000..4dfd279 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionDetails.m @@ -0,0 +1,59 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +@interface FPRSessionDetails () + +/** @brief Time at which the session was created. */ +@property(nonatomic) NSDate *sessionCreationTime; + +@end + +@implementation FPRSessionDetails + +- (instancetype)initWithSessionId:(NSString *)sessionId options:(FPRSessionOptions)options { + self = [super init]; + if (self) { + _sessionId = sessionId; + _options = options; + _sessionCreationTime = [NSDate date]; + } + return self; +} + +- (FPRSessionDetails *)copyWithZone:(NSZone *)zone { + FPRSessionDetails *detailsCopy = [[[self class] allocWithZone:zone] initWithSessionId:_sessionId + options:_options]; + detailsCopy.sessionCreationTime = _sessionCreationTime; + return detailsCopy; +} + +- (NSUInteger)sessionLengthInMinutesFromDate:(NSDate *)now { + NSTimeInterval sessionLengthInSeconds = ABS([now timeIntervalSinceDate:self.sessionCreationTime]); + return (NSUInteger)(sessionLengthInSeconds / 60); +} + +- (BOOL)isEqual:(FPRSessionDetails *)detailsObject { + if (self.sessionId == detailsObject.sessionId) { + return YES; + } + return NO; +} + +- (BOOL)isVerbose { + return (self.options > FPRSessionOptionsNone); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager+Private.h new file mode 100644 index 0000000..ac88eb6 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager+Private.h @@ -0,0 +1,49 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This extension should only be used for testing. */ +@interface FPRSessionManager () + +@property(nonatomic) FPRGaugeManager *gaugeManager; + +/** The current active session managed by the session manager. Modifiable for unit tests */ +@property(atomic, nullable, readwrite) FPRSessionDetails *sessionDetails; + +/** + * Creates an instance of FPRSesssionManager with the notification center provided. All the + * notifications from the session manager will sent using this notification center. + * + * @param gaugeManager Gauge manager used by the session manager to work with gauges. + * @param notificationCenter Notification center with which the session manager with be initialized. + * @return Returns an instance of the session manager. + */ +- (FPRSessionManager *)initWithGaugeManager:(FPRGaugeManager *)gaugeManager + notificationCenter:(NSNotificationCenter *)notificationCenter; + +/** + * Checks if the currently active session is beyond maximum allowed time for gauge-collection. If so + * stop gauges, else no-op. + */ +- (void)stopGaugesIfRunningTooLong; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.h new file mode 100644 index 0000000..bfffd7f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.h @@ -0,0 +1,54 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +/* Notification name when the session Id gets updated. */ +FOUNDATION_EXTERN NSString *_Nonnull const kFPRSessionIdUpdatedNotification; + +/* Notification name when the session Id gets updated. */ +FOUNDATION_EXTERN NSString *_Nonnull const kFPRSessionIdNotificationKey; + +/** This class manages the current active sessionId of the application and provides mechanism for + * propagating the session Id. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRSessionManager : NSObject + +/** The current active session managed by the session manager. */ +@property(atomic, readonly, nonnull) FPRSessionDetails *sessionDetails; + +/** + * The notification center managed by the session manager. All the notifications by the session + * manager will get broadcasted on this notification center. + */ +@property(nonatomic, readonly, nonnull) NSNotificationCenter *sessionNotificationCenter; + +/** + * The shared instance of Session Manager. + * + * @return The singleton instance. + */ ++ (nonnull FPRSessionManager *)sharedInstance; + +- (nullable instancetype)init NS_UNAVAILABLE; + +- (void)updateSessionId:(nonnull NSString *)sessionIdString; + +// Collects all the enabled gauge metrics once. +- (void)collectAllGaugesOnce; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.m new file mode 100644 index 0000000..bebfd3f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRSessionManager.m @@ -0,0 +1,113 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager+Private.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#import + +NSString *const kFPRSessionIdUpdatedNotification = @"kFPRSessionIdUpdatedNotification"; +NSString *const kFPRSessionIdNotificationKey = @"kFPRSessionIdNotificationKey"; + +@interface FPRSessionManager () + +@property(nonatomic, readwrite) NSNotificationCenter *sessionNotificationCenter; + +@end + +@implementation FPRSessionManager + ++ (FPRSessionManager *)sharedInstance { + static FPRSessionManager *instance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSNotificationCenter *notificationCenter = [[NSNotificationCenter alloc] init]; + FPRGaugeManager *gaugeManager = [FPRGaugeManager sharedInstance]; + instance = [[FPRSessionManager alloc] initWithGaugeManager:gaugeManager + notificationCenter:notificationCenter]; + }); + return instance; +} + +- (FPRSessionManager *)initWithGaugeManager:(FPRGaugeManager *)gaugeManager + notificationCenter:(NSNotificationCenter *)notificationCenter { + self = [super init]; + if (self) { + _gaugeManager = gaugeManager; + _sessionNotificationCenter = notificationCenter; + // Empty string is immediately replaced when FirebaseCore runs Fireperf's + // FIRComponentCreationBlock, because in the creation block we register Fireperf with Sessions, + // and the registration function immediately propagates real sessionId. This is at an early time + // in initialization that any trace is yet to be created. + _sessionDetails = [[FPRSessionDetails alloc] initWithSessionId:@"" + options:FPRSessionOptionsNone]; + } + return self; +} + +- (void)stopGaugesIfRunningTooLong { + NSUInteger maxSessionLength = [[FPRConfigurations sharedInstance] maxSessionLengthInMinutes]; + if ([self.sessionDetails sessionLengthInMinutesFromDate:[NSDate date]] >= maxSessionLength) { + [self.gaugeManager stopCollectingGauges:FPRGaugeCPU | FPRGaugeMemory]; + } +} + +/** + * Stops current session, and create a new session with new session id. + * + * @param sessionIdString New session id. + */ +- (void)updateSessionId:(NSString *)sessionIdString { + FPRSessionOptions sessionOptions = FPRSessionOptionsNone; + if ([self isGaugeCollectionEnabledForSessionId:sessionIdString]) { + [self.gaugeManager startCollectingGauges:FPRGaugeCPU | FPRGaugeMemory + forSessionId:sessionIdString]; + sessionOptions = FPRSessionOptionsGauges; + } else { + [self.gaugeManager stopCollectingGauges:FPRGaugeCPU | FPRGaugeMemory]; + } + + FPRLogDebug(kFPRSessionId, @"Session Id changed - %@", sessionIdString); + FPRSessionDetails *sessionInfo = [[FPRSessionDetails alloc] initWithSessionId:sessionIdString + options:sessionOptions]; + self.sessionDetails = sessionInfo; + NSMutableDictionary *userInfo = + [[NSMutableDictionary alloc] init]; + [userInfo setObject:sessionInfo forKey:kFPRSessionIdNotificationKey]; + [self.sessionNotificationCenter postNotificationName:kFPRSessionIdUpdatedNotification + object:self + userInfo:[userInfo copy]]; +} + +- (void)collectAllGaugesOnce { + [self.gaugeManager collectAllGauges]; +} + +/** + * Checks if the provided sessionId can have gauge data collection enabled. + * + * @param sessionId Session Id for which the check is done. + * @return YES if gauge collection is enabled, NO otherwise. + */ +- (BOOL)isGaugeCollectionEnabledForSessionId:(NSString *)sessionId { + float_t sessionSamplePercentage = [[FPRConfigurations sharedInstance] sessionsSamplingPercentage]; + double randomNumberBetween0And1 = ((double)arc4random() / UINT_MAX); + BOOL sessionsEnabled = randomNumberBetween0And1 * 100 < sessionSamplePercentage; + return sessionsEnabled; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h new file mode 100644 index 0000000..9353416 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h @@ -0,0 +1,42 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** Different background states of a trace. */ +typedef NS_ENUM(NSInteger, FPRTraceState) { + FPRTraceStateUnknown, + + /** Background only trace. */ + FPRTraceStateBackgroundOnly, + + /** Foreground only trace. */ + FPRTraceStateForegroundOnly, + + /** Background and foreground trace. */ + FPRTraceStateBackgroundAndForeground, +}; + +/** + * This class is used to track the app activity and track the background and foreground state of the + * object. This object will be used by a trace to determine its application state if the lifecycle + * of the trace is backgrounded, foregrounded or both. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRTraceBackgroundActivityTracker : NSObject + +/** Background state of the tracker. */ +@property(nonatomic, readonly) FPRTraceState traceBackgroundState; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m new file mode 100644 index 0000000..f7608fd --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.m @@ -0,0 +1,81 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h" + +#import +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" + +@interface FPRTraceBackgroundActivityTracker () + +@property(nonatomic, readwrite) FPRTraceState traceBackgroundState; + +@end + +@implementation FPRTraceBackgroundActivityTracker + +- (instancetype)init { + self = [super init]; + if (self) { + if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) { + _traceBackgroundState = FPRTraceStateBackgroundOnly; + } else { + _traceBackgroundState = FPRTraceStateForegroundOnly; + } + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidBecomeActive:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(applicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:[UIApplication sharedApplication]]; + } + return self; +} + +- (void)dealloc { + // Remove all the notification observers registered. + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +#pragma mark - UIApplicationDelegate events + +/** + * This gets called whenever the app becomes active. + * + * @param notification Notification received during app launch. + */ +- (void)applicationDidBecomeActive:(NSNotification *)notification { + if (_traceBackgroundState == FPRTraceStateBackgroundOnly) { + _traceBackgroundState = FPRTraceStateBackgroundAndForeground; + } +} + +/** + * This gets called whenever the app enters background. + * + * @param notification Notification received when the app enters background. + */ +- (void)applicationDidEnterBackground:(NSNotification *)notification { + if (_traceBackgroundState == FPRTraceStateForegroundOnly) { + _traceBackgroundState = FPRTraceStateBackgroundAndForeground; + } +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.h new file mode 100644 index 0000000..b6bfcb0 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.h @@ -0,0 +1,51 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** This class generated the console URLs for a project or a metric.*/ +@interface FPRConsoleURLGenerator : NSObject + +/** + * Generates the console URL for the dashboard page of the project. + * + * @param projectID The Firebase project ID. + * @param bundleID The bundle ID of this project. + * @return The console URL for the dashboard page. + */ ++ (NSString *)generateDashboardURLWithProjectID:(NSString *)projectID bundleID:(NSString *)bundleID; + +/** + * Generates the console URL for the custom trace page. + * + * @param projectID The Firebase project ID. + * @param bundleID The bundle ID of this project. + * @return The console URL for the custom trace page. + */ ++ (NSString *)generateCustomTraceURLWithProjectID:(NSString *)projectID + bundleID:(NSString *)bundleID + traceName:(NSString *)traceName; + +/** + * Generates the console URL for the screen trace page. + * + * @param projectID The Firebase project ID. + * @param bundleID The bundle ID of this project. + * @return The console URL for the custom trace page. + */ ++ (NSString *)generateScreenTraceURLWithProjectID:(NSString *)projectID + bundleID:(NSString *)bundleID + traceName:(NSString *)traceName; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.m new file mode 100644 index 0000000..6ae728f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.m @@ -0,0 +1,56 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.h" + +NSString *const URL_BASE_PATH = @"https://console.firebase.google.com"; +NSString *const UTM_MEDIUM = @"ios-ide"; +NSString *const UTM_SOURCE = @"perf-ios-sdk"; + +@implementation FPRConsoleURLGenerator + +/** This is a class method to generate the console URL for the project's dashboard page.*/ ++ (NSString *)generateDashboardURLWithProjectID:(NSString *)projectID + bundleID:(NSString *)bundleID { + NSString *rootUrl = [FPRConsoleURLGenerator getRootURLWithProjectID:projectID bundleID:bundleID]; + return [NSString + stringWithFormat:@"%@/trends?utm_source=%@&utm_medium=%@", rootUrl, UTM_SOURCE, UTM_MEDIUM]; +} + +/** This is a class method to generate the console URL for the custom trace.*/ ++ (NSString *)generateCustomTraceURLWithProjectID:(NSString *)projectID + bundleID:(NSString *)bundleID + traceName:(NSString *)traceName { + NSString *rootUrl = [FPRConsoleURLGenerator getRootURLWithProjectID:projectID bundleID:bundleID]; + return [NSString stringWithFormat:@"%@/troubleshooting/trace/" + @"DURATION_TRACE/%@?utm_source=%@&utm_medium=%@", + rootUrl, traceName, UTM_SOURCE, UTM_MEDIUM]; +} + +/** This is a class method to generate the console URL for the screen trace.*/ ++ (NSString *)generateScreenTraceURLWithProjectID:(NSString *)projectID + bundleID:(NSString *)bundleID + traceName:(NSString *)traceName { + NSString *rootUrl = [FPRConsoleURLGenerator getRootURLWithProjectID:projectID bundleID:bundleID]; + return [NSString stringWithFormat:@"%@/troubleshooting/trace/" + @"SCREEN_TRACE/%@?utm_source=%@&utm_medium=%@", + rootUrl, traceName, UTM_SOURCE, UTM_MEDIUM]; +} + +/** This is a class method to get the root URL for the console .*/ ++ (NSString *)getRootURLWithProjectID:(NSString *)projectID bundleID:(NSString *)bundleID { + return [NSString + stringWithFormat:@"%@/project/%@/performance/app/ios:%@", URL_BASE_PATH, projectID, bundleID]; +} +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.h new file mode 100644 index 0000000..a65e814 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.h @@ -0,0 +1,39 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +// SDK Version number. +FOUNDATION_EXTERN const char* const kFPRSDKVersion; + +// Prefix for internal naming of objects +FOUNDATION_EXTERN NSString* const kFPRInternalNamePrefix; + +// Max length for object names +FOUNDATION_EXTERN int const kFPRMaxNameLength; + +// Max URL length +FOUNDATION_EXTERN int const kFPRMaxURLLength; + +// Max length for attribute name. +FOUNDATION_EXTERN int const kFPRMaxAttributeNameLength; + +// Max length for attribute value. +FOUNDATION_EXTERN int const kFPRMaxAttributeValueLength; + +// Maximum number of global custom attributes. +FOUNDATION_EXTERN int const kFPRMaxGlobalCustomAttributesCount; + +// Maximum number of trace custom attributes. +FOUNDATION_EXTERN int const kFPRMaxTraceCustomAttributesCount; diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.m new file mode 100644 index 0000000..28218c7 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRConstants.m @@ -0,0 +1,43 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" + +// extract macro value into a C string +#define STR_FROM_MACRO(x) #x +#define STR(x) STR_FROM_MACRO(x) + +// SDK Version number. +const char *const kFPRSDKVersion = (const char *const)STR(FIRPerformance_LIB_VERSION); + +// Characters used prefix for internal naming of objects. +NSString *const kFPRInternalNamePrefix = @"_"; + +// Max length for object names +int const kFPRMaxNameLength = 100; + +// Max URL length. +int const kFPRMaxURLLength = 2000; + +// Max length for attribute name. +int const kFPRMaxAttributeNameLength = 40; + +// Max length for attribute value. +int const kFPRMaxAttributeValueLength = 100; + +// Maximum number of global custom attributes. +int const kFPRMaxGlobalCustomAttributesCount = 5; + +// Maximum number of trace custom attributes. +int const kFPRMaxTraceCustomAttributesCount = 5; diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDate.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDate.h new file mode 100644 index 0000000..a4b7258 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDate.h @@ -0,0 +1,35 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Definition of a date that is used internally. + */ +@protocol FPRDate + +/** Returns the current time. */ +- (NSDate *)now; + +/** + * Calculates the time difference between the provided date and returns the difference in seconds. + * + * @param date A date object used for reference. + * @return Difference in time between the current date and the provided date in seconds. If the + * current date is older than the provided date, the difference is returned in positive, else + * negative. + */ +- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)date; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.h new file mode 100644 index 0000000..0def288 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.h @@ -0,0 +1,60 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +/** Logs assert information. This shouldn't be called by anything except FPRAssert. + * + * @param object The object (or class) that is asserting. + * @param condition The condition that is being asserted to be true. + * @param func The value of the __func__ variable. + */ +FOUNDATION_EXTERN void __FPRAssert(id object, BOOL condition, const char *func); + +/** This protocol defines the selectors that are invoked when a diagnostics event occurs. */ +@protocol FPRDiagnosticsProtocol + +@optional + +/** Emits class-level diagnostic information. */ ++ (void)emitDiagnostics; + +/** Emits object-level diagnostic information. */ +- (void)emitDiagnostics; + +@end + +// Use this define in implementations of +/-emitDiagnostics. +#define EMIT_DIAGNOSTIC(...) FPRLogNotice(kFPRDiagnosticLog, __VA_ARGS__) + +// This assert adds additional functionality to the normal NSAssert, including printing out +// information when NSAsserts are stripped. A __builtin_expect is utilized to keep running speed +// as fast as possible. +#define FPRAssert(condition, ...) \ + { \ + do { \ + __FPRAssert(self, !!(condition), __func__); \ + NSAssert(condition, __VA_ARGS__); \ + } while (0); \ + } + +/** This class handles the control of diagnostics in the SDK. */ +@interface FPRDiagnostics : NSObject + +/** YES if diagnostics are enabled, NO otherwise. */ +@property(class, nonatomic, readonly, getter=isEnabled) BOOL enabled; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.m new file mode 100644 index 0000000..12439c6 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics.m @@ -0,0 +1,83 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Common/FPRDiagnostics_Private.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +void __FPRAssert(id object, BOOL condition, const char *func) { + static BOOL diagnosticsEnabled = NO; + static dispatch_once_t onceToken; + NSDictionary *environment = [NSProcessInfo processInfo].environment; + // Enable diagnostics when in test environment + if (environment[@"XCTestConfigurationFilePath"] != nil) { + diagnosticsEnabled = [FPRDiagnostics isEnabled]; + } else { + dispatch_once(&onceToken, ^{ + diagnosticsEnabled = [FPRDiagnostics isEnabled]; + }); + } + + if (__builtin_expect(!condition && diagnosticsEnabled, NO)) { + FPRLogError(kFPRDiagnosticFailure, @"Failure in %s, information follows:", func); + FPRLogNotice(kFPRDiagnosticLog, @"Stack for failure in %s:\n%@", func, + [NSThread callStackSymbols]); + if ([[object class] respondsToSelector:@selector(emitDiagnostics)]) { + [[object class] performSelector:@selector(emitDiagnostics) withObject:nil]; + } + if ([object respondsToSelector:@selector(emitDiagnostics)]) { + [object performSelector:@selector(emitDiagnostics) withObject:nil]; + } + FPRLogNotice(kFPRDiagnosticLog, @"End of diagnostics for %s failure.", func); + } +} + +@implementation FPRDiagnostics + +static FPRConfigurations *_configuration; + ++ (void)initialize { + _configuration = [FPRConfigurations sharedInstance]; +} + ++ (FPRConfigurations *)configuration { + return _configuration; +} + ++ (void)setConfiguration:(FPRConfigurations *)config { + _configuration = config; +} + ++ (BOOL)isEnabled { + // Check a soft-linked FIRCore class to see if this is running in the app store. + Class FIRAppEnvironmentUtil = NSClassFromString(@"FIRAppEnvironmentUtil"); + SEL isFromAppStore = NSSelectorFromString(@"isFromAppStore"); +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Warc-performSelector-leaks" + if (FIRAppEnvironmentUtil && [FIRAppEnvironmentUtil respondsToSelector:isFromAppStore] && + [FIRAppEnvironmentUtil performSelector:isFromAppStore]) { + return NO; + } +#pragma clang diagnostic pop + BOOL enabled = [FPRDiagnostics.configuration diagnosticsEnabled]; + if (enabled) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + FPRLogNotice(kFPRDiagnosticInfo, @"Firebase Performance Diagnostics have been enabled!"); + }); + } + return enabled; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics_Private.h new file mode 100644 index 0000000..287a309 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRDiagnostics_Private.h @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +/** + * Extension that is added on top of the class FPRDiagnostics to make the private properties + * visible between the implementation file and the unit tests. + */ +@interface FPRDiagnostics () + +/** FPRCongiguration to check if diagnostic is enabled. */ +@property(class, nonatomic, readwrite) FPRConfigurations *configuration; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.h new file mode 100644 index 0000000..d3a851a --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.h @@ -0,0 +1,22 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRDate.h" + +/** + * FPRPerfDate creates a date object that does time calculations. + */ +@interface FPRPerfDate : NSObject + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.m new file mode 100644 index 0000000..6d8659f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Common/FPRPerfDate.m @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Common/FPRPerfDate.h" + +@implementation FPRPerfDate + +- (NSDate *)now { + return [NSDate date]; +} + +- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)date { + return [self.now timeIntervalSinceDate:date]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h new file mode 100644 index 0000000..8053363 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GULUserDefaults; + +/** List of gauges the gauge manager controls. */ +typedef NS_OPTIONS(NSUInteger, FPRConfigurationSource) { + FPRConfigurationSourceNone = 0, + FPRConfigurationSourceRemoteConfig = (1 << 1), +}; + +/** This extension should only be used for testing. */ +@interface FPRConfigurations () + +/** @brief Different configuration sources managed by the object. */ +@property(nonatomic) FPRConfigurationSource sources; + +/** @brief Instance of remote config flags. */ +@property(nonatomic) FPRRemoteConfigFlags *remoteConfigFlags; + +/** @brief The class to use when FIRApp is referenced. */ +@property(nonatomic) Class FIRAppClass; + +/** @brief User defaults used for user preference config fetches . */ +@property(nonatomic) GULUserDefaults *userDefaults; + +/** @brief The main bundle identifier used by config system. */ +@property(nonatomic) NSString *mainBundleIdentifier; + +/** @brief The infoDictionary provided by the main bundle. */ +@property(nonatomic) NSDictionary *infoDictionary; + +/** @brief Configurations update queue. */ +@property(nonatomic) dispatch_queue_t updateQueue; + +/** + * Creates an instance of the FPRConfigurations class with the specified sources. + * + * @param source Source that needs to be enabled for fetching configurations. + * @return Instance of FPRConfiguration. + */ +- (instancetype)initWithSources:(FPRConfigurationSource)source NS_DESIGNATED_INITIALIZER; + +/** + * Returns the list of SDK versions that are disabled. SDK Versions are ';' separated. If no + * versions are disabled, an empty set is returned. + * + * @return The set of disabled SDK versions. + */ +- (nonnull NSSet *)sdkDisabledVersions; + +/** + * Resets this class by changing the onceToken back to 0, allowing a new singleton to be created, + * while the old one is dealloc'd. This should only be used for testing. + */ ++ (void)reset; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.h new file mode 100644 index 0000000..8756baf --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.h @@ -0,0 +1,212 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Different modes of prewarm-detection + * KeepNone = No app start events are allowed + * ActivePrewarm = Only detect prewarming using ActivePrewarm environment + * KeepAll = All app start events are allowed + */ +typedef NS_ENUM(NSInteger, PrewarmDetectionMode) { + PrewarmDetectionModeKeepNone = 0, + PrewarmDetectionModeActivePrewarm = 1, + PrewarmDetectionModeKeepAll = 2 +}; + +/** A typedef for ensuring that config names are one of the below specified strings. */ +typedef NSString* const FPRConfigName; + +/** + * Class that manages the configurations used by firebase performance SDK. This class abstracts the + * configuration flags from different configuration sources. + */ +@interface FPRConfigurations : NSObject + +/** Enables or disables performance data collection in the SDK. If the value is set to 'NO' none of + * the performance data will be sent to the server. Default is YES. */ +@property(nonatomic, getter=isDataCollectionEnabled) BOOL dataCollectionEnabled; + +/** The config KVC name string for the dataCollectionEnabled property. */ +FOUNDATION_EXTERN FPRConfigName kFPRConfigDataCollectionEnabled; + +/** Enables or disables instrumenting the app to collect performance data (like app start time, + * networking). Default is YES. */ +@property(nonatomic, getter=isInstrumentationEnabled) BOOL instrumentationEnabled; + +/** The config KVC name string for the instrumentationEnabled property. */ +FOUNDATION_EXTERN FPRConfigName kFPRConfigInstrumentationEnabled; + +/** Log source against which the Fireperf events are recorded. */ +@property(nonatomic, readonly) int logSource; + +/** Specifies if the SDK is enabled. */ +@property(nonatomic, readonly) BOOL sdkEnabled; + +/** Specifies if the diagnostic log messages should be enabled. */ +@property(nonatomic, readonly) BOOL diagnosticsEnabled; + +- (nullable instancetype)init NS_UNAVAILABLE; + +/** Singleton instance of FPRConfigurations. */ ++ (nullable instancetype)sharedInstance; + +/** + * Updates all the configurations flags relevant to Firebase Performance. + * + * This call blocks until the update is done. + */ +- (void)update; + +#pragma mark - Configuration fetcher methods. + +/** + * Returns the mode that prewarm-detection should drop events in. + * + * @see PrewarmDetectionMode + * @return filter mode of app start traces prewarm-detection + */ +- (PrewarmDetectionMode)prewarmDetectionMode; + +/** + * Returns the percentage of instances that would send trace events. Range [0-1]. + * + * @return The percentage of instances that would send trace events. + */ +- (float)logTraceSamplingRate; + +/** + * Returns the percentage of instances that would send network request events. Range [0-1]. + * + * @return The percentage of instances that would send network request events. + */ +- (float)logNetworkSamplingRate; + +/** + * Returns the foreground event count/burst size. This is the number of events that are allowed to + * flow in burst when the app is in foreground. + * + * @return The foreground event count as determined from configs. + */ +- (uint32_t)foregroundEventCount; + +/** + * Returns the foreground time limit to allow the foreground event count. This is specified in + * number of minutes. + * + * @return The foreground event time limit as determined from configs. + */ +- (uint32_t)foregroundEventTimeLimit; + +/** + * Returns the background event count/burst size. This is the number of events that are allowed to + * flow in burst when the app is in background. + * + * @return The background event count as determined from configs. + */ +- (uint32_t)backgroundEventCount; + +/** + * Returns the background time limit to allow the background event count. This is specified in + * number of minutes. + * + * @return The background event time limit as determined from configs. + */ +- (uint32_t)backgroundEventTimeLimit; + +/** + * Returns the foreground network event count/burst size. This is the number of network events that + * are allowed to flow in burst when the app is in foreground. + * + * @return The foreground network event count as determined from configs. + */ +- (uint32_t)foregroundNetworkEventCount; + +/** + * Returns the foreground time limit to allow the foreground network event count. This is specified + * in number of minutes. + * + * @return The foreground network event time limit as determined from configs. + */ +- (uint32_t)foregroundNetworkEventTimeLimit; + +/** + * Returns the background network event count/burst size. This is the number of network events that + * are allowed to flow in burst when the app is in background. + * + * @return The background network event count as determined from configs. + */ +- (uint32_t)backgroundNetworkEventCount; + +/** + * Returns the background time limit to allow the background network event count. This is specified + * in number of minutes. + * + * @return The background network event time limit as determined from configs. + */ +- (uint32_t)backgroundNetworkEventTimeLimit; + +/** + * Returns a float specifying the percentage of device instances on which session feature is + * enabled. Range [0-100]. + * + * @return The percentage of devices on which session feature should be enabled. + */ +- (float_t)sessionsSamplingPercentage; + +/** + * Returns the maximum length of a session in minutes. Default is 240 minutes. + * + * @return Maximum allowed length of the session in minutes. + */ +- (uint32_t)maxSessionLengthInMinutes; + +/** + * Returns the frequency at which the CPU usage metrics are to be collected when the app is in the + * foreground. Frequency is specified in milliseconds. A value of '0' means do not capture. + * + * @return An integer value specifying the frequency of capture in milliseconds. + */ +- (uint32_t)cpuSamplingFrequencyInForegroundInMS; + +/** + * Returns the frequency at which the CPU usage metrics are to be collected when the app is in the + * background. Frequency is specified in milliseconds. A value of '0' means do not capture. + * + * @return An integer value specifying the frequency of capture in milliseconds. + */ +- (uint32_t)cpuSamplingFrequencyInBackgroundInMS; + +/** + * Returns the frequency at which the memory usage metrics are to be collected when the app is in + * the foreground. Frequency is specified in milliseconds. A value of '0' means do not capture. + * + * @return An integer value specifying the frequency of capture in milliseconds. + */ +- (uint32_t)memorySamplingFrequencyInForegroundInMS; + +/** + * Returns the frequency at which the memory usage metrics are to be collected when the app is in + * the background. Frequency is specified in milliseconds. A value of '0' means do not capture. + * + * @return An integer value specifying the frequency of capture in milliseconds. + */ +- (uint32_t)memorySamplingFrequencyInBackgroundInMS; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.m new file mode 100644 index 0000000..9d498a5 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRConfigurations.m @@ -0,0 +1,488 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h" +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +FPRConfigName kFPRConfigDataCollectionEnabled = @"dataCollectionEnabled"; + +FPRConfigName kFPRConfigInstrumentationEnabled = @"instrumentationEnabled"; + +NSString *const kFPRConfigInstrumentationUserPreference = + @"com.firebase.performanceInsrumentationEnabled"; +NSString *const kFPRConfigInstrumentationPlistKey = @"firebase_performance_instrumentation_enabled"; + +NSString *const kFPRConfigCollectionUserPreference = @"com.firebase.performanceCollectionEnabled"; +NSString *const kFPRConfigCollectionPlistKey = @"firebase_performance_collection_enabled"; + +NSString *const kFPRDiagnosticsUserPreference = @"FPRDiagnosticsLocal"; +NSString *const kFPRDiagnosticsEnabledPlistKey = @"FPRDiagnosticsLocal"; + +NSString *const kFPRConfigCollectionDeactivationPlistKey = + @"firebase_performance_collection_deactivated"; + +NSString *const kFPRConfigLogSource = @"com.firebase.performanceLogSource"; + +@implementation FPRConfigurations + +static dispatch_once_t gSharedInstanceToken; + ++ (instancetype)sharedInstance { + static FPRConfigurations *instance = nil; + dispatch_once(&gSharedInstanceToken, ^{ + FPRConfigurationSource sources = FPRConfigurationSourceRemoteConfig; + instance = [[FPRConfigurations alloc] initWithSources:sources]; + }); + return instance; +} + ++ (void)reset { + // TODO(b/120032990): Reset the singletons that this singleton uses. + gSharedInstanceToken = 0; + [[GULUserDefaults standardUserDefaults] + removeObjectForKey:kFPRConfigInstrumentationUserPreference]; + [[GULUserDefaults standardUserDefaults] removeObjectForKey:kFPRConfigCollectionUserPreference]; +} + +- (instancetype)initWithSources:(FPRConfigurationSource)source { + self = [super init]; + if (self) { + _sources = source; + [self setupRemoteConfigFlags]; + + // Register for notifications to update configs. + [self registerForNotifications]; + + self.FIRAppClass = [FIRApp class]; + self.userDefaults = [GULUserDefaults standardUserDefaults]; + self.infoDictionary = [NSBundle mainBundle].infoDictionary; + self.mainBundleIdentifier = [NSBundle mainBundle].bundleIdentifier; + self.updateQueue = dispatch_queue_create("com.google.perf.configUpdate", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (void)registerForNotifications { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(update) + name:UIApplicationDidBecomeActiveNotification + object:nil]; +} + +/** Searches the main bundle and the bundle from bundleForClass: info dictionaries for the key and + * returns the first result. + * + * @param key The key to search the info dictionaries for. + * @return The first object found in the info dictionary of the main bundle and bundleForClass:. + */ +- (nullable id)objectForInfoDictionaryKey:(NSString *)key { + // If the config infoDictionary has been set to a new dictionary, only use the original dictionary + // instead of the new dictionary. + if (self.infoDictionary != [NSBundle mainBundle].infoDictionary) { + return self.infoDictionary[key]; // nullable. + } + NSArray *bundles = @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; + for (NSBundle *bundle in bundles) { + id object = [bundle objectForInfoDictionaryKey:key]; + if (object) { + return object; // nonnull. + } + } + return nil; +} + +- (void)update { + dispatch_async(self.updateQueue, ^{ + if (!self.remoteConfigFlags) { + [self setupRemoteConfigFlags]; + } + [self.remoteConfigFlags update]; + }); +} + +/** + * Sets up the remote config flags instance based on 3 different factors: + * 1. Is the firebase app configured? + * 2. Is the remote config source enabled? + * 3. If the Remote Config flags instance exists already? + */ +- (void)setupRemoteConfigFlags { + if (!self.remoteConfigFlags && [self.FIRAppClass isDefaultAppConfigured] && + (self.sources & FPRConfigurationSourceRemoteConfig) == FPRConfigurationSourceRemoteConfig) { + self.remoteConfigFlags = [FPRRemoteConfigFlags sharedInstance]; + } +} + +#pragma mark - Overridden Properties + +- (void)setDataCollectionEnabled:(BOOL)dataCollectionEnabled { + [self.userDefaults setBool:dataCollectionEnabled forKey:kFPRConfigCollectionUserPreference]; +} + +// The data collection flag is determined by this order: +// 1. A plist flag for permanently disabling data collection +// 2. The runtime flag (GULUserDefaults) +// 3. A plist flag for enabling/disabling (overridable) +// 4. The global data collection switch from Core. +- (BOOL)isDataCollectionEnabled { + /** + * Perf only works with the default app, so validate it exists then use the value from the global + * data collection from the default app as the base value if no other values are set. + */ + if (![self.FIRAppClass isDefaultAppConfigured]) { + return NO; + } + + BOOL dataCollectionPreference = [self.FIRAppClass defaultApp].isDataCollectionDefaultEnabled; + + // Check if data collection is permanently disabled by plist. If so, disable data collection. + id dataCollectionDeactivationObject = + [self objectForInfoDictionaryKey:kFPRConfigCollectionDeactivationPlistKey]; + if (dataCollectionDeactivationObject) { + BOOL dataCollectionDeactivated = [dataCollectionDeactivationObject boolValue]; + if (dataCollectionDeactivated) { + return NO; + } + } + /** + * Check if the performance collection preference key is available in GULUserDefaults. + * If it exists - Just honor that and return that value. + * If it does not exist - Check if firebase_performance_collection_enabled exists in Info.plist. + * If it exists - honor that and return that value. + * If not - return YES stating performance collection is enabled. + */ + id dataCollectionPreferenceObject = + [self.userDefaults objectForKey:kFPRConfigCollectionUserPreference]; + if (dataCollectionPreferenceObject) { + dataCollectionPreference = [dataCollectionPreferenceObject boolValue]; + } else { + dataCollectionPreferenceObject = [self objectForInfoDictionaryKey:kFPRConfigCollectionPlistKey]; + if (dataCollectionPreferenceObject) { + dataCollectionPreference = [dataCollectionPreferenceObject boolValue]; + } + } + + return dataCollectionPreference; +} + +- (void)setInstrumentationEnabled:(BOOL)instrumentationEnabled { + [self.userDefaults setBool:instrumentationEnabled forKey:kFPRConfigInstrumentationUserPreference]; +} + +- (BOOL)isInstrumentationEnabled { + BOOL instrumentationPreference = YES; + + id instrumentationPreferenceObject = + [self.userDefaults objectForKey:kFPRConfigInstrumentationUserPreference]; + + /** + * Check if the performance instrumentation preference key is available in GULUserDefaults. + * If it exists - Just honor that and return that value. + * If not - Check if firebase_performance_instrumentation_enabled exists in Info.plist. + * If it exists - honor that and return that value. + * If not - return YES stating performance instrumentation is enabled. + */ + if (instrumentationPreferenceObject) { + instrumentationPreference = [instrumentationPreferenceObject boolValue]; + } else { + instrumentationPreferenceObject = + [self objectForInfoDictionaryKey:kFPRConfigInstrumentationPlistKey]; + if (instrumentationPreferenceObject) { + instrumentationPreference = [instrumentationPreferenceObject boolValue]; + } + } + + return instrumentationPreference; +} + +#pragma mark - Fireperf SDK configurations. + +- (BOOL)sdkEnabled { + BOOL enabled = YES; + if (self.remoteConfigFlags) { + enabled = [self.remoteConfigFlags performanceSDKEnabledWithDefaultValue:enabled]; + } + + // Check if the current version is one of the disabled versions. + if ([[self sdkDisabledVersions] containsObject:[NSString stringWithUTF8String:kFPRSDKVersion]]) { + enabled = NO; + } + + // If there is a plist override, honor that value. + // NOTE: PList override should ideally be used only for tests and not for production. + id plistObject = [self objectForInfoDictionaryKey:@"firebase_performance_sdk_enabled"]; + if (plistObject) { + enabled = [plistObject boolValue]; + } + + return enabled; +} + +- (BOOL)diagnosticsEnabled { + BOOL enabled = NO; + + /** + * Check if the diagnostics preference key is available in GULUserDefaults. + * If it exists - Just honor that and return that value. + * If not - Check if firebase_performance_instrumentation_enabled exists in Info.plist. + * If it exists - honor that and return that value. + * If not - return NO stating diagnostics is disabled. + */ + id diagnosticsEnabledPreferenceObject = + [self.userDefaults objectForKey:kFPRDiagnosticsUserPreference]; + + if (diagnosticsEnabledPreferenceObject) { + enabled = [diagnosticsEnabledPreferenceObject boolValue]; + } else { + id diagnosticsEnabledObject = [self objectForInfoDictionaryKey:kFPRDiagnosticsEnabledPlistKey]; + if (diagnosticsEnabledObject) { + enabled = [diagnosticsEnabledObject boolValue]; + } + } + + return enabled; +} + +- (NSSet *)sdkDisabledVersions { + NSMutableSet *disabledVersions = [[NSMutableSet alloc] init]; + + if (self.remoteConfigFlags) { + NSSet *sdkDisabledVersions = + [self.remoteConfigFlags sdkDisabledVersionsWithDefaultValue:[disabledVersions copy]]; + if (sdkDisabledVersions.count > 0) { + [disabledVersions addObjectsFromArray:[sdkDisabledVersions allObjects]]; + } + } + + return [disabledVersions copy]; +} + +- (int)logSource { + /** + * Order of preference of returning the log source. + * If it is an autopush build (based on environment variable), always return + * LogRequest_LogSource_FireperfAutopush (461). If there is a recent value of remote config fetch, + * honor that value. If logSource cached value (GULUserDefaults value) exists, honor that. + * Fallback to the default value LogRequest_LogSource_Fireperf (462). + */ + int logSource = 462; + + NSDictionary *environment = [NSProcessInfo processInfo].environment; + if (environment[@"FPR_AUTOPUSH_ENV"] != nil && + [environment[@"FPR_AUTOPUSH_ENV"] isEqualToString:@"1"]) { + logSource = 461; + } else { + if (self.remoteConfigFlags) { + logSource = [self.remoteConfigFlags logSourceWithDefaultValue:462]; + } + } + + return logSource; +} + +- (PrewarmDetectionMode)prewarmDetectionMode { + PrewarmDetectionMode mode = PrewarmDetectionModeActivePrewarm; + if (self.remoteConfigFlags) { + mode = [self.remoteConfigFlags getIntValueForFlag:@"fpr_prewarm_detection" + defaultValue:(int)mode]; + } + return mode; +} + +#pragma mark - Log sampling configurations. + +- (float)logTraceSamplingRate { + float samplingRate = 1.0f; + if (self.remoteConfigFlags) { + float rcSamplingRate = [self.remoteConfigFlags traceSamplingRateWithDefaultValue:samplingRate]; + if (rcSamplingRate >= 0) { + samplingRate = rcSamplingRate; + } + } + return samplingRate; +} + +- (float)logNetworkSamplingRate { + float samplingRate = 1.0f; + if (self.remoteConfigFlags) { + float rcSamplingRate = + [self.remoteConfigFlags networkRequestSamplingRateWithDefaultValue:samplingRate]; + if (rcSamplingRate >= 0) { + samplingRate = rcSamplingRate; + } + } + return samplingRate; +} + +#pragma mark - Traces rate limiting configurations. + +- (uint32_t)foregroundEventCount { + uint32_t eventCount = 300; + if (self.remoteConfigFlags) { + eventCount = + [self.remoteConfigFlags rateLimitTraceCountInForegroundWithDefaultValue:eventCount]; + } + return eventCount; +} + +- (uint32_t)foregroundEventTimeLimit { + uint32_t timeLimit = 600; + if (self.remoteConfigFlags) { + timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit]; + } + + uint32_t timeLimitInMinutes = timeLimit / 60; + return timeLimitInMinutes; +} + +- (uint32_t)backgroundEventCount { + uint32_t eventCount = 30; + if (self.remoteConfigFlags) { + eventCount = + [self.remoteConfigFlags rateLimitTraceCountInBackgroundWithDefaultValue:eventCount]; + } + return eventCount; +} + +- (uint32_t)backgroundEventTimeLimit { + uint32_t timeLimit = 600; + if (self.remoteConfigFlags) { + timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit]; + } + + uint32_t timeLimitInMinutes = timeLimit / 60; + return timeLimitInMinutes; +} + +#pragma mark - Network requests rate limiting configurations. + +- (uint32_t)foregroundNetworkEventCount { + uint32_t eventCount = 700; + if (self.remoteConfigFlags) { + eventCount = [self.remoteConfigFlags + rateLimitNetworkRequestCountInForegroundWithDefaultValue:eventCount]; + } + return eventCount; +} + +- (uint32_t)foregroundNetworkEventTimeLimit { + uint32_t timeLimit = 600; + if (self.remoteConfigFlags) { + timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit]; + } + + uint32_t timeLimitInMinutes = timeLimit / 60; + return timeLimitInMinutes; +} + +- (uint32_t)backgroundNetworkEventCount { + uint32_t eventCount = 70; + if (self.remoteConfigFlags) { + eventCount = [self.remoteConfigFlags + rateLimitNetworkRequestCountInBackgroundWithDefaultValue:eventCount]; + } + return eventCount; +} + +- (uint32_t)backgroundNetworkEventTimeLimit { + uint32_t timeLimit = 600; + if (self.remoteConfigFlags) { + timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit]; + } + + uint32_t timeLimitInMinutes = timeLimit / 60; + return timeLimitInMinutes; +} + +#pragma mark - Sessions feature related configurations. + +- (float_t)sessionsSamplingPercentage { + float samplingPercentage = 1.0f; // One Percent. + if (self.remoteConfigFlags) { + float rcSamplingRate = + [self.remoteConfigFlags sessionSamplingRateWithDefaultValue:(samplingPercentage / 100)]; + if (rcSamplingRate >= 0) { + samplingPercentage = rcSamplingRate * 100; + } + } + + id plistObject = [self objectForInfoDictionaryKey:@"sessionsSamplingPercentage"]; + if (plistObject) { + samplingPercentage = [plistObject floatValue]; + } + return samplingPercentage; +} + +- (uint32_t)maxSessionLengthInMinutes { + uint32_t sessionLengthInMinutes = 240; + if (self.remoteConfigFlags) { + sessionLengthInMinutes = + [self.remoteConfigFlags sessionMaxDurationWithDefaultValue:sessionLengthInMinutes]; + } + + // If the session max length gets set to 0, default it to 240 minutes. + if (sessionLengthInMinutes == 0) { + return 240; + } + return sessionLengthInMinutes; +} + +- (uint32_t)cpuSamplingFrequencyInForegroundInMS { + uint32_t samplingFrequency = 100; + if (self.remoteConfigFlags) { + samplingFrequency = [self.remoteConfigFlags + sessionGaugeCPUCaptureFrequencyInForegroundWithDefaultValue:samplingFrequency]; + } + return samplingFrequency; +} + +- (uint32_t)cpuSamplingFrequencyInBackgroundInMS { + uint32_t samplingFrequency = 0; + if (self.remoteConfigFlags) { + samplingFrequency = [self.remoteConfigFlags + sessionGaugeCPUCaptureFrequencyInBackgroundWithDefaultValue:samplingFrequency]; + } + return samplingFrequency; +} + +- (uint32_t)memorySamplingFrequencyInForegroundInMS { + uint32_t samplingFrequency = 100; + if (self.remoteConfigFlags) { + samplingFrequency = [self.remoteConfigFlags + sessionGaugeMemoryCaptureFrequencyInForegroundWithDefaultValue:samplingFrequency]; + } + return samplingFrequency; +} + +- (uint32_t)memorySamplingFrequencyInBackgroundInMS { + uint32_t samplingFrequency = 0; + if (self.remoteConfigFlags) { + samplingFrequency = [self.remoteConfigFlags + sessionGaugeMemoryCaptureFrequencyInBackgroundWithDefaultValue:samplingFrequency]; + } + return samplingFrequency; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h new file mode 100644 index 0000000..9279d45 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h @@ -0,0 +1,114 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h" + +#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h" + +NS_ASSUME_NONNULL_BEGIN + +@class GULUserDefaults; + +static NSString *const kFPRConfigPrefix = @"com.fireperf"; + +/** Interval at which the configurations can be fetched. Specified in seconds. */ +static NSInteger const kFPRConfigFetchIntervalInSeconds = 12 * 60 * 60; + +/** Interval after which the configurations can be fetched. Specified in seconds. */ +static NSInteger const kFPRMinAppStartConfigFetchDelayInSeconds = 5; + +/** This extension should only be used for testing. */ +@interface FPRRemoteConfigFlags () + +/** @brief Instance of remote config used for firebase performance namespace. */ +@property(nonatomic) FIRRemoteConfig *fprRemoteConfig; + +/** @brief Last activated time of the configurations. */ +@property(atomic, nullable) NSDate *lastFetchedTime; + +/** @brief User defaults used for caching. */ +@property(nonatomic) GULUserDefaults *userDefaults; + +/** @brief Last activated time of the configurations. */ +@property(nonatomic) NSDate *applicationStartTime; + +/** @brief Number of seconds delayed until the first config is made during app start. */ +@property(nonatomic) NSTimeInterval appStartConfigFetchDelayInSeconds; + +/** @brief Status of the last remote config fetch. */ +@property(nonatomic) FIRRemoteConfigFetchStatus lastFetchStatus; + +/** + * Creates an instance of FPRRemoteConfigFlags. + * + * @param config RemoteConfig object to be used for configuration management. + * @return Instance of remote config. + */ +- (instancetype)initWithRemoteConfig:(FIRRemoteConfig *)config NS_DESIGNATED_INITIALIZER; + +#pragma mark - Config fetch methods + +/** + * Gets and returns the string value for the provided remote config flag. If there are no values + * returned from remote config, default value will be returned. + * @param flagName Name of the flag for which the value needs to be fetched from RC. + * @param defaultValue Default value that will be returned if no value is fetched from RC. + * + * @return string value for the flag from RC if available. Default value, otherwise. + */ +- (NSString *)getStringValueForFlag:(NSString *)flagName defaultValue:(NSString *)defaultValue; + +/** + * Gets and returns the int value for the provided remote config flag. If there are no values + * returned from remote config, default value will be returned. + * @param flagName Name of the flag for which the value needs to be fetched from RC. + * @param defaultValue Default value that will be returned if no value is fetched from RC. + * + * @return Int value for the flag from RC if available. Default value, otherwise. + */ +- (int)getIntValueForFlag:(NSString *)flagName defaultValue:(int)defaultValue; + +/** + * Gets and returns the float value for the provided remote config flag. If there are no values + * returned from remote config, default value will be returned. + * @param flagName Name of the flag for which the value needs to be fetched from RC. + * @param defaultValue Default value that will be returned if no value is fetched from RC. + * + * @return Float value for the flag from RC if available. Default value, otherwise. + */ +- (float)getFloatValueForFlag:(NSString *)flagName defaultValue:(float)defaultValue; + +/** + * Gets and returns the boolean value for the provided remote config flag. If there are no values + * returned from remote config, default value will be returned. + * @param flagName Name of the flag for which the value needs to be fetched from RC. + * @param defaultValue Default value that will be returned if no value is fetched from RC. + * + * @return Bool value for the flag from RC if available. Default value, otherwise. + */ +- (BOOL)getBoolValueForFlag:(NSString *)flagName defaultValue:(BOOL)defaultValue; + +/** + * Caches the remote config values. + */ +- (void)cacheConfigValues; + +/** + * Reset (Clears) all the remote config keys and values that were cached. + */ +- (void)resetCache; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h new file mode 100644 index 0000000..4900ebe --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h @@ -0,0 +1,203 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * Configuration flags retrieved from Firebase Remote Configuration. + */ +@interface FPRRemoteConfigFlags : NSObject + +/** + * The name of the name space for which the remote config flags are fetched. + */ +@property(nonatomic, readonly, nonnull) NSString *remoteConfigNamespace; + +#pragma mark - Instance methods + +- (nullable instancetype)init NS_UNAVAILABLE; + +/** Singleton instance of Firebase Remote Configuration flags. */ ++ (nullable instancetype)sharedInstance; + +/** + * Initiate a fetch of the flags from Firebase Remote Configuration and updates the configurations + * at the end of the fetch. + * + * @note This method is throttled to initiate a fetch once in 12 hours. So, calling this method does + * not guarantee a fetch from Firebase Remote Config. + */ +- (void)update; + +#pragma mark - General configs. + +/** + * Returns if performance SDK is enabled. + * Name in remote config: "fpr_enabled". + * + * @param sdkEnabled Default value to be returned if values does not exist in remote config. + * @return Specifies if SDK should be enabled or not. + */ +- (BOOL)performanceSDKEnabledWithDefaultValue:(BOOL)sdkEnabled; + +/** + * Returns set of versions on which SDK is disabled. + * Name in remote config: "fpr_disabled_ios_versions". + * + * @param sdkVersions Default value to be returned if values does not exist in remote config. + * @return SDK versions list where the SDK has to be disabled. + */ +- (nullable NSSet *)sdkDisabledVersionsWithDefaultValue: + (nullable NSSet *)sdkVersions; + +/** + * Returns the log source against which the events will be recorded. + * Name in remote config: "fpr_log_source" + * + * @param logSource Default value to be returned if values does not exist in remote config. + * @return Log source towards which the events would be logged. + */ +- (int)logSourceWithDefaultValue:(int)logSource; + +#pragma mark - Rate limiting related configs. + +/** + * Returns the time limit for which the event are measured against. Measured in seconds. + * Name in remote config: "fpr_rl_time_limit_sec" + * + * @param durationInSeconds Default value to be returned if values does not exist in remote config. + * @return Time limit used for rate limiting in seconds. + */ +- (int)rateLimitTimeDurationWithDefaultValue:(int)durationInSeconds; + +/** + * Returns the number of trace events that are allowed when the app is in foreground. + * Name in remote config: "fpr_rl_trace_event_count_fg" + * + * @param eventCount Default value to be returned if values does not exist in remote config. + * @return Trace count limit when the app is in foreground. + */ +- (int)rateLimitTraceCountInForegroundWithDefaultValue:(int)eventCount; + +/** + * Returns the number of trace events that are allowed when the app is in background. + * Name in remote config: "fpr_rl_trace_event_count_bg" + * + * @param eventCount Default value to be returned if values does not exist in remote config. + * @return Trace count limit when the app is in background. + */ +- (int)rateLimitTraceCountInBackgroundWithDefaultValue:(int)eventCount; + +/** + * Returns the number of network trace events that are allowed when the app is in foreground. + * Name in remote config: "fpr_rl_network_request_event_count_fg" + * + * @param eventCount Default value to be returned if values does not exist in remote config. + * @return Network request count limit when the app is in foreground. + */ +- (int)rateLimitNetworkRequestCountInForegroundWithDefaultValue:(int)eventCount; + +/** + * Returns the number of network trace events that are allowed when the app is in background. + * Name in remote config: "fpr_rl_network_request_event_count_bg" + * + * @param eventCount Default value to be returned if values does not exist in remote config. + * @return Network request count limit when the app is in background. + */ +- (int)rateLimitNetworkRequestCountInBackgroundWithDefaultValue:(int)eventCount; + +#pragma mark - Sampling related configs. + +/** + * Returns the sampling rate for traces. A value of 1 means all the events must be sent to the + * backend. A value of 0 means, no data must be sent. Range [0-1]. A value of -1 means the value is + * not found. + * Name in remote config: "fpr_vc_trace_sampling_rate" + * + * @param samplingRate Default value to be returned if values does not exist in remote config. + * @return Sampling rate used for the number of traces. + */ +- (float)traceSamplingRateWithDefaultValue:(float)samplingRate; + +/** + * Returns the sampling rate for network requests. A value of 1 means all the events must be sent to + * the backend. A value of 0 means, no data must be sent. Range [0-1]. A value of -1 means the value + * is not found. + * Name in remote config: "fpr_vc_network_request_sampling_rate" + * + * @param samplingRate Default value to be returned if values does not exist in remote config. + * @return Sampling rate used for the number of network request traces. + */ +- (float)networkRequestSamplingRateWithDefaultValue:(float)samplingRate; + +#pragma mark - Session related configs. + +/** + * Returns the sampling rate for sessions. A value of 1 means all the events must be sent to the + * backend. A value of 0 means, no data must be sent. Range [0-1]. A value of -1 means the value is + * not found. + * Name in remote config: "fpr_vc_session_sampling_rate" + * + * @param samplingRate Default value to be returned if values does not exist in remote config. + * @return Session sampling rate used for the number of sessions generated. + */ +- (float)sessionSamplingRateWithDefaultValue:(float)samplingRate; + +/** + * Returns the frequency at which CPU usage is measured when the app is in foreground. Measured in + * milliseconds. Name in remote config: "fpr_session_gauge_cpu_capture_frequency_fg_ms" + * + * @param defaultFrequency Default value to be returned if values does not exist in remote config. + * @return Frequency at which CPU information is captured when app is in foreground. + */ +- (int)sessionGaugeCPUCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency; + +/** + * Returns the frequency at which CPU usage is measured when the app is in background. Measured in + * milliseconds. Name in remote config: "fpr_session_gauge_cpu_capture_frequency_bg_ms" + * + * @param defaultFrequency Default value to be returned if values does not exist in remote config. + * @return Frequency at which CPU information is captured when app is in background. + */ +- (int)sessionGaugeCPUCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency; + +/** + * Returns the frequency at which memory usage is measured when the app is in foreground. Measured + * in milliseconds. Name in remote config: "fpr_session_gauge_memory_capture_frequency_fg_ms" + * + * @param defaultFrequency Default value to be returned if values does not exist in remote config. + * @return Frequency at which memory information is captured when app is in foreground. + */ +- (int)sessionGaugeMemoryCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency; + +/** + * Returns the frequency at which memory usage is measured when the app is in background. Measured + * in milliseconds. Name in remote config: "fpr_session_gauge_memory_capture_frequency_bg_ms" + * + * @param defaultFrequency Default value to be returned if values does not exist in remote config. + * @return Frequency at which memory information is captured when app is in background. + */ +- (int)sessionGaugeMemoryCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency; + +/** + * Returns the maximum allowed duration for the length of a session. Measured in minutes. + * Name in remote config: "fpr_session_max_duration_min" + * + * @param maxDurationInMinutes Default value to be returned if values does not exist in remote + * config. + * @return Duration for which a sessions can be active. + */ +- (int)sessionMaxDurationWithDefaultValue:(int)maxDurationInMinutes; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.m new file mode 100644 index 0000000..86f1280 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.m @@ -0,0 +1,346 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h" +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h" + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +#define ONE_DAY_SECONDS 24 * 60 * 60 + +static NSDate *FPRAppStartTime = nil; + +typedef NS_ENUM(NSInteger, FPRConfigValueType) { + // Config value type String. + FPRConfigValueTypeString, + // Config value type Bool. + FPRConfigValueTypeBool, + // Config value type Integer. + FPRConfigValueTypeInteger, + // Config value type Float. + FPRConfigValueTypeFloat, +}; + +@interface FPRRemoteConfigFlags () + +/** @brief Represents if a fetch is currently in progress. */ +@property(atomic) BOOL fetchInProgress; + +/** @brief Dictionary of different config keys and value types. */ +@property(nonatomic) NSDictionary *configKeys; + +/** @brief Last time the configs were cached. */ +@property(nonatomic) NSDate *lastCachedTime; + +@end + +@implementation FPRRemoteConfigFlags + ++ (void)load { + FPRAppStartTime = [NSDate date]; +} + ++ (nullable instancetype)sharedInstance { + static FPRRemoteConfigFlags *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + FIRRemoteConfig *rc = [FIRRemoteConfig remoteConfigWithFIRNamespace:@"fireperf" + app:[FIRApp defaultApp]]; + instance = [[FPRRemoteConfigFlags alloc] initWithRemoteConfig:rc]; + }); + return instance; +} + +- (instancetype)initWithRemoteConfig:(FIRRemoteConfig *)config { + self = [super init]; + if (self) { + _fprRemoteConfig = config; + _userDefaults = [FPRConfigurations sharedInstance].userDefaults; + self.fetchInProgress = NO; + + // Set the overall delay to 5+random(25) making the config fetch delay at a max of 30 seconds + self.applicationStartTime = FPRAppStartTime; + self.appStartConfigFetchDelayInSeconds = + kFPRMinAppStartConfigFetchDelayInSeconds + arc4random_uniform(25); + + NSMutableDictionary *keysToCache = + [[NSMutableDictionary alloc] init]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_log_source"]; + [keysToCache setObject:@(FPRConfigValueTypeBool) forKey:@"fpr_enabled"]; + [keysToCache setObject:@(FPRConfigValueTypeString) forKey:@"fpr_disabled_ios_versions"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_time_limit_sec"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_trace_event_count_fg"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_trace_event_count_bg"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_rl_network_request_event_count_fg"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_rl_network_request_event_count_bg"]; + [keysToCache setObject:@(FPRConfigValueTypeFloat) forKey:@"fpr_vc_trace_sampling_rate"]; + [keysToCache setObject:@(FPRConfigValueTypeFloat) + forKey:@"fpr_vc_network_request_sampling_rate"]; + [keysToCache setObject:@(FPRConfigValueTypeFloat) forKey:@"fpr_vc_session_sampling_rate"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_session_gauge_cpu_capture_frequency_fg_ms"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_session_gauge_cpu_capture_frequency_bg_ms"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_session_gauge_memory_capture_frequency_fg_ms"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) + forKey:@"fpr_session_gauge_memory_capture_frequency_bg_ms"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_session_max_duration_min"]; + [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_prewarm_detection"]; + self.configKeys = [keysToCache copy]; + + [self update]; + } + return self; +} + +- (void)update { + // If a fetch is already happening, do not attempt a fetch. + if (self.fetchInProgress) { + return; + } + + NSTimeInterval timeIntervalSinceLastFetch = + [self.fprRemoteConfig.lastFetchTime timeIntervalSinceNow]; + NSTimeInterval timeSinceAppStart = [self.applicationStartTime timeIntervalSinceNow]; + if ((ABS(timeSinceAppStart) > self.appStartConfigFetchDelayInSeconds) && + (!self.fprRemoteConfig.lastFetchTime || + ABS(timeIntervalSinceLastFetch) > kFPRConfigFetchIntervalInSeconds)) { + self.fetchInProgress = YES; + [self.fprRemoteConfig + fetchAndActivateWithCompletionHandler:^(FIRRemoteConfigFetchAndActivateStatus status, + NSError *_Nullable error) { + self.lastFetchStatus = self.fprRemoteConfig.lastFetchStatus; + if (status == FIRRemoteConfigFetchAndActivateStatusError) { + FPRLogError(kFPRConfigurationFetchFailure, @"Unable to fetch configurations."); + } else { + self.lastFetchedTime = self.fprRemoteConfig.lastFetchTime; + // If a fetch was successful, + // 1. Clear the old cache + [self resetCache]; + // 2. Cache the new config values + [self cacheConfigValues]; + } + self.fetchInProgress = NO; + }]; + } else if (self.fprRemoteConfig.lastFetchTime) { + // Update the last fetched time to know that remote config fetch has happened in the past. + self.lastFetchedTime = self.fprRemoteConfig.lastFetchTime; + } +} + +#pragma mark - Util methods. + +- (void)resetCache { + [self.configKeys + enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *valueType, BOOL *stop) { + NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, key]; + [self.userDefaults removeObjectForKey:cacheKey]; + }]; +} + +- (void)cacheConfigValues { + [self.configKeys + enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *valueType, BOOL *stop) { + FIRRemoteConfigValue *rcValue = [self.fprRemoteConfig configValueForKey:key]; + + // Cache only values that comes from remote. + if (rcValue != nil && rcValue.source == FIRRemoteConfigSourceRemote) { + FPRConfigValueType configValueType = [valueType integerValue]; + NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, key]; + + if (configValueType == FPRConfigValueTypeInteger) { + NSInteger integerValue = [[rcValue numberValue] integerValue]; + [self.userDefaults setInteger:integerValue forKey:cacheKey]; + } else if (configValueType == FPRConfigValueTypeFloat) { + float floatValue = [[rcValue numberValue] floatValue]; + [self.userDefaults setFloat:floatValue forKey:cacheKey]; + } else if (configValueType == FPRConfigValueTypeBool) { + BOOL boolValue = [rcValue boolValue]; + [self.userDefaults setBool:boolValue forKey:cacheKey]; + } else if (configValueType == FPRConfigValueTypeString) { + NSString *stringValue = [rcValue stringValue]; + [self.userDefaults setObject:stringValue forKey:cacheKey]; + } + + self.lastCachedTime = [NSDate date]; + } + }]; +} + +- (id)cachedValueForConfigFlag:(NSString *)configFlag { + // If the cached value is too old, return nil. + if (ABS([self.lastFetchedTime timeIntervalSinceNow]) > 7 * ONE_DAY_SECONDS) { + return nil; + } + + NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, configFlag]; + id cachedValueObject = [self.userDefaults objectForKey:cacheKey]; + return cachedValueObject; +} + +#pragma mark - Config value fetch methods. + +- (NSString *)getStringValueForFlag:(NSString *)flagName defaultValue:(NSString *)defaultValue { + id cachedValueObject = [self cachedValueForConfigFlag:flagName]; + if ([cachedValueObject isKindOfClass:[NSString class]]) { + return (NSString *)cachedValueObject; + } + + return defaultValue; +} + +- (int)getIntValueForFlag:(NSString *)flagName defaultValue:(int)defaultValue { + id cachedValueObject = [self cachedValueForConfigFlag:flagName]; + if (cachedValueObject) { + return [cachedValueObject intValue]; + } + + return defaultValue; +} + +- (float)getFloatValueForFlag:(NSString *)flagName defaultValue:(float)defaultValue { + id cachedValueObject = [self cachedValueForConfigFlag:flagName]; + if (cachedValueObject) { + return [cachedValueObject floatValue]; + } + + return defaultValue; +} + +- (BOOL)getBoolValueForFlag:(NSString *)flagName defaultValue:(BOOL)defaultValue { + id cachedValueObject = [self cachedValueForConfigFlag:flagName]; + if (cachedValueObject) { + return [cachedValueObject boolValue]; + } + + return defaultValue; +} + +#pragma mark - Configuration methods. + +- (int)logSourceWithDefaultValue:(int)logSource { + return [self getIntValueForFlag:@"fpr_log_source" defaultValue:logSource]; +} + +- (BOOL)performanceSDKEnabledWithDefaultValue:(BOOL)sdkEnabled { + /* Order of preference: + * 1. If remote config fetch was a failure, return NO. + * 2. If the fetch was successful, but RC does not have the value (not a remote value), + * return YES. + * 3. Else, use the value from RC. + */ + + if (self.lastFetchStatus == FIRRemoteConfigFetchStatusFailure) { + return NO; + } + + return [self getBoolValueForFlag:@"fpr_enabled" defaultValue:sdkEnabled]; +} + +- (NSSet *)sdkDisabledVersionsWithDefaultValue:(NSSet *)sdkVersions { + NSMutableSet *disabledVersions = [[NSMutableSet alloc] init]; + + NSString *sdkVersionsString = [[self getStringValueForFlag:@"fpr_disabled_ios_versions" + defaultValue:@""] + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + if (sdkVersionsString.length > 0) { + NSArray *sdkVersionStrings = [sdkVersionsString componentsSeparatedByString:@";"]; + for (NSString *sdkVersionString in sdkVersionStrings) { + NSString *trimmedString = [sdkVersionString + stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + if (trimmedString.length > 0) { + [disabledVersions addObject:trimmedString]; + } + } + } else { + return sdkVersions; + } + + return [disabledVersions copy]; +} + +#pragma mark - Rate limiting flags + +- (int)rateLimitTimeDurationWithDefaultValue:(int)durationInSeconds { + return [self getIntValueForFlag:@"fpr_rl_time_limit_sec" defaultValue:durationInSeconds]; +} + +- (int)rateLimitTraceCountInForegroundWithDefaultValue:(int)eventCount { + return [self getIntValueForFlag:@"fpr_rl_trace_event_count_fg" defaultValue:eventCount]; +} + +- (int)rateLimitTraceCountInBackgroundWithDefaultValue:(int)eventCount { + return [self getIntValueForFlag:@"fpr_rl_trace_event_count_bg" defaultValue:eventCount]; +} + +- (int)rateLimitNetworkRequestCountInForegroundWithDefaultValue:(int)eventCount { + return [self getIntValueForFlag:@"fpr_rl_network_request_event_count_fg" defaultValue:eventCount]; +} + +- (int)rateLimitNetworkRequestCountInBackgroundWithDefaultValue:(int)eventCount { + return [self getIntValueForFlag:@"fpr_rl_network_request_event_count_bg" defaultValue:eventCount]; +} + +#pragma mark - Sampling flags + +- (float)traceSamplingRateWithDefaultValue:(float)samplingRate { + return [self getFloatValueForFlag:@"fpr_vc_trace_sampling_rate" defaultValue:samplingRate]; +} + +- (float)networkRequestSamplingRateWithDefaultValue:(float)samplingRate { + return [self getFloatValueForFlag:@"fpr_vc_network_request_sampling_rate" + defaultValue:samplingRate]; +} + +#pragma mark - Session flags + +- (float)sessionSamplingRateWithDefaultValue:(float)samplingRate { + return [self getFloatValueForFlag:@"fpr_vc_session_sampling_rate" defaultValue:samplingRate]; +} + +- (int)sessionGaugeCPUCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency { + return [self getIntValueForFlag:@"fpr_session_gauge_cpu_capture_frequency_fg_ms" + defaultValue:defaultFrequency]; +} + +- (int)sessionGaugeCPUCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency { + return [self getIntValueForFlag:@"fpr_session_gauge_cpu_capture_frequency_bg_ms" + defaultValue:defaultFrequency]; +} + +- (int)sessionGaugeMemoryCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency { + return [self getIntValueForFlag:@"fpr_session_gauge_memory_capture_frequency_fg_ms" + defaultValue:defaultFrequency]; +} + +- (int)sessionGaugeMemoryCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency { + return [self getIntValueForFlag:@"fpr_session_gauge_memory_capture_frequency_bg_ms" + defaultValue:defaultFrequency]; +} + +- (int)sessionMaxDurationWithDefaultValue:(int)maxDurationInMinutes { + return [self getIntValueForFlag:@"fpr_session_max_duration_min" + defaultValue:maxDurationInMinutes]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance+Internal.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance+Internal.h new file mode 100644 index 0000000..539df9a --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance+Internal.h @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h" +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformanceAttributable.h" + +/** + * Extension that is added on top of the class FIRPerformance to make certain methods used + * internally within the SDK, but not public facing. A category could be ideal, but Firebase + * recommends not using categories as that mandates including -ObjC flag for build which is an extra + * step for the developer. + */ + +@interface FIRPerformance (Attributable) + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance.m new file mode 100644 index 0000000..25fbe5c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance.m @@ -0,0 +1,156 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h" +#import "FirebasePerformance/Sources/FIRPerformance+Internal.h" +#import "FirebasePerformance/Sources/FIRPerformance_Private.h" + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRClient+Private.h" +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/FPRDataUtils.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" + +static NSString *const kFirebasePerfErrorDomain = @"com.firebase.perf"; + +@implementation FIRPerformance + +#pragma mark - Public methods + ++ (instancetype)sharedInstance { + static FIRPerformance *firebasePerformance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + firebasePerformance = [[FIRPerformance alloc] init]; + }); + return firebasePerformance; +} + ++ (FIRTrace *)startTraceWithName:(NSString *)name { + FIRTrace *trace = [[self sharedInstance] traceWithName:name]; + [trace start]; + return trace; +} + +- (FIRTrace *)traceWithName:(NSString *)name { + if (![self isPerfConfigured]) { + FPRLogError(kFPRTraceNotCreated, @"Failed creating trace %@. Firebase is not configured.", + name); + [NSException raise:kFirebasePerfErrorDomain + format:@"The default Firebase app has not yet been configured. Add " + @"`FirebaseApp.configure()` to your application initialization."]; + return nil; + } + FIRTrace *trace = [[FIRTrace alloc] initWithName:name]; + return trace; +} + +/** + * Checks if the SDK has been successfully configured. + * + * @return YES if SDK is configured successfully, otherwise NO. + */ +- (BOOL)isPerfConfigured { + return self.fprClient.isConfigured; +} + +#pragma mark - Internal methods + +- (instancetype)init { + self = [super init]; + if (self) { + _customAttributes = [[NSMutableDictionary alloc] init]; + _customAttributesSerialQueue = + dispatch_queue_create("com.google.perf.customAttributes", DISPATCH_QUEUE_SERIAL); + _fprClient = [FPRClient sharedInstance]; + } + return self; +} + +- (BOOL)isDataCollectionEnabled { + return [FPRConfigurations sharedInstance].isDataCollectionEnabled; +} + +- (void)setDataCollectionEnabled:(BOOL)dataCollectionEnabled { + [[FPRConfigurations sharedInstance] setDataCollectionEnabled:dataCollectionEnabled]; +} + +- (BOOL)isInstrumentationEnabled { + return self.fprClient.isSwizzled || [FPRConfigurations sharedInstance].isInstrumentationEnabled; +} + +- (void)setInstrumentationEnabled:(BOOL)instrumentationEnabled { + [[FPRConfigurations sharedInstance] setInstrumentationEnabled:instrumentationEnabled]; + if (instrumentationEnabled) { + [self.fprClient checkAndStartInstrumentation]; + } else { + if (self.fprClient.isSwizzled) { + FPRLogError(kFPRInstrumentationDisabledAfterConfigure, + @"Failed to disable instrumentation because Firebase Performance has already " + @"been configured. It will be disabled when the app restarts."); + } + } +} + +#pragma mark - Custom attributes related methods + +- (NSDictionary *)attributes { + return [self.customAttributes copy]; +} + +- (void)setValue:(NSString *)value forAttribute:(nonnull NSString *)attribute { + NSString *validatedName = FPRReservableAttributeName(attribute); + NSString *validatedValue = FPRValidatedAttributeValue(value); + + BOOL canAddAttribute = YES; + if (validatedName == nil) { + FPRLogError(kFPRAttributeNoName, + @"Failed to initialize because of a nil or zero length attribute name."); + canAddAttribute = NO; + } + + if (validatedValue == nil) { + FPRLogError(kFPRAttributeNoValue, + @"Failed to initialize because of a nil or zero length attribute value."); + canAddAttribute = NO; + } + + if (self.customAttributes.allKeys.count >= kFPRMaxGlobalCustomAttributesCount) { + FPRLogError(kFPRMaxAttributesReached, + @"Only %d attributes allowed. Already reached maximum attribute count.", + kFPRMaxGlobalCustomAttributesCount); + canAddAttribute = NO; + } + + if (canAddAttribute) { + // Ensure concurrency during update of attributes. + dispatch_sync(self.customAttributesSerialQueue, ^{ + self.customAttributes[validatedName] = validatedValue; + }); + } +} + +- (NSString *)valueForAttribute:(NSString *)attribute { + // TODO(b/175053654): Should this be happening on the serial queue for thread safety? + return self.customAttributes[attribute]; +} + +- (void)removeAttribute:(NSString *)attribute { + [self.customAttributes removeObjectForKey:attribute]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance_Private.h new file mode 100644 index 0000000..423ceb8 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FIRPerformance_Private.h @@ -0,0 +1,33 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h" + +/** + * Extension that is added on top of the class FIRPerformances to make the private properties + * visible between the implementation file and the unit tests. + */ +@interface FIRPerformance () + +/** Custom attribute managed internally. */ +@property(nonatomic) NSMutableDictionary *customAttributes; + +/** Serial queue to manage mutation of attributes. */ +@property(nonatomic, readwrite) dispatch_queue_t customAttributesSerialQueue; + +/** Client object used for checking the status of the performance SDK before generating events. */ +@property(nonatomic, readwrite) FPRClient *fprClient; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient+Private.h new file mode 100644 index 0000000..7b57497 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient+Private.h @@ -0,0 +1,75 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +@class FPRGDTLogger; +@class FPRConfigurations; +@class FIRInstallations; + +/// Protocol to define the Firebase performance provider for the component framework. +@protocol FIRPerformanceProvider + +@end + +/** + * Extension that is added on top of the class FPRClient to make the private properties visible + * between the implementation file and the unit tests. + */ +@interface FPRClient () + +@property(nonatomic, getter=isConfigured, readwrite) BOOL configured; + +/** GDT Logger to transmit Fireperf events to Google Data Transport. */ +@property(nonatomic) FPRGDTLogger *gdtLogger; + +/** The queue group all FPRClient work will run on. Used for testing only. */ +@property(nonatomic, readonly) dispatch_group_t eventsQueueGroup; + +/** Serial queue used for processing events. */ +@property(nonatomic, readonly) dispatch_queue_t eventsQueue; + +/** Firebase Remote Configuration object for FPRClient. */ +@property(nonatomic) FPRConfigurations *configuration; + +/** Firebase Installations object for FPRClient. */ +@property(nonatomic) FIRInstallations *installations; + +/** The Firebase Project ID of the project. */ +@property(nonatomic, readonly) NSString *projectID; + +/** The bundle ID of the project*/ +@property(nonatomic, readonly) NSString *bundleID; +/** + * Determines the log directory path in the caches directory. + * + * @return The directory in which Clearcut logs are stored. + */ ++ (NSString *)logDirectoryPath; + +/** + * Cleans up the log directory path in the cache directory created for Clearcut logs storage. + * + * @remark This method (cleanup logic) should stay for a while until all of our apps have migrated + * to a version which includes this logic. + */ ++ (void)cleanupClearcutCacheDirectory; + +/** Performs post processing and logs a firebase_perf_v1_PerfMetric object to Google Data Transport. + * @param event Reference to a firebase_perf_v1_PerfMetric proto object. + */ +- (void)processAndLogEvent:(firebase_perf_v1_PerfMetric)event; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.h new file mode 100644 index 0000000..c51a1a9 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.h @@ -0,0 +1,85 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h" + +#import "FirebasePerformance/Sources/FPRConfiguration.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +/** NSError codes for FPRClient related errors */ +typedef NS_ENUM(NSInteger, FPRClientErrorCode) { + // Generic Error. + FPRClientErrorCodeUnknown, + + // Error starting the client. + FPRClientErrorCodeStartupError +}; + +/** This class is not exposed to the public and internally provides the primary entry point into + * the Firebase Performance module's functionality. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRClient : NSObject + +/** YES if SDK is configured, otherwise NO. */ +@property(nonatomic, getter=isConfigured, readonly) BOOL configured; + +/** YES if methods have been swizzled, NO otherwise. */ +@property(nonatomic, getter=isSwizzled) BOOL swizzled; + +/** Accesses the singleton instance. All Firebase Performance methods should be managed via this + * shared instance. + * @return Reference to the shared object if successful; nil if not. + */ ++ (nonnull FPRClient *)sharedInstance; + +/** Enables performance reporting. This installs auto instrumentation and configures metric + * uploading. + * + * @param config Configures perf reporting behavior. + * @param error Populated with an NSError instance on failure. + * @return YES if successful; NO if not. + */ +- (BOOL)startWithConfiguration:(nonnull FPRConfiguration *)config + error:(NSError *__autoreleasing _Nullable *_Nullable)error; + +/** Logs a trace event. + * + * @param trace Trace event that needs to be logged to Google Data Transport. + */ +- (void)logTrace:(nonnull FIRTrace *)trace; + +/** Logs a network trace event. + * + * @param trace Network trace event that needs to be logged to Google Data Transport. + */ +- (void)logNetworkTrace:(nonnull FPRNetworkTrace *)trace; + +/** Logs a gauge metric event. + * + * @param gaugeData Gauge metric event that needs to be logged to Google Data Transport. + * @param sessionId SessionID with which the gauge data will be logged. + */ +- (void)logGaugeMetric:(nonnull NSArray *)gaugeData forSessionId:(nonnull NSString *)sessionId; + +/** Checks if the instrumentation of the app is enabled. If enabled, setup the instrumentation. */ +- (void)checkAndStartInstrumentation; + +/** Unswizzles any existing methods that have been instrumented and stops automatic instrumentation + * for all future app starts unless explicitly enabled. + */ +- (void)disableInstrumentation; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.m new file mode 100644 index 0000000..e701130 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRClient.m @@ -0,0 +1,370 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/FPRClient+Private.h" + +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h" +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker.h" +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager+Private.h" +#import "FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h" +#import "FirebasePerformance/Sources/Common/FPRConsoleURLGenerator.h" +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/FPRNanoPbUtils.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogger.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h" + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +@import FirebaseSessions; + +@interface FPRClient () + +/** The original configuration object used to initialize the client. */ +@property(nonatomic, strong) FPRConfiguration *config; + +/** The object that manages all automatic class instrumentation. */ +@property(nonatomic) FPRInstrumentation *instrumentation; + +@end + +@implementation FPRClient + ++ (void)load { + [FIRApp registerInternalLibrary:[FPRClient class] + withName:@"fire-perf" + withVersion:[NSString stringWithUTF8String:kFPRSDKVersion]]; + [FIRSessionsDependencies addDependencyWithName:FIRSessionsSubscriberNamePerformance]; +} + +#pragma mark - Component registration system + ++ (nonnull NSArray *)componentsToRegister { + FIRComponentCreationBlock creationBlock = + ^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + if (!container.app.isDefaultApp) { + return nil; + } + + id sessions = FIR_COMPONENT(FIRSessionsProvider, container); + + NSString *appName = container.app.name; + FIRApp *app = [FIRApp appNamed:appName]; + FIROptions *options = app.options; + NSError *error = nil; + + // Based on the environment variable SDK decides if events are dispatched to Autopush or Prod. + // By default, events are sent to Prod. + BOOL useAutoPush = NO; + NSDictionary *environment = [NSProcessInfo processInfo].environment; + if (environment[@"FPR_AUTOPUSH_ENV"] != nil && + [environment[@"FPR_AUTOPUSH_ENV"] isEqualToString:@"1"]) { + useAutoPush = YES; + } + + FPRConfiguration *configuration = [FPRConfiguration configurationWithAppID:options.googleAppID + APIKey:options.APIKey + autoPush:useAutoPush]; + if (![[self sharedInstance] startWithConfiguration:configuration error:&error]) { + FPRLogError(kFPRClientInitialize, @"Failed to initialize the client with error: %@.", error); + } + + if (sessions) { + FPRLogDebug(kFPRClientInitialize, @"Registering Sessions SDK subscription for session data"); + + // Subscription should be made after the first call to [FPRClient sharedInstance] where + // _configuration is initialized so that the sessions SDK can immediately get the data + // collection state. + [sessions registerWithSubscriber:[self sharedInstance]]; + } + + *isCacheable = YES; + + return [self sharedInstance]; + }; + + FIRComponent *component = + [FIRComponent componentWithProtocol:@protocol(FIRPerformanceProvider) + instantiationTiming:FIRInstantiationTimingEagerInDefaultApp + creationBlock:creationBlock]; + + return @[ component ]; +} + ++ (FPRClient *)sharedInstance { + static FPRClient *sharedInstance = nil; + static dispatch_once_t token; + dispatch_once(&token, ^{ + sharedInstance = [[FPRClient alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _instrumentation = [[FPRInstrumentation alloc] init]; + _swizzled = NO; + _eventsQueue = dispatch_queue_create("com.google.perf.FPREventsQueue", DISPATCH_QUEUE_SERIAL); + _eventsQueueGroup = dispatch_group_create(); + _configuration = [FPRConfigurations sharedInstance]; + _projectID = [FIROptions defaultOptions].projectID; + _bundleID = [FIROptions defaultOptions].bundleID; + } + return self; +} + +- (BOOL)startWithConfiguration:(FPRConfiguration *)config error:(NSError *__autoreleasing *)error { + self.config = config; + NSInteger logSource = [self.configuration logSource]; + + dispatch_group_async(self.eventsQueueGroup, self.eventsQueue, ^{ + // Create the Logger for the Perf SDK events to be sent to Google Data Transport. + self.gdtLogger = [[FPRGDTLogger alloc] initWithLogSource:logSource]; + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + // Create telephony network information object ahead of time to avoid runtime delays. + FPRNetworkInfo(); +#endif + + // Update the configuration flags. + [self.configuration update]; + + [FPRClient cleanupClearcutCacheDirectory]; + }); + + // Set up instrumentation. + [self checkAndStartInstrumentation]; + + self.configured = YES; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + FPRLogInfo(kFPRClientInitialize, + @"Firebase Performance Monitoring is successfully initialized! In a minute, visit " + @"the Firebase console to view your data: %@", + [FPRConsoleURLGenerator generateDashboardURLWithProjectID:self.projectID + bundleID:self.bundleID]); + }); + + return YES; +} + +- (void)checkAndStartInstrumentation { + BOOL instrumentationEnabled = self.configuration.isInstrumentationEnabled; + if (instrumentationEnabled && !self.isSwizzled) { + [self.instrumentation registerInstrumentGroup:kFPRInstrumentationGroupNetworkKey]; + [self.instrumentation registerInstrumentGroup:kFPRInstrumentationGroupUIKitKey]; + self.swizzled = YES; + } +} + +#pragma mark - Public methods + +- (void)logTrace:(FIRTrace *)trace { + if (self.configured == NO) { + FPRLogError(kFPRClientPerfNotConfigured, @"Dropping trace event %@. Perf SDK not configured.", + trace.name); + return; + } + if ([trace isCompleteAndValid]) { + dispatch_group_async(self.eventsQueueGroup, self.eventsQueue, ^{ + firebase_perf_v1_PerfMetric metric = FPRGetPerfMetricMessage(self.config.appID); + FPRSetTraceMetric(&metric, FPRGetTraceMetric(trace)); + FPRSetApplicationProcessState(&metric, + FPRApplicationProcessState(trace.backgroundTraceState)); + + // Log the trace metric with its console URL. + if ([trace.name hasPrefix:kFPRPrefixForScreenTraceName]) { + FPRLogInfo(kFPRClientMetricLogged, + @"Logging trace metric - %@ %.4fms. In a minute, visit the Firebase console to " + @"view your data: %@", + trace.name, metric.trace_metric.duration_us / 1000.0, + [FPRConsoleURLGenerator generateScreenTraceURLWithProjectID:self.projectID + bundleID:self.bundleID + traceName:trace.name]); + } else { + FPRLogInfo(kFPRClientMetricLogged, + @"Logging trace metric - %@ %.4fms. In a minute, visit the Firebase console to " + @"view your data: %@", + trace.name, metric.trace_metric.duration_us / 1000.0, + [FPRConsoleURLGenerator generateCustomTraceURLWithProjectID:self.projectID + bundleID:self.bundleID + traceName:trace.name]); + } + [self processAndLogEvent:metric]; + }); + } else { + FPRLogWarning(kFPRClientInvalidTrace, @"Invalid trace, skipping send."); + } +} + +- (void)logNetworkTrace:(nonnull FPRNetworkTrace *)trace { + if (self.configured == NO) { + FPRLogError(kFPRClientPerfNotConfigured, @"Dropping trace event %@. Perf SDK not configured.", + trace.URLRequest.URL.absoluteString); + return; + } + dispatch_group_async(self.eventsQueueGroup, self.eventsQueue, ^{ + if ([trace isValid]) { + firebase_perf_v1_NetworkRequestMetric networkRequestMetric = + FPRGetNetworkRequestMetric(trace); + int64_t duration = networkRequestMetric.has_time_to_response_completed_us + ? networkRequestMetric.time_to_response_completed_us + : 0; + + NSString *responseCode = networkRequestMetric.has_http_response_code + ? [@(networkRequestMetric.http_response_code) stringValue] + : @"UNKNOWN"; + FPRLogInfo(kFPRClientMetricLogged, + @"Logging network request trace - %@, Response code: %@, %.4fms", + trace.trimmedURLString, responseCode, duration / 1000.0); + firebase_perf_v1_PerfMetric metric = FPRGetPerfMetricMessage(self.config.appID); + FPRSetNetworkRequestMetric(&metric, networkRequestMetric); + FPRSetApplicationProcessState(&metric, + FPRApplicationProcessState(trace.backgroundTraceState)); + + [self processAndLogEvent:metric]; + } + }); +} + +- (void)logGaugeMetric:(nonnull NSArray *)gaugeData forSessionId:(nonnull NSString *)sessionId { + if (self.configured == NO) { + FPRLogError(kFPRClientPerfNotConfigured, @"Dropping session event. Perf SDK not configured."); + return; + } + dispatch_group_async(self.eventsQueueGroup, self.eventsQueue, ^{ + firebase_perf_v1_PerfMetric metric = FPRGetPerfMetricMessage(self.config.appID); + firebase_perf_v1_GaugeMetric gaugeMetric = firebase_perf_v1_GaugeMetric_init_default; + if ((gaugeData != nil && gaugeData.count != 0) && (sessionId != nil && sessionId.length != 0)) { + gaugeMetric = FPRGetGaugeMetric(gaugeData, sessionId); + } + FPRSetGaugeMetric(&metric, gaugeMetric); + [self processAndLogEvent:metric]; + }); + + // Check and update the sessionID if the session is running for too long. + [[FPRSessionManager sharedInstance] stopGaugesIfRunningTooLong]; +} + +- (void)processAndLogEvent:(firebase_perf_v1_PerfMetric)event { + BOOL tracingEnabled = self.configuration.isDataCollectionEnabled; + if (!tracingEnabled) { + FPRLogDebug(kFPRClientPerfNotConfigured, @"Dropping event since data collection is disabled."); + return; + } + + BOOL sdkEnabled = [self.configuration sdkEnabled]; + if (!sdkEnabled) { + FPRLogInfo(kFPRClientSDKDisabled, @"Dropping event since Performance SDK is disabled."); + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (self.installations == nil) { + // Delayed initialization of installations because FIRApp needs to be configured first. + self.installations = [FIRInstallations installations]; + } + }); + + // Attempts to dispatch events if successfully retrieve installation ID. + [self.installations + installationIDWithCompletion:^(NSString *_Nullable identifier, NSError *_Nullable error) { + if (error) { + FPRLogError(kFPRClientInstanceIDNotAvailable, @"FIRInstallations error: %@", + error.description); + } else { + dispatch_group_async(self.eventsQueueGroup, self.eventsQueue, ^{ + firebase_perf_v1_PerfMetric updatedEvent = event; + updatedEvent.application_info.app_instance_id = FPREncodeString(identifier); + [self.gdtLogger logEvent:updatedEvent]; + }); + } + }]; +} + +#pragma mark - Clearcut log directory removal methods + ++ (void)cleanupClearcutCacheDirectory { + NSString *logDirectoryPath = [FPRClient logDirectoryPath]; + + if (logDirectoryPath != nil) { + BOOL logDirectoryExists = [[NSFileManager defaultManager] fileExistsAtPath:logDirectoryPath]; + + if (logDirectoryExists) { + NSError *directoryError = nil; + [[NSFileManager defaultManager] removeItemAtPath:logDirectoryPath error:&directoryError]; + + if (directoryError) { + FPRLogDebug(kFPRClientTempDirectory, + @"Failed to delete the stale log directory at path: %@ with error: %@.", + logDirectoryPath, directoryError); + } + } + } +} + ++ (NSString *)logDirectoryPath { + static NSString *cacheDir; + static NSString *fireperfCacheDir; + static dispatch_once_t onceToken; + + dispatch_once(&onceToken, ^{ + cacheDir = + [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; + + if (!cacheDir) { + fireperfCacheDir = nil; + } else { + fireperfCacheDir = [cacheDir stringByAppendingPathComponent:@"firebase_perf_logging"]; + } + }); + + return fireperfCacheDir; +} + +#pragma mark - Unswizzling, use only for unit tests + +- (void)disableInstrumentation { + [self.instrumentation deregisterInstrumentGroup:kFPRInstrumentationGroupNetworkKey]; + [self.instrumentation deregisterInstrumentGroup:kFPRInstrumentationGroupUIKitKey]; + self.swizzled = NO; + [self.configuration setInstrumentationEnabled:NO]; +} + +#pragma mark - FIRSessionsSubscriber + +- (void)onSessionChanged:(FIRSessionDetails *_Nonnull)session { + [[FPRSessionManager sharedInstance] updateSessionId:session.sessionId]; +} + +- (BOOL)isDataCollectionEnabled { + return self.configuration.isDataCollectionEnabled; +} + +- (FIRSessionsSubscriberName)sessionsSubscriberName { + return FIRSessionsSubscriberNamePerformance; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.h new file mode 100644 index 0000000..e06aa4c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.h @@ -0,0 +1,50 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * @brief Configures the behavior of FPR. + */ +@interface FPRConfiguration : NSObject + +/** + * Designated initializer. + * @brief Creates a new configuration. + * + * @param appID Identifies app on Firebase + * @param APIKey Authenticates app on Firebase + * @param autoPush Google Data Transport destination - prod/autopush + */ +- (instancetype)initWithAppID:(NSString *)appID + APIKey:(NSString *)APIKey + autoPush:(BOOL)autoPush NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/** This is a class method for initWithAppID:APIKey:autoPush:. */ ++ (instancetype)configurationWithAppID:(NSString *)appID + APIKey:(NSString *)APIKey + autoPush:(BOOL)autoPush; + +/** @brief Identifies app on Firebase. */ +@property(readonly, nonatomic, copy) NSString *appID; + +/** @brief Authenticates app on Firebase. */ +@property(readonly, nonatomic, copy) NSString *APIKey; + +/** @brief Use autopush or prod logging. */ +@property(readonly, nonatomic, assign, getter=isAutoPush) BOOL autoPush; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.m new file mode 100644 index 0000000..f69d5b8 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConfiguration.m @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRConfiguration.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" + +@implementation FPRConfiguration + +- (instancetype)init { + FPRAssert(NO, @"init called on NS_UNAVAILABLE init"); + return nil; +} + +- (instancetype)initWithAppID:(NSString *)appID APIKey:(NSString *)APIKey autoPush:(BOOL)autoPush { + self = [super init]; + if (self) { + _appID = [appID copy]; + _APIKey = [APIKey copy]; + _autoPush = autoPush; + } + + return self; +} + ++ (instancetype)configurationWithAppID:(NSString *)appID + APIKey:(NSString *)APIKey + autoPush:(BOOL)autoPush { + return [[self alloc] initWithAppID:appID APIKey:APIKey autoPush:autoPush]; +} + +- (id)copyWithZone:(NSZone *)zone { + return self; // This class is immutable +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.h new file mode 100644 index 0000000..4341fa1 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.h @@ -0,0 +1,95 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseCore/Extension/FIRLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSString* const kFIRLoggerPerf; + +#define FPRLogDebug(messageCode, ...) FIRLogDebug(kFIRLoggerPerf, messageCode, __VA_ARGS__) +#define FPRLogError(messageCode, ...) FIRLogError(kFIRLoggerPerf, messageCode, __VA_ARGS__) +#define FPRLogInfo(messageCode, ...) FIRLogInfo(kFIRLoggerPerf, messageCode, __VA_ARGS__) +#define FPRLogNotice(messageCode, ...) FIRLogNotice(kFIRLoggerPerf, messageCode, __VA_ARGS__) +#define FPRLogWarning(messageCode, ...) FIRLogWarning(kFIRLoggerPerf, messageCode, __VA_ARGS__) + +// FPR Client message codes. +FOUNDATION_EXTERN NSString* const kFPRClientInitialize; +FOUNDATION_EXTERN NSString* const kFPRClientTempDirectory; +FOUNDATION_EXTERN NSString* const kFPRClientCreateWorkingDirectory; +FOUNDATION_EXTERN NSString* const kFPRClientClearcutUpload; +FOUNDATION_EXTERN NSString* const kFPRClientInstanceIDNotAvailable; +FOUNDATION_EXTERN NSString* const kFPRClientNameTruncated; +FOUNDATION_EXTERN NSString* const kFPRClientNameReserved; +FOUNDATION_EXTERN NSString* const kFPRClientInvalidTrace; +FOUNDATION_EXTERN NSString* const kFPRClientMetricLogged; +FOUNDATION_EXTERN NSString* const kFPRClientDataUpload; +FOUNDATION_EXTERN NSString* const kFPRClientNameLengthCheckFailed; +FOUNDATION_EXTERN NSString* const kFPRClientPerfNotConfigured; +FOUNDATION_EXTERN NSString* const kFPRClientSDKDisabled; + +// FPR Trace message codes. +FOUNDATION_EXTERN NSString* const kFPRTraceNoName; +FOUNDATION_EXTERN NSString* const kFPRTraceAlreadyStopped; +FOUNDATION_EXTERN NSString* const kFPRTraceNotStarted; +FOUNDATION_EXTERN NSString* const kFPRTraceDisabled; +FOUNDATION_EXTERN NSString* const kFPRTraceEmptyName; +FOUNDATION_EXTERN NSString* const kFPRTraceStartedNotStopped; +FOUNDATION_EXTERN NSString* const kFPRTraceNotCreated; +FOUNDATION_EXTERN NSString* const kFPRTraceInvalidName; + +// FPR NetworkTrace message codes. +FOUNDATION_EXTERN NSString* const kFPRNetworkTraceFileError; +FOUNDATION_EXTERN NSString* const kFPRNetworkTraceInvalidInputs; +FOUNDATION_EXTERN NSString* const kFPRNetworkTraceURLLengthExceeds; +FOUNDATION_EXTERN NSString* const kFPRNetworkTraceURLLengthTruncation; +FOUNDATION_EXTERN NSString* const kFPRNetworkTraceNotTrackable; + +// FPR LogSampler message codes. +FOUNDATION_EXTERN NSString* const kFPRSamplerInvalidConfigs; + +// FPR attributes message codes. +FOUNDATION_EXTERN NSString* const kFPRAttributeNoName; +FOUNDATION_EXTERN NSString* const kFPRAttributeNoValue; +FOUNDATION_EXTERN NSString* const kFPRMaxAttributesReached; +FOUNDATION_EXTERN NSString* const kFPRAttributeNameIllegalCharacters; + +// Manual network instrumentation codes. +FOUNDATION_EXTERN NSString* const kFPRInstrumentationInvalidInputs; +FOUNDATION_EXTERN NSString* const kFPRInstrumentationDisabledAfterConfigure; + +// FPR diagnostic message codes. +FOUNDATION_EXTERN NSString* const kFPRDiagnosticInfo; +FOUNDATION_EXTERN NSString* const kFPRDiagnosticFailure; +FOUNDATION_EXTERN NSString* const kFPRDiagnosticLog; + +// FPR Configuration related error codes. +FOUNDATION_EXTERN NSString* const kFPRConfigurationFetchFailure; + +// FPR URL filtering message codes. +FOUNDATION_EXTERN NSString* const kFPRURLAllowlistingEnabled; + +// FPR Gauge manager codes. +FOUNDATION_EXTERN NSString* const kFPRGaugeManagerDataCollected; +FOUNDATION_EXTERN NSString* const kFPRSessionId; +FOUNDATION_EXTERN NSString* const kFPRCPUCollection; +FOUNDATION_EXTERN NSString* const kFPRMemoryCollection; + +// FPRSDKConfiguration message codes. +FOUNDATION_EXTERN NSString* const kFPRSDKFeaturesBlock; + +// FPRGDTEvent message codes. +FOUNDATION_EXTERN NSString* const kFPRTransportBytesError; + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.m new file mode 100644 index 0000000..9e890c6 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRConsoleLogger.m @@ -0,0 +1,86 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +// The Firebase service used in the Firebase logger. +FIRLoggerService kFIRLoggerPerf = @"[FirebasePerformance]"; + +// FPR Client message codes. +NSString* const kFPRClientInitialize = @"I-PRF100001"; +NSString* const kFPRClientTempDirectory = @"I-PRF100002"; +NSString* const kFPRClientCreateWorkingDirectory = @"I-PRF100003"; +NSString* const kFPRClientClearcutUpload = @"I-PRF100004"; +NSString* const kFPRClientInstanceIDNotAvailable = @"I-PRF100005"; +NSString* const kFPRClientNameTruncated = @"I-PRF100006"; +NSString* const kFPRClientNameReserved = @"I-PRF100007"; +NSString* const kFPRClientInvalidTrace = @"I-PRF100008"; +NSString* const kFPRClientMetricLogged = @"I-PRF100009"; +NSString* const kFPRClientDataUpload = @"I-PRF100010"; +NSString* const kFPRClientNameLengthCheckFailed = @"I-PRF100012"; +NSString* const kFPRClientPerfNotConfigured = @"I-PRF100013"; +NSString* const kFPRClientSDKDisabled = @"I-PRF100014"; + +// FPR Trace message codes. +NSString* const kFPRTraceNoName = @"I-PRF200001"; +NSString* const kFPRTraceAlreadyStopped = @"I-PRF200002"; +NSString* const kFPRTraceNotStarted = @"I-PRF200003"; +NSString* const kFPRTraceDisabled = @"I-PRF200004"; +NSString* const kFPRTraceEmptyName = @"I-PRF200005"; +NSString* const kFPRTraceStartedNotStopped = @"I-PRF200006"; +NSString* const kFPRTraceNotCreated = @"I-PRF200007"; +NSString* const kFPRTraceInvalidName = @"I-PRF200008"; + +// FPR NetworkTrace message codes. +NSString* const kFPRNetworkTraceFileError = @"I-PRF300001"; +NSString* const kFPRNetworkTraceInvalidInputs = @"I-PRF300002"; +NSString* const kFPRNetworkTraceURLLengthExceeds = @"I-PRF300003"; +NSString* const kFPRNetworkTraceNotTrackable = @"I-PRF300004"; +NSString* const kFPRNetworkTraceURLLengthTruncation = @"I-PRF300005"; + +// FPR LogSampler message codes. +NSString* const kFPRSamplerInvalidConfigs = @"I-PRF400001"; + +// FPR Attributes message codes. +NSString* const kFPRAttributeNoName = @"I-PRF500001"; +NSString* const kFPRAttributeNoValue = @"I-PRF500002"; +NSString* const kFPRMaxAttributesReached = @"I-PRF500003"; +NSString* const kFPRAttributeNameIllegalCharacters = @"I-PRF500004"; + +// Manual network instrumentation codes. +NSString* const kFPRInstrumentationInvalidInputs = @"I-PRF600001"; +NSString* const kFPRInstrumentationDisabledAfterConfigure = @"I-PRF600002"; + +// FPR diagnostic message codes. +NSString* const kFPRDiagnosticInfo = @"I-PRF700001"; +NSString* const kFPRDiagnosticFailure = @"I-PRF700002"; +NSString* const kFPRDiagnosticLog = @"I-PRF700003"; + +// FPR Configuration related error codes. +NSString* const kFPRConfigurationFetchFailure = @"I-PRF710001"; + +// FPR URL filtering message codes. +NSString* const kFPRURLAllowlistingEnabled = @"I-PRF800001"; + +// FPR Gauge manager codes. +NSString* const kFPRGaugeManagerDataCollected = @"I-PRF900001"; +NSString* const kFPRSessionId = @"I-PRF900002"; +NSString* const kFPRCPUCollection = @"I-PRF900003"; +NSString* const kFPRMemoryCollection = @"I-PRF900004"; + +// FPRSDKConfiguration message codes. +NSString* const kFPRSDKFeaturesBlock = @"I-PRF910001"; + +// FPRGDTEvent message codes. +NSString* const kFPRTransportBytesError = @"I-PRF920001"; diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.h new file mode 100644 index 0000000..f7a6557 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.h @@ -0,0 +1,48 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** Trims the given name string and checks if the name is reservable. + * + * @param name The name to be checked for reservability. + * @return Reservable name or nil if there is an error. + */ +FOUNDATION_EXTERN NSString *FPRReservableName(NSString *name); + +/** Trims the given name string and checks if the name is reservable. + * + * @param name The name to be checked for reservability for an attribute name. + * @return Reservable name or nil if there is an error. + */ +FOUNDATION_EXTERN NSString *FPRReservableAttributeName(NSString *name); + +/** Checks if the given attribute value follows length restrictions. + * + * @param value The value to be checked. + * @return Valid value or nil if that does not adhere to length restrictions. + */ +FOUNDATION_EXTERN NSString *FPRValidatedAttributeValue(NSString *value); + +/** Truncates the URL string if the length of the URL going beyond the defined limit. The truncation + * will happen upto the end of a complete query sub path whose length is less than limit. + * For example: If the URL is abc.com/one/two/three/four and if the URL max length is 20, trimmed + * URL will be to abc.com/one/two and not abc.com/one/two/thre (three is incomplete). + * If the domain name goes beyond 2000 characters (which is unlikely), that might result in an + * empty string being returned. + * + * @param URLString A URL string. + * @return The unchanged url string or a truncated version if the length goes beyond the limit. + */ +FOUNDATION_EXTERN NSString *FPRTruncatedURLString(NSString *URLString); diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.m new file mode 100644 index 0000000..23d6bf9 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRDataUtils.m @@ -0,0 +1,127 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRDataUtils.h" + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#pragma mark - Public functions + +NSString *FPRReservableName(NSString *name) { + NSString *reservableName = + [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + if ([reservableName hasPrefix:kFPRInternalNamePrefix]) { + FPRLogError(kFPRClientNameReserved, @"%@ prefix is reserved. Dropped %@.", + kFPRInternalNamePrefix, reservableName); + return nil; + } + + if (reservableName.length == 0) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"Given name is empty."); + return nil; + } + + if (reservableName.length > kFPRMaxNameLength) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"%@ is greater than %d characters, dropping it.", + reservableName, kFPRMaxNameLength); + return nil; + } + + return reservableName; +} + +NSString *FPRReservableAttributeName(NSString *name) { + NSString *reservableName = + [name stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; + + static NSArray *reservedPrefix = nil; + static NSPredicate *characterCheck = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + reservedPrefix = @[ @"firebase_", @"google_", @"ga_" ]; + NSString *characterRegex = @"[A-Z0-9a-z_]*"; + characterCheck = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", characterRegex]; + }); + + __block BOOL containsReservedPrefix = NO; + [reservedPrefix enumerateObjectsUsingBlock:^(NSString *prefix, NSUInteger idx, BOOL *stop) { + if ([reservableName hasPrefix:prefix]) { + FPRLogError(kFPRClientNameReserved, @"%@ prefix is reserved. Dropped %@.", prefix, + reservableName); + *stop = YES; + containsReservedPrefix = YES; + } + }]; + + if (containsReservedPrefix) { + return nil; + } + + if (reservableName.length == 0) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"Given name is empty."); + return nil; + } + + if ([characterCheck evaluateWithObject:reservableName] == NO) { + FPRLogError(kFPRAttributeNameIllegalCharacters, + @"Illegal characters used for attribute name, " + "characters allowed are alphanumeric or underscore."); + return nil; + } + + if (reservableName.length > kFPRMaxAttributeNameLength) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"%@ is greater than %d characters, dropping it.", + reservableName, kFPRMaxAttributeNameLength); + return nil; + } + + return reservableName; +} + +NSString *FPRValidatedAttributeValue(NSString *value) { + if (value.length == 0) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"Given value is empty."); + return nil; + } + + if (value.length > kFPRMaxAttributeValueLength) { + FPRLogError(kFPRClientNameLengthCheckFailed, @"%@ is greater than %d characters, dropping it.", + value, kFPRMaxAttributeValueLength); + return nil; + } + + return value; +} + +NSString *FPRTruncatedURLString(NSString *URLString) { + NSString *truncatedURLString = URLString; + NSString *pathSeparator = @"/"; + if (truncatedURLString.length > kFPRMaxURLLength) { + NSString *truncationCharacter = + [truncatedURLString substringWithRange:NSMakeRange(kFPRMaxURLLength, 1)]; + + truncatedURLString = [URLString substringToIndex:kFPRMaxURLLength]; + if (![pathSeparator isEqual:truncationCharacter]) { + NSRange rangeOfTruncation = [truncatedURLString rangeOfString:pathSeparator + options:NSBackwardsSearch]; + if (rangeOfTruncation.location != NSNotFound) { + truncatedURLString = [URLString substringToIndex:rangeOfTruncation.location]; + } + } + FPRLogWarning(kFPRClientNameTruncated, @"URL exceeds %d characters. Truncated url: %@", + kFPRMaxURLLength, truncatedURLString); + } + return truncatedURLString; +} diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.h new file mode 100644 index 0000000..db0cbf9 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.h @@ -0,0 +1,161 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST +#define TARGET_HAS_MOBILE_CONNECTIVITY +#import +#endif + +#import "FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h" + +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +/**nanopb struct of encoded NSDictionary.*/ +typedef struct { + pb_bytes_array_t* _Nonnull key; + pb_bytes_array_t* _Nonnull value; +} StringToStringMap; + +/**nanopb struct of encoded NSDictionary.*/ +typedef struct { + pb_bytes_array_t* _Nonnull key; + bool has_value; + int64_t value; +} StringToNumberMap; + +/** Callocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + * @return pb_byte array + */ +extern pb_bytes_array_t* _Nullable FPREncodeData(NSData* _Nonnull data); + +/** Callocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + * @return pb_byte array + */ +extern pb_bytes_array_t* _Nullable FPREncodeString(NSString* _Nonnull string); + +/** Callocs a nanopb StringToStringMap and copies the given NSDictionary bytes into the + * StringToStringMap. + * + * @param dict The dict to copy into the new StringToStringMap. + * @return A reference to StringToStringMap + */ +extern StringToStringMap* _Nullable FPREncodeStringToStringMap(NSDictionary* _Nullable dict); + +/** Callocs a nanopb StringToNumberMap and copies the given NSDictionary bytes into the + * StringToStringMap. + * + * @param dict The dict to copy into the new StringToNumberMap. + * @return A reference to StringToNumberMap + */ +extern StringToNumberMap* _Nullable FPREncodeStringToNumberMap(NSDictionary* _Nullable dict); + +/** Creates a new firebase_perf_v1_PerfMetric struct populated with system metadata. + * @param appID The Google app id to put into the message + * @return A firebase_perf_v1_PerfMetric struct. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +extern firebase_perf_v1_PerfMetric FPRGetPerfMetricMessage(NSString* _Nonnull appID); + +/** Creates a new firebase_perf_v1_ApplicationInfo struct populated with system metadata. + * @return A firebase_perf_v1_ApplicationInfo struct. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +extern firebase_perf_v1_ApplicationInfo FPRGetApplicationInfoMessage(void); + +/** Converts the FIRTrace object to a firebase_perf_v1_TraceMetric struct. + * @return A firebase_perf_v1_TraceMetric struct. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +extern firebase_perf_v1_TraceMetric FPRGetTraceMetric(FIRTrace* _Nonnull trace); + +/** Converts the FPRNetworkTrace object to a firebase_perf_v1_NetworkRequestMetric struct. + * @return A firebase_perf_v1_NetworkRequestMetric struct. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +extern firebase_perf_v1_NetworkRequestMetric FPRGetNetworkRequestMetric( + FPRNetworkTrace* _Nonnull trace); + +/** Converts the gaugeData array object to a firebase_perf_v1_GaugeMetric struct. + * @return A firebase_perf_v1_GaugeMetric struct. + */ +extern firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray* _Nonnull gaugeData, + NSString* _Nonnull sessionId); + +/** Converts the FPRTraceState to a firebase_perf_v1_ApplicationProcessState struct. + * @return A firebase_perf_v1_ApplicationProcessState struct. + */ +extern firebase_perf_v1_ApplicationProcessState FPRApplicationProcessState(FPRTraceState state); + +/** Populate a firebase_perf_v1_PerfMetric object with the given firebase_perf_v1_ApplicationInfo. + * + * @param perfMetric The reference to a firebase_perf_v1_PerfMetric object to be populated. + * @param appInfo The firebase_perf_v1_ApplicationInfo object that will be added to + * firebase_perf_v1_PerfMetric. + */ +extern void FPRSetApplicationInfo(firebase_perf_v1_PerfMetric* _Nonnull perfMetric, + firebase_perf_v1_ApplicationInfo appInfo); + +/** Populate a firebase_perf_v1_PerfMetric object with the given firebase_perf_v1_TraceMetric. + * + * @param perfMetric The reference to firebase_perf_v1_PerfMetric to be populated. + * @param traceMetric The firebase_perf_v1_TraceMetric object that will be added to + * firebase_perf_v1_PerfMetric. + */ +extern void FPRSetTraceMetric(firebase_perf_v1_PerfMetric* _Nonnull perfMetric, + firebase_perf_v1_TraceMetric traceMetric); + +/** Populate a firebase_perf_v1_PerfMetric object with the given + * firebase_perf_v1_NetworkRequestMetric. + * + * @param perfMetric The reference to a firebase_perf_v1_PerfMetric object to be populated. + * @param networkMetric The firebase_perf_v1_NetworkRequestMetric object that will be added to + * firebase_perf_v1_PerfMetric. + */ +extern void FPRSetNetworkRequestMetric(firebase_perf_v1_PerfMetric* _Nonnull perfMetric, + firebase_perf_v1_NetworkRequestMetric networkMetric); + +/** Populate a firebase_perf_v1_PerfMetric object with the given firebase_perf_v1_GaugeMetric. + * + * @param perfMetric The reference to a firebase_perf_v1_PerfMetric object to be populated. + * @param gaugeMetric The firebase_perf_v1_GaugeMetric object that will be added to + * firebase_perf_v1_PerfMetric. + */ +extern void FPRSetGaugeMetric(firebase_perf_v1_PerfMetric* _Nonnull perfMetric, + firebase_perf_v1_GaugeMetric gaugeMetric); + +/** Populate a firebase_perf_v1_PerfMetric object with the given + * firebase_perf_v1_ApplicationProcessState. + * + * @param perfMetric The reference to a firebase_perf_v1_PerfMetric object to be populated. + * @param state The firebase_perf_v1_ApplicationProcessState object that will be added to + * firebase_perf_v1_PerfMetric. + */ +extern void FPRSetApplicationProcessState(firebase_perf_v1_PerfMetric* _Nonnull perfMetric, + firebase_perf_v1_ApplicationProcessState state); + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY +/** Obtain a CTTelephonyNetworkInfo object to determine device network attributes. + * @return CTTelephonyNetworkInfo object. + */ +extern CTTelephonyNetworkInfo* _Nullable FPRNetworkInfo(void); +#endif diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.m new file mode 100644 index 0000000..2f02fd3 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRNanoPbUtils.m @@ -0,0 +1,472 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRNanoPbUtils.h" + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY +#import +#import +#endif + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/FIRPerformance+Internal.h" +#import "FirebasePerformance/Sources/FPRDataUtils.h" +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h" + +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h" + +#define BYTES_TO_KB(x) (x / 1024) + +static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString( + NSString *methodString); +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY +static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType(void); +#endif +NSArray *FPRMakeFirstSessionVerbose(NSArray *sessions); + +#pragma mark - Nanopb creation utilities + +/** Converts the network method string to a value defined in the enum + * firebase_perf_v1_NetworkRequestMetric_HttpMethod. + * @return Enum value of the method string. If there is no mapping value defined for the method + * firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN is returned. + */ +static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString( + NSString *methodString) { + static NSDictionary *HTTPToFPRNetworkTraceMethod; + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + HTTPToFPRNetworkTraceMethod = @{ + @"GET" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_GET), + @"POST" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_POST), + @"PUT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PUT), + @"DELETE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_DELETE), + @"HEAD" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_HEAD), + @"PATCH" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PATCH), + @"OPTIONS" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_OPTIONS), + @"TRACE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_TRACE), + @"CONNECT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT), + }; + }); + + NSNumber *HTTPMethod = HTTPToFPRNetworkTraceMethod[methodString]; + if (HTTPMethod == nil) { + return firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN; + } + return HTTPMethod.intValue; +} + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY +/** Get the current cellular network connection type in + * firebase_perf_v1_NetworkConnectionInfo_MobileSubtype format. + * @return Current cellular network connection type. + */ +static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType(void) { + static NSDictionary *cellularNetworkToMobileSubtype; + static dispatch_once_t onceToken = 0; + dispatch_once(&onceToken, ^{ + cellularNetworkToMobileSubtype = @{ + CTRadioAccessTechnologyGPRS : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_GPRS), + CTRadioAccessTechnologyEdge : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EDGE), + CTRadioAccessTechnologyWCDMA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA), + CTRadioAccessTechnologyHSDPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSDPA), + CTRadioAccessTechnologyHSUPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSUPA), + CTRadioAccessTechnologyCDMA1x : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA), + CTRadioAccessTechnologyCDMAEVDORev0 : + @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_0), + CTRadioAccessTechnologyCDMAEVDORevA : + @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_A), + CTRadioAccessTechnologyCDMAEVDORevB : + @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_B), + CTRadioAccessTechnologyeHRPD : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EHRPD), + CTRadioAccessTechnologyLTE : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_LTE) + }; + }); + + NSDictionary *radioAccessors = + FPRNetworkInfo().serviceCurrentRadioAccessTechnology; + if (radioAccessors.count > 0) { + NSString *networkString = [radioAccessors.allValues objectAtIndex:0]; + NSNumber *cellularNetworkType = cellularNetworkToMobileSubtype[networkString]; + return cellularNetworkType.intValue; + } + + return firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; +} +#endif + +#pragma mark - Nanopb decode and encode helper methods + +pb_bytes_array_t *FPREncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} + +pb_bytes_array_t *FPREncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return FPREncodeData(stringBytes); +} + +StringToStringMap *_Nullable FPREncodeStringToStringMap(NSDictionary *_Nullable dict) { + StringToStringMap *map = calloc(dict.count, sizeof(StringToStringMap)); + __block NSUInteger index = 0; + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) { + map[index].key = FPREncodeString(key); + map[index].value = FPREncodeString(value); + index++; + }]; + return map; +} + +StringToNumberMap *_Nullable FPREncodeStringToNumberMap(NSDictionary *_Nullable dict) { + StringToNumberMap *map = calloc(dict.count, sizeof(StringToNumberMap)); + __block NSUInteger index = 0; + [dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *value, BOOL *stop) { + map[index].key = FPREncodeString(key); + map[index].value = [value longLongValue]; + map[index].has_value = true; + index++; + }]; + return map; +} + +firebase_perf_v1_PerfSession *FPREncodePerfSessions(NSArray *sessions, + NSInteger count) { + firebase_perf_v1_PerfSession *perfSessions = calloc(count, sizeof(firebase_perf_v1_PerfSession)); + __block NSUInteger perfSessionIndex = 0; + + [sessions enumerateObjectsUsingBlock:^(FPRSessionDetails *_Nonnull session, NSUInteger index, + BOOL *_Nonnull stop) { + perfSessions[perfSessionIndex].session_id = FPREncodeString(session.sessionId); + perfSessions[perfSessionIndex].session_verbosity_count = 0; + if ((session.options & FPRSessionOptionsEvents) || + (session.options & FPRSessionOptionsGauges)) { + perfSessions[perfSessionIndex].session_verbosity_count = 1; + perfSessions[perfSessionIndex].session_verbosity = + calloc(perfSessions[perfSessionIndex].session_verbosity_count, + sizeof(firebase_perf_v1_SessionVerbosity)); + perfSessions[perfSessionIndex].session_verbosity[0] = + firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS; + } + perfSessionIndex++; + }]; + return perfSessions; +} + +#pragma mark - Public methods + +firebase_perf_v1_PerfMetric FPRGetPerfMetricMessage(NSString *appID) { + firebase_perf_v1_PerfMetric perfMetricMessage = firebase_perf_v1_PerfMetric_init_default; + FPRSetApplicationInfo(&perfMetricMessage, FPRGetApplicationInfoMessage()); + perfMetricMessage.application_info.google_app_id = FPREncodeString(appID); + + return perfMetricMessage; +} + +firebase_perf_v1_ApplicationInfo FPRGetApplicationInfoMessage(void) { + firebase_perf_v1_ApplicationInfo appInfoMessage = firebase_perf_v1_ApplicationInfo_init_default; + firebase_perf_v1_IosApplicationInfo iosAppInfo = firebase_perf_v1_IosApplicationInfo_init_default; + NSBundle *mainBundle = [NSBundle mainBundle]; + iosAppInfo.bundle_short_version = + FPREncodeString([mainBundle infoDictionary][@"CFBundleShortVersionString"]); + iosAppInfo.sdk_version = FPREncodeString([NSString stringWithUTF8String:kFPRSDKVersion]); + iosAppInfo.network_connection_info.network_type = + [FPRAppActivityTracker sharedInstance].networkType; + iosAppInfo.has_network_connection_info = true; + iosAppInfo.network_connection_info.has_network_type = true; +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + if (iosAppInfo.network_connection_info.network_type == + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE) { + iosAppInfo.network_connection_info.mobile_subtype = FPRCellularNetworkType(); + iosAppInfo.network_connection_info.has_mobile_subtype = true; + } +#endif + appInfoMessage.ios_app_info = iosAppInfo; + appInfoMessage.has_ios_app_info = true; + + NSDictionary *attributes = + [[FIRPerformance sharedInstance].attributes mutableCopy]; + appInfoMessage.custom_attributes_count = (pb_size_t)attributes.count; + appInfoMessage.custom_attributes = + (firebase_perf_v1_ApplicationInfo_CustomAttributesEntry *)FPREncodeStringToStringMap( + attributes); + + return appInfoMessage; +} + +firebase_perf_v1_TraceMetric FPRGetTraceMetric(FIRTrace *trace) { + firebase_perf_v1_TraceMetric traceMetric = firebase_perf_v1_TraceMetric_init_default; + traceMetric.name = FPREncodeString(trace.name); + + // Set if the trace is an internally created trace. + traceMetric.is_auto = trace.isInternal; + traceMetric.has_is_auto = true; + + // Convert the trace duration from seconds to microseconds. + traceMetric.duration_us = trace.totalTraceTimeInterval * USEC_PER_SEC; + traceMetric.has_duration_us = true; + + // Convert the start time from seconds to microseconds. + traceMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC; + traceMetric.has_client_start_time_us = true; + + // Filling counters + NSDictionary *counters = trace.counters; + traceMetric.counters_count = (pb_size_t)counters.count; + traceMetric.counters = + (firebase_perf_v1_TraceMetric_CountersEntry *)FPREncodeStringToNumberMap(counters); + + // Filling subtraces + traceMetric.subtraces_count = (pb_size_t)[trace.stages count]; + firebase_perf_v1_TraceMetric *subtraces = + calloc(traceMetric.subtraces_count, sizeof(firebase_perf_v1_TraceMetric)); + __block NSUInteger subtraceIndex = 0; + [trace.stages + enumerateObjectsUsingBlock:^(FIRTrace *_Nonnull stage, NSUInteger idx, BOOL *_Nonnull stop) { + subtraces[subtraceIndex] = FPRGetTraceMetric(stage); + subtraceIndex++; + }]; + traceMetric.subtraces = subtraces; + + // Filling custom attributes + NSDictionary *attributes = [trace.attributes mutableCopy]; + traceMetric.custom_attributes_count = (pb_size_t)attributes.count; + traceMetric.custom_attributes = + (firebase_perf_v1_TraceMetric_CustomAttributesEntry *)FPREncodeStringToStringMap(attributes); + + // Filling session details + NSArray *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions); + traceMetric.perf_sessions_count = (pb_size_t)[orderedSessions count]; + traceMetric.perf_sessions = + FPREncodePerfSessions(orderedSessions, traceMetric.perf_sessions_count); + + return traceMetric; +} + +firebase_perf_v1_NetworkRequestMetric FPRGetNetworkRequestMetric(FPRNetworkTrace *trace) { + firebase_perf_v1_NetworkRequestMetric networkMetric = + firebase_perf_v1_NetworkRequestMetric_init_default; + networkMetric.url = FPREncodeString(trace.trimmedURLString); + networkMetric.http_method = FPRHTTPMethodForString(trace.URLRequest.HTTPMethod); + networkMetric.has_http_method = true; + + // Convert the start time from seconds to microseconds. + networkMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC; + networkMetric.has_client_start_time_us = true; + + networkMetric.request_payload_bytes = trace.requestSize; + networkMetric.has_request_payload_bytes = true; + networkMetric.response_payload_bytes = trace.responseSize; + networkMetric.has_response_payload_bytes = true; + + networkMetric.http_response_code = trace.responseCode; + networkMetric.has_http_response_code = true; + networkMetric.response_content_type = FPREncodeString(trace.responseContentType); + + if (trace.responseError) { + networkMetric.network_client_error_reason = + firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR; + networkMetric.has_network_client_error_reason = true; + } + + NSTimeInterval requestTimeUs = + USEC_PER_SEC * + [trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated + andState:FPRNetworkTraceCheckpointStateRequestCompleted]; + if (requestTimeUs > 0) { + networkMetric.time_to_request_completed_us = requestTimeUs; + networkMetric.has_time_to_request_completed_us = true; + } + + NSTimeInterval responseIntiationTimeUs = + USEC_PER_SEC * + [trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated + andState:FPRNetworkTraceCheckpointStateResponseReceived]; + if (responseIntiationTimeUs > 0) { + networkMetric.time_to_response_initiated_us = responseIntiationTimeUs; + networkMetric.has_time_to_response_initiated_us = true; + } + + NSTimeInterval responseCompletedUs = + USEC_PER_SEC * + [trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated + andState:FPRNetworkTraceCheckpointStateResponseCompleted]; + if (responseCompletedUs > 0) { + networkMetric.time_to_response_completed_us = responseCompletedUs; + networkMetric.has_time_to_response_completed_us = true; + } + + // Filling custom attributes + NSDictionary *attributes = [trace.attributes mutableCopy]; + networkMetric.custom_attributes_count = (pb_size_t)attributes.count; + networkMetric.custom_attributes = + (firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry *)FPREncodeStringToStringMap( + attributes); + + // Filling session details + NSArray *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions); + networkMetric.perf_sessions_count = (pb_size_t)[orderedSessions count]; + networkMetric.perf_sessions = + FPREncodePerfSessions(orderedSessions, networkMetric.perf_sessions_count); + + return networkMetric; +} + +firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray *gaugeData, NSString *sessionId) { + firebase_perf_v1_GaugeMetric gaugeMetric = firebase_perf_v1_GaugeMetric_init_default; + gaugeMetric.session_id = FPREncodeString(sessionId); + + __block NSInteger cpuReadingsCount = 0; + __block NSInteger memoryReadingsCount = 0; + + firebase_perf_v1_CpuMetricReading *cpuReadings = + calloc([gaugeData count], sizeof(firebase_perf_v1_CpuMetricReading)); + firebase_perf_v1_IosMemoryReading *memoryReadings = + calloc([gaugeData count], sizeof(firebase_perf_v1_IosMemoryReading)); + [gaugeData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { + if ([obj isKindOfClass:[FPRCPUGaugeData class]]) { + FPRCPUGaugeData *gaugeData = (FPRCPUGaugeData *)obj; + cpuReadings[cpuReadingsCount].client_time_us = + gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC; + cpuReadings[cpuReadingsCount].has_client_time_us = true; + cpuReadings[cpuReadingsCount].system_time_us = gaugeData.systemTime; + cpuReadings[cpuReadingsCount].has_system_time_us = true; + cpuReadings[cpuReadingsCount].user_time_us = gaugeData.userTime; + cpuReadings[cpuReadingsCount].has_user_time_us = true; + cpuReadingsCount++; + } + + if ([obj isKindOfClass:[FPRMemoryGaugeData class]]) { + FPRMemoryGaugeData *gaugeData = (FPRMemoryGaugeData *)obj; + memoryReadings[memoryReadingsCount].client_time_us = + gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC; + memoryReadings[memoryReadingsCount].has_client_time_us = true; + memoryReadings[memoryReadingsCount].used_app_heap_memory_kb = + (int32_t)BYTES_TO_KB(gaugeData.heapUsed); + memoryReadings[memoryReadingsCount].has_used_app_heap_memory_kb = true; + memoryReadings[memoryReadingsCount].free_app_heap_memory_kb = + (int32_t)BYTES_TO_KB(gaugeData.heapAvailable); + memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true; + memoryReadingsCount++; + } + }]; + cpuReadings = realloc(cpuReadings, cpuReadingsCount * sizeof(firebase_perf_v1_CpuMetricReading)); + memoryReadings = + realloc(memoryReadings, memoryReadingsCount * sizeof(firebase_perf_v1_IosMemoryReading)); + + gaugeMetric.cpu_metric_readings = cpuReadings; + gaugeMetric.cpu_metric_readings_count = (pb_size_t)cpuReadingsCount; + gaugeMetric.ios_memory_readings = memoryReadings; + gaugeMetric.ios_memory_readings_count = (pb_size_t)memoryReadingsCount; + return gaugeMetric; +} + +firebase_perf_v1_ApplicationProcessState FPRApplicationProcessState(FPRTraceState state) { + firebase_perf_v1_ApplicationProcessState processState = + firebase_perf_v1_ApplicationProcessState_APPLICATION_PROCESS_STATE_UNKNOWN; + switch (state) { + case FPRTraceStateForegroundOnly: + processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND; + break; + + case FPRTraceStateBackgroundOnly: + processState = firebase_perf_v1_ApplicationProcessState_BACKGROUND; + break; + + case FPRTraceStateBackgroundAndForeground: + processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND; + break; + + default: + break; + } + + return processState; +} + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY +CTTelephonyNetworkInfo *FPRNetworkInfo(void) { + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + return networkInfo; +} +#endif + +/** Reorders the list of sessions to make sure the first session is verbose if at least one session + * in the list is verbose. + * @return Ordered list of sessions. + */ +NSArray *FPRMakeFirstSessionVerbose(NSArray *sessions) { + NSMutableArray *orderedSessions = + [[NSMutableArray alloc] initWithArray:sessions]; + + NSInteger firstVerboseSessionIndex = -1; + for (int i = 0; i < [sessions count]; i++) { + if ([sessions[i] isVerbose]) { + firstVerboseSessionIndex = i; + break; + } + } + + if (firstVerboseSessionIndex > 0) { + FPRSessionDetails *verboseSession = orderedSessions[firstVerboseSessionIndex]; + [orderedSessions removeObjectAtIndex:firstVerboseSessionIndex]; + [orderedSessions insertObject:verboseSession atIndex:0]; + } + + return [orderedSessions copy]; +} + +#pragma mark - Nanopb struct fields populating helper methods + +void FPRSetApplicationInfo(firebase_perf_v1_PerfMetric *perfMetric, + firebase_perf_v1_ApplicationInfo appInfo) { + perfMetric->application_info = appInfo; + perfMetric->has_application_info = true; +} + +void FPRSetTraceMetric(firebase_perf_v1_PerfMetric *perfMetric, + firebase_perf_v1_TraceMetric traceMetric) { + perfMetric->trace_metric = traceMetric; + perfMetric->has_trace_metric = true; +} + +void FPRSetNetworkRequestMetric(firebase_perf_v1_PerfMetric *perfMetric, + firebase_perf_v1_NetworkRequestMetric networkMetric) { + perfMetric->network_request_metric = networkMetric; + perfMetric->has_network_request_metric = true; +} + +void FPRSetGaugeMetric(firebase_perf_v1_PerfMetric *perfMetric, + firebase_perf_v1_GaugeMetric gaugeMetric) { + perfMetric->gauge_metric = gaugeMetric; + perfMetric->has_gauge_metric = true; +} + +void FPRSetApplicationProcessState(firebase_perf_v1_PerfMetric *perfMetric, + firebase_perf_v1_ApplicationProcessState state) { + perfMetric->application_info.application_process_state = state; + perfMetric->application_info.has_application_process_state = true; +} diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.h new file mode 100644 index 0000000..e9d5874 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.h @@ -0,0 +1,43 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Allows the filtering of URLs based on a allowlist specified in the Info.plist. */ +@interface FPRURLFilter : NSObject + +/** Returns a singleton URL filterer. + * + * @return The singleton instance. */ ++ (instancetype)sharedInstance; + +/** Default initializer is disabled. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** Checks the allowlist and denylist, and returns a YES or NO depending on their state. + * + * @note The current implementation is very naive. The denylist is only set by the SDK, and these + * URLs will not be allowed, even if we explicitly allow them. + * + * @param URL The URL string to check. + * @return YES if the URL should be instrumented, NO otherwise. + */ +- (BOOL)shouldInstrumentURL:(NSString *)URL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.m new file mode 100644 index 0000000..529e405 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter.m @@ -0,0 +1,147 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/FPRURLFilter.h" +#import "FirebasePerformance/Sources/FPRURLFilter_Private.h" + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#import + +/** The expected key of the domain allowlist array. */ +static NSString *const kFPRAllowlistDomainsKey = @"FPRWhitelistedDomains"; + +/** Allowlist status enums. */ +typedef NS_ENUM(NSInteger, FPRURLAllowlistStatus) { + + /** No allowlist is present, so the URL will be allowed. */ + FPRURLAllowlistStatusDoesNotExist = 1, + + /** The URL is allowed. */ + FPRURLAllowlistStatusAllowed = 2, + + /** The URL is NOT allowed. */ + FPRURLAllowlistStatusNotAllowed = 3 +}; + +/** Returns the set of denied URL strings. + * + * @return the set of denied URL strings. + */ +NSSet *GetSystemDenyListURLStrings(void) { + // The denylist of URLs for uploading events to avoid cyclic generation of those network events. + static NSSet *denylist = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + denylist = [[NSSet alloc] initWithArray:@[ + [[GDTCOREndpoints uploadURLForTarget:kGDTCORTargetCCT] absoluteString], + [[GDTCOREndpoints uploadURLForTarget:kGDTCORTargetFLL] absoluteString] + ]]; + }); + return denylist; +} + +@implementation FPRURLFilter + ++ (instancetype)sharedInstance { + static FPRURLFilter *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[FPRURLFilter alloc] initWithBundle:[NSBundle mainBundle]]; + }); + return sharedInstance; +} + +- (instancetype)initWithBundle:(NSBundle *)bundle { + self = [super init]; + if (self) { + _mainBundle = bundle; + _allowlistDomains = [self retrieveAllowlistFromPlist]; + } + + return self; +} + +- (BOOL)shouldInstrumentURL:(NSString *)URL { + if ([self isURLDeniedByTheSDK:URL]) { + return NO; + } + FPRURLAllowlistStatus allowlistStatus = [self isURLAllowed:URL]; + if (allowlistStatus == FPRURLAllowlistStatusDoesNotExist) { + return YES; + } + return allowlistStatus == FPRURLAllowlistStatusAllowed; +} + +#pragma mark - Private helper methods + +/** Determines if the URL is denied by the SDK. + * + * @param URL the URL string to check. + * @return YES if the URL is allowed by the SDK, NO otherwise. + */ +- (BOOL)isURLDeniedByTheSDK:(NSString *)URL { + BOOL shouldDenyURL = NO; + + for (NSString *denyListURL in GetSystemDenyListURLStrings()) { + if ([URL hasPrefix:denyListURL]) { + shouldDenyURL = YES; + break; + } + } + + return shouldDenyURL; +} + +/** Determines if the URL is allowed by the Developer. + * + * @param URL The URL string to check. + * @return FPRURLAllowlistStatusAllowed if the URL is allowed, + * FPRURLAllowlistStatusNotAllowed if the URL is not allowed, or + * FPRURLAllowlistStatusDoesNotExist if the allowlist does not exist. + */ +- (FPRURLAllowlistStatus)isURLAllowed:(NSString *)URL { + if (self.allowlistDomains && !self.disablePlist) { + for (NSString *allowlistDomain in self.allowlistDomains) { + NSURLComponents *components = [[NSURLComponents alloc] initWithString:URL]; + if ([components.host containsString:allowlistDomain]) { + return FPRURLAllowlistStatusAllowed; + } + } + return FPRURLAllowlistStatusNotAllowed; + } + return FPRURLAllowlistStatusDoesNotExist; +} + +/** Retrieves the allowlist from an Info.plist. + * + * @return An array of the allowlist values, or nil if the allowlist key is not found. + */ +- (nullable NSArray *)retrieveAllowlistFromPlist { + NSArray *allowlist = nil; + id plistObject = [self.mainBundle objectForInfoDictionaryKey:kFPRAllowlistDomainsKey]; + if (!plistObject) { + NSBundle *localBundle = [NSBundle bundleForClass:[self class]]; + plistObject = [localBundle objectForInfoDictionaryKey:kFPRAllowlistDomainsKey]; + } + if ([plistObject isKindOfClass:[NSArray class]]) { + FPRLogInfo(kFPRURLAllowlistingEnabled, @"A domain allowlist was detected. Domains not " + "explicitly allowlisted will not be instrumented."); + allowlist = plistObject; + } + + return allowlist; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter_Private.h new file mode 100644 index 0000000..6a049a0 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/FPRURLFilter_Private.h @@ -0,0 +1,45 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This extension should only be used for testing. */ +@interface FPRURLFilter () + +/** Set to YES to disable the retrieval of allowed domains from the Info.plist. This property + * should only be used in tests in order to prevent the need for mocks. + */ +@property(nonatomic) BOOL disablePlist; + +/** List of domains that are allowed for instrumenting network requests. + */ +@property(nonatomic, readonly, nullable) NSArray *allowlistDomains; + +/** NSBundle that is used for referring to allowed domains. + */ +@property(nonatomic, readonly, nullable) NSBundle *mainBundle; + +/** Custom initializer to be used in unit tests for taking in a custom bundle and return an instance + * of FPRURLFilter. + * + * @param bundle Custom bundle to use for initialization. + * @return Instance of FPRURLFilter. + */ +- (instancetype)initWithBundle:(NSBundle *)bundle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector+Private.h new file mode 100644 index 0000000..0110a8b --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector+Private.h @@ -0,0 +1,39 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN FPRCPUGaugeData *fprCollectCPUMetric(void); + +/** This extension should only be used for testing. */ +@interface FPRCPUGaugeCollector () + +/** @brief Override configurations. */ +@property(nonatomic) FPRConfigurations *configurations; + +/** @brief Stop CPU data collection. */ +- (void)stopCollecting; + +/** @brief Resumes CPU data collection. */ +- (void)resumeCollecting; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h new file mode 100644 index 0000000..4a6b137 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h @@ -0,0 +1,64 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeCollector.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FPRCPUGaugeCollector; + +/** Delegate method for the CPU Gauge collector to report back the CPU gauge data. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@protocol FPRCPUGaugeCollectorDelegate + +/** + * Reports the collected CPU gauge data back to its delegate. + * + * @param collector CPU gauge collector that collected the information. + * @param gaugeData CPU gauge data. + */ +- (void)cpuGaugeCollector:(FPRCPUGaugeCollector *)collector gaugeData:(FPRCPUGaugeData *)gaugeData; + +@end + +/** CPU Gauge collector implementation. This class collects the CPU utilization and reports back + * to the delegate. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRCPUGaugeCollector : NSObject + +/** Reference to the delegate object. */ +@property(nonatomic, weak, readonly) id delegate; + +/** + * Initializes the CPU collector object with the delegate object provided. + * + * @param delegate Delegate object to which the CPU gauge data is provided. + * @return Instance of the CPU Gauge collector. + */ +- (instancetype)initWithDelegate:(id)delegate + NS_DESIGNATED_INITIALIZER; + +/** + * Initializer for the CPU Gauge collector. This is not available. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.m new file mode 100644 index 0000000..7e3742a --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.m @@ -0,0 +1,174 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h" +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector+Private.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#import +#import + +@interface FPRCPUGaugeCollector () + +/** @brief Timer property used for the frequency of CPU data collection. */ +@property(nonatomic) dispatch_source_t timerSource; + +/** @brief Gauge collector queue on which the gauge data collected. */ +@property(nonatomic) dispatch_queue_t gaugeCollectorQueue; + +/** @brief Boolean to see if the timer is active or paused. */ +@property(nonatomic) BOOL timerPaused; + +@end + +/** + * Fetches the CPU metric and returns an instance of FPRCPUGaugeData. + * + * This implementation is inspired by the following references: + * http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/thread_basic_info.html + * https://stackoverflow.com/a/8382889 + * + * @return Instance of FPRCPUGaugeData. + */ +FPRCPUGaugeData *fprCollectCPUMetric(void) { + kern_return_t kernelReturnValue; + mach_msg_type_number_t task_info_count; + task_info_data_t taskInfo; + thread_array_t threadList; + mach_msg_type_number_t threadCount; + task_basic_info_t taskBasicInfo; + thread_basic_info_t threadBasicInfo; + + NSDate *collectionTime = [NSDate date]; + // Get the task info to find out the CPU time used by terminated threads. + task_info_count = TASK_BASIC_INFO_COUNT; + kernelReturnValue = + task_info(mach_task_self(), TASK_BASIC_INFO, (task_info_t)taskInfo, &task_info_count); + if (kernelReturnValue != KERN_SUCCESS) { + return nil; + } + taskBasicInfo = (task_basic_info_t)taskInfo; + + // Get the current set of threads and find their CPU time. + kernelReturnValue = task_threads(mach_task_self(), &threadList, &threadCount); + if (kernelReturnValue != KERN_SUCCESS) { + return nil; + } + + uint64_t totalUserTimeUsec = + taskBasicInfo->user_time.seconds * USEC_PER_SEC + taskBasicInfo->user_time.microseconds; + uint64_t totalSystemTimeUsec = + taskBasicInfo->system_time.seconds * USEC_PER_SEC + taskBasicInfo->system_time.microseconds; + thread_info_data_t threadInfo; + mach_msg_type_number_t threadInfoCount; + + for (int i = 0; i < (int)threadCount; i++) { + threadInfoCount = THREAD_INFO_MAX; + kernelReturnValue = + thread_info(threadList[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount); + if (kernelReturnValue != KERN_SUCCESS) { + return nil; + } + + threadBasicInfo = (thread_basic_info_t)threadInfo; + if (!(threadBasicInfo->flags & TH_FLAGS_IDLE)) { + totalUserTimeUsec += threadBasicInfo->user_time.seconds * USEC_PER_SEC + + threadBasicInfo->user_time.microseconds; + totalSystemTimeUsec += threadBasicInfo->system_time.seconds * USEC_PER_SEC + + threadBasicInfo->system_time.microseconds; + } + } + + kernelReturnValue = + vm_deallocate(mach_task_self(), (vm_offset_t)threadList, threadCount * sizeof(thread_t)); + assert(kernelReturnValue == KERN_SUCCESS); + + FPRCPUGaugeData *gaugeData = [[FPRCPUGaugeData alloc] initWithCollectionTime:collectionTime + systemTime:totalSystemTimeUsec + userTime:totalUserTimeUsec]; + return gaugeData; +} + +@implementation FPRCPUGaugeCollector + +- (instancetype)initWithDelegate:(id)delegate { + self = [super init]; + if (self) { + _delegate = delegate; + _gaugeCollectorQueue = + dispatch_queue_create("com.google.firebase.FPRCPUGaugeCollector", DISPATCH_QUEUE_SERIAL); + _configurations = [FPRConfigurations sharedInstance]; + _timerPaused = YES; + [self updateSamplingFrequencyForApplicationState:[FPRAppActivityTracker sharedInstance] + .applicationState]; + } + return self; +} + +- (void)stopCollecting { + if (self.timerPaused == NO) { + dispatch_source_cancel(self.timerSource); + self.timerPaused = YES; + } +} + +- (void)resumeCollecting { + [self updateSamplingFrequencyForApplicationState:[FPRAppActivityTracker sharedInstance] + .applicationState]; +} + +- (void)updateSamplingFrequencyForApplicationState:(FPRApplicationState)applicationState { + uint32_t frequencyInMs = (applicationState == FPRApplicationStateBackground) + ? [self.configurations cpuSamplingFrequencyInBackgroundInMS] + : [self.configurations cpuSamplingFrequencyInForegroundInMS]; + [self captureCPUGaugeAtFrequency:frequencyInMs]; +} + +/** + * Captures the CPU gauge at a defined frequency. + * + * @param frequencyInMs Frequency at which the CPU gauges are collected. + */ +- (void)captureCPUGaugeAtFrequency:(uint32_t)frequencyInMs { + [self stopCollecting]; + if (frequencyInMs > 0) { + self.timerSource = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.gaugeCollectorQueue); + dispatch_source_set_timer(self.timerSource, + dispatch_time(DISPATCH_TIME_NOW, frequencyInMs * NSEC_PER_MSEC), + frequencyInMs * NSEC_PER_MSEC, (1ull * NSEC_PER_SEC) / 10); + FPRCPUGaugeCollector __weak *weakSelf = self; + dispatch_source_set_event_handler(weakSelf.timerSource, ^{ + FPRCPUGaugeCollector *strongSelf = weakSelf; + if (strongSelf) { + [strongSelf collectMetric]; + } + }); + dispatch_resume(self.timerSource); + self.timerPaused = NO; + } else { + FPRLogDebug(kFPRCPUCollection, @"CPU metric collection is disabled."); + } +} + +- (void)collectMetric { + FPRCPUGaugeData *gaugeMetric = fprCollectCPUMetric(); + [self.delegate cpuGaugeCollector:self gaugeData:gaugeMetric]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h new file mode 100644 index 0000000..7d28081 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h @@ -0,0 +1,49 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Class that contains CPU gauge information for any point in time. + */ +@interface FPRCPUGaugeData : NSObject + +/** @brief Time which which CPU data was measured. */ +@property(nonatomic, readonly) NSDate *collectionTime; + +/** @brief CPU system time used in microseconds. */ +@property(nonatomic, readonly) uint64_t systemTime; + +/** @brief CPU user time used in microseconds. */ +@property(nonatomic, readonly) uint64_t userTime; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates an instance of CPU gauge data with the provided information. + * + * @param collectionTime Time at which the gauge data was collected. + * @param systemTime CPU system time in microseconds. + * @param userTime CPU user time in microseconds. + * @return Instance of CPU gauge data. + */ +- (instancetype)initWithCollectionTime:(NSDate *)collectionTime + systemTime:(uint64_t)systemTime + userTime:(uint64_t)userTime NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.m new file mode 100644 index 0000000..a713b58 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.m @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h" + +@implementation FPRCPUGaugeData + +- (instancetype)initWithCollectionTime:(NSDate *)collectionTime + systemTime:(uint64_t)systemTime + userTime:(uint64_t)userTime { + self = [super init]; + if (self) { + _collectionTime = collectionTime; + _systemTime = systemTime; + _userTime = userTime; + } + return self; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeCollector.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeCollector.h new file mode 100644 index 0000000..9f03bb3 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeCollector.h @@ -0,0 +1,34 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" + +@protocol FPRGaugeCollector + +/** Initiates a fetch for the gauge metric. */ +- (void)collectMetric; + +/** + * Adapts to application state and starts capturing the gauge metric at a pre-configured rate as + * defined in the configuration system. + * + * @note Call this method when the application state has changed. + * + * @param applicationState Application state. + */ +- (void)updateSamplingFrequencyForApplicationState:(FPRApplicationState)applicationState; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager+Private.h new file mode 100644 index 0000000..175389c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager+Private.h @@ -0,0 +1,51 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" + +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h" + +/** This extension should only be used for testing. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRGaugeManager () + +/** @brief Tracks if gauge collection is enabled. */ +@property(nonatomic, readonly) BOOL gaugeCollectionEnabled; + +/** @brief CPU gauge collector. */ +@property(nonatomic, readwrite, nullable) FPRCPUGaugeCollector *cpuGaugeCollector; + +/** @brief Memory gauge collector. */ +@property(nonatomic, readwrite, nullable) FPRMemoryGaugeCollector *memoryGaugeCollector; + +/** @brief Serial queue to manage gauge data collection. */ +@property(nonatomic, readwrite, nonnull) dispatch_queue_t gaugeDataProtectionQueue; + +/** @brief Tracks if this session is a cold start of the application. */ +@property(nonatomic) BOOL isColdStart; + +/** + * Creates an instance of FPRGaugeManager with the gauges required. + */ +- (nonnull instancetype)initWithGauges:(FPRGauges)gauges; + +/** + * Prepares for dispatching the current set of gauge data to Google Data Transport. + * + * @param sessionId SessionId that will be used for dispatching the gauge data + */ +- (void)prepareAndDispatchCollectedGaugeDataWithSessionId:(nullable NSString *)sessionId; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.h new file mode 100644 index 0000000..9057b7e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.h @@ -0,0 +1,79 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSInteger const kGaugeDataBatchSize; + +/** List of gauges the gauge manager controls. */ +typedef NS_OPTIONS(NSUInteger, FPRGauges) { + FPRGaugeNone = 0, + FPRGaugeCPU = (1 << 0), + FPRGaugeMemory = (1 << 1), +}; + +/** This class controls different gauge collection in the system. List of the gauges this class + manages are listed above. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRGaugeManager : NSObject + +/** @brief List of gauges that are currently being actively captured. */ +@property(nonatomic, readonly) FPRGauges activeGauges; + +/** + * Creates an instance of GaugeManager. + * + * @return Instance of GaugeManager. + */ ++ (instancetype)sharedInstance; + +/** + * Initializer for the gauge manager. This is not available. + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Starts collecting gauge metrics for the specified set of gauges. Calling this will dispatch all + * the currently existing gauge data and will start collecting the new data with the new sessionId. + * + * @param gauges Gauges that needs to be collected. + * @param sessionId SessionId for which the gauges are collected. + */ +- (void)startCollectingGauges:(FPRGauges)gauges forSessionId:(NSString *)sessionId; + +/** + * Stops collecting gauge metrics for the specified set of gauges. Calling this will dispatch all + * the existing gauge data. + * + * @param gauges Gauges that needs to be stopped collecting. + */ +- (void)stopCollectingGauges:(FPRGauges)gauges; + +/** + * Collects all the gauges. + */ +- (void)collectAllGauges; + +/** + * Takes a gauge metric and tries to dispatch the gauge metric. + * + * @param gaugeMetric Gauge metric that needs to be dispatched. + */ +- (void)dispatchMetric:(id)gaugeMetric; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.m new file mode 100644 index 0000000..7f28902 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/FPRGaugeManager.m @@ -0,0 +1,223 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager+Private.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h" + +#import + +// Number of gauge data information after which that gets flushed to Google Data Transport. +NSInteger const kGaugeDataBatchSize = 25; + +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRGaugeManager () + +/** @brief List of gauges that are currently being actively captured. */ +@property(nonatomic, readwrite) FPRGauges activeGauges; + +/** @brief List of gauge information collected. Intentionally this is not a typed collection. Gauge + * data could be CPU Gauge data or Memory gauge data. + */ +@property(nonatomic) NSMutableArray *gaugeData; + +/** @brief Currently active sessionID. */ +@property(nonatomic, readwrite, copy) NSString *currentSessionId; + +@end + +@implementation FPRGaugeManager + ++ (instancetype)sharedInstance { + static FPRGaugeManager *instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + instance = [[FPRGaugeManager alloc] initWithGauges:FPRGaugeNone]; + }); + return instance; +} + +- (instancetype)initWithGauges:(FPRGauges)gauges { + self = [super init]; + if (self) { + _activeGauges = FPRGaugeNone; + _gaugeData = [[NSMutableArray alloc] init]; + _gaugeDataProtectionQueue = + dispatch_queue_create("com.google.perf.gaugeManager.gaugeData", DISPATCH_QUEUE_SERIAL); + _isColdStart = YES; + [self startAppActivityTracking]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] removeObserver:self + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; +} + +/** + * Starts tracking the application state changes. + */ +- (void)startAppActivityTracking { + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appStateChanged:) + name:UIApplicationDidBecomeActiveNotification + object:[UIApplication sharedApplication]]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(appStateChanged:) + name:UIApplicationWillResignActiveNotification + object:[UIApplication sharedApplication]]; +} + +- (void)appStateChanged:(NSNotification *)notification { + FPRApplicationState applicationState = [FPRAppActivityTracker sharedInstance].applicationState; + [self.cpuGaugeCollector updateSamplingFrequencyForApplicationState:applicationState]; + [self.memoryGaugeCollector updateSamplingFrequencyForApplicationState:applicationState]; + self.isColdStart = NO; +} + +#pragma mark - Implementation methods + +- (BOOL)gaugeCollectionEnabled { + // Allow gauge collection to happen during cold start. During dispatch time, we do another check + // to make sure if gauge collection is enabled. This is to accommodate gauge metric collection + // during app_start scenario. + if (self.isColdStart) { + return YES; + } + + // Check if the SDK is enabled to collect gauge data. + BOOL sdkEnabled = [[FPRConfigurations sharedInstance] sdkEnabled]; + if (!sdkEnabled) { + return NO; + } + + return [FPRConfigurations sharedInstance].isDataCollectionEnabled; +} + +- (void)startCollectingGauges:(FPRGauges)gauges forSessionId:(NSString *)sessionId { + // Dispatch the already available gauge data with old sessionId. + [self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId]; + + self.currentSessionId = sessionId; + if (self.gaugeCollectionEnabled) { + if ((gauges & FPRGaugeCPU) == FPRGaugeCPU) { + self.cpuGaugeCollector = [[FPRCPUGaugeCollector alloc] initWithDelegate:self]; + } + if ((gauges & FPRGaugeMemory) == FPRGaugeMemory) { + self.memoryGaugeCollector = [[FPRMemoryGaugeCollector alloc] initWithDelegate:self]; + } + + self.activeGauges = self.activeGauges | gauges; + } +} + +- (void)stopCollectingGauges:(FPRGauges)gauges { + if ((gauges & FPRGaugeCPU) == FPRGaugeCPU) { + self.cpuGaugeCollector = nil; + } + + if ((gauges & FPRGaugeMemory) == FPRGaugeMemory) { + self.memoryGaugeCollector = nil; + } + + self.activeGauges = self.activeGauges & ~(gauges); + + // Flush out all the already collected gauge metrics + [self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId]; +} + +- (void)collectAllGauges { + if (self.cpuGaugeCollector) { + [self.cpuGaugeCollector collectMetric]; + } + + if (self.memoryGaugeCollector) { + [self.memoryGaugeCollector collectMetric]; + } +} + +- (void)dispatchMetric:(id)gaugeMetric { + // If the gauge metric is of type CPU, then dispatch only if CPU collection is enabled. + if ([gaugeMetric isKindOfClass:[FPRCPUGaugeData class]] && + ((self.activeGauges & FPRGaugeCPU) == FPRGaugeCPU)) { + [self addGaugeData:gaugeMetric]; + } + + // If the gauge metric is of type memory, then dispatch only if memory collection is enabled. + if ([gaugeMetric isKindOfClass:[FPRMemoryGaugeData class]] && + ((self.activeGauges & FPRGaugeMemory) == FPRGaugeMemory)) { + [self addGaugeData:gaugeMetric]; + } +} + +#pragma mark - Utils + +- (void)prepareAndDispatchCollectedGaugeDataWithSessionId:(nullable NSString *)sessionId { + dispatch_async(self.gaugeDataProtectionQueue, ^{ + NSArray *dispatchGauges = [self.gaugeData copy]; + self.gaugeData = [[NSMutableArray alloc] init]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + if (dispatchGauges.count > 0 && sessionId != nil) { + [[FPRClient sharedInstance] logGaugeMetric:dispatchGauges forSessionId:sessionId]; + FPRLogInfo(kFPRGaugeManagerDataCollected, @"Logging %lu gauge metrics.", + (unsigned long)dispatchGauges.count); + } + }); + }); +} + +/** + * Adds the gauge to the batch and decide on when to dispatch the events to Google Data Transport. + * + * @param gauge Gauge data received from the collectors. + */ +- (void)addGaugeData:(id)gauge { + dispatch_async(self.gaugeDataProtectionQueue, ^{ + if (gauge) { + [self.gaugeData addObject:gauge]; + + if (self.gaugeData.count >= kGaugeDataBatchSize) { + [self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId]; + } + } + }); +} + +#pragma mark - FPRCPUGaugeCollectorDelegate methods + +- (void)cpuGaugeCollector:(FPRCPUGaugeCollector *)collector gaugeData:(FPRCPUGaugeData *)gaugeData { + [self addGaugeData:gaugeData]; +} + +#pragma mark - FPRMemoryGaugeCollectorDelegate methods + +- (void)memoryGaugeCollector:(FPRMemoryGaugeCollector *)collector + gaugeData:(FPRMemoryGaugeData *)gaugeData { + [self addGaugeData:gaugeData]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector+Private.h new file mode 100644 index 0000000..2333fab --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector+Private.h @@ -0,0 +1,39 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN FPRMemoryGaugeData *fprCollectMemoryMetric(void); + +/** This extension should only be used for testing. */ +@interface FPRMemoryGaugeCollector () + +/** @brief Override configurations. */ +@property(nonatomic) FPRConfigurations *configurations; + +/** @brief Stop memory data collection. */ +- (void)stopCollecting; + +/** @brief Resumes memory data collection. */ +- (void)resumeCollecting; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h new file mode 100644 index 0000000..a001081 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/Gauges/FPRGaugeCollector.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h" + +NS_ASSUME_NONNULL_BEGIN + +@class FPRMemoryGaugeCollector; + +/** Delegate method for the memory Gauge collector to report back the memory gauge data. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@protocol FPRMemoryGaugeCollectorDelegate + +/** + * Reports the collected memory gauge data back to its delegate. + * + * @param collector memory gauge collector that collected the information. + * @param gaugeData memory gauge data. + */ +- (void)memoryGaugeCollector:(FPRMemoryGaugeCollector *)collector + gaugeData:(FPRMemoryGaugeData *)gaugeData; + +@end + +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRMemoryGaugeCollector : NSObject + +/** Reference to the delegate object. */ +@property(nonatomic, weak, readonly) id delegate; + +/** + * Initializes the memory collector object with the delegate object provided. + * + * @param delegate Delegate object to which the memory gauge data is provided. + * @return Instance of the memory gauge collector. + */ +- (instancetype)initWithDelegate:(id)delegate + NS_DESIGNATED_INITIALIZER; + +/** + * Initializer for the memory Gauge collector. This is not available. + */ +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m new file mode 100644 index 0000000..7c4104d --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.m @@ -0,0 +1,116 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h" +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector+Private.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" + +#include + +@interface FPRMemoryGaugeCollector () + +/** @brief Timer property used for the frequency of CPU data collection. */ +@property(nonatomic) dispatch_source_t timerSource; + +/** @brief Gauge collector queue on which the gauge data collected. */ +@property(nonatomic) dispatch_queue_t gaugeCollectorQueue; + +/** @brief Boolean to see if the timer is active or paused. */ +@property(nonatomic) BOOL timerPaused; + +@end + +FPRMemoryGaugeData *fprCollectMemoryMetric(void) { + NSDate *collectionTime = [NSDate date]; + + struct mstats ms = mstats(); + FPRMemoryGaugeData *gaugeData = [[FPRMemoryGaugeData alloc] initWithCollectionTime:collectionTime + heapUsed:ms.bytes_used + heapAvailable:ms.bytes_free]; + return gaugeData; +} + +@implementation FPRMemoryGaugeCollector + +- (instancetype)initWithDelegate:(id)delegate { + self = [super init]; + if (self) { + _delegate = delegate; + _gaugeCollectorQueue = + dispatch_queue_create("com.google.firebase.FPRMemoryGaugeCollector", DISPATCH_QUEUE_SERIAL); + _configurations = [FPRConfigurations sharedInstance]; + _timerPaused = YES; + [self updateSamplingFrequencyForApplicationState:[FPRAppActivityTracker sharedInstance] + .applicationState]; + } + return self; +} + +- (void)stopCollecting { + if (self.timerPaused == NO) { + dispatch_source_cancel(self.timerSource); + self.timerPaused = YES; + } +} + +- (void)resumeCollecting { + [self updateSamplingFrequencyForApplicationState:[FPRAppActivityTracker sharedInstance] + .applicationState]; +} + +- (void)updateSamplingFrequencyForApplicationState:(FPRApplicationState)applicationState { + uint32_t frequencyInMs = (applicationState == FPRApplicationStateBackground) + ? [self.configurations memorySamplingFrequencyInBackgroundInMS] + : [self.configurations memorySamplingFrequencyInForegroundInMS]; + [self captureMemoryGaugeAtFrequency:frequencyInMs]; +} + +#pragma mark - Internal methods. + +/** + * Captures the memory gauge at a defined frequency. + * + * @param frequencyInMs Frequency at which the memory gauges are collected. + */ +- (void)captureMemoryGaugeAtFrequency:(uint32_t)frequencyInMs { + [self stopCollecting]; + if (frequencyInMs > 0) { + self.timerSource = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self.gaugeCollectorQueue); + dispatch_source_set_timer(self.timerSource, + dispatch_time(DISPATCH_TIME_NOW, frequencyInMs * NSEC_PER_MSEC), + frequencyInMs * NSEC_PER_MSEC, (1ull * NSEC_PER_SEC) / 10); + FPRMemoryGaugeCollector __weak *weakSelf = self; + dispatch_source_set_event_handler(weakSelf.timerSource, ^{ + FPRMemoryGaugeCollector *strongSelf = weakSelf; + if (strongSelf) { + [strongSelf collectMetric]; + } + }); + dispatch_resume(self.timerSource); + self.timerPaused = NO; + } else { + FPRLogDebug(kFPRMemoryCollection, @"Memory metric collection is disabled."); + } +} + +- (void)collectMetric { + FPRMemoryGaugeData *gaugeMetric = fprCollectMemoryMetric(); + [self.delegate memoryGaugeCollector:self gaugeData:gaugeMetric]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h new file mode 100644 index 0000000..747a4aa --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h @@ -0,0 +1,49 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * Class that contains memory gauge information for any point in time. + */ +@interface FPRMemoryGaugeData : NSObject + +/** @brief Time at which memory data was measured. */ +@property(nonatomic, readonly) NSDate *collectionTime; + +/** @brief Heap memory that is used. */ +@property(nonatomic, readonly) u_long heapUsed; + +/** @brief Heap memory that is available. */ +@property(nonatomic, readonly) u_long heapAvailable; + +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates an instance of memory gauge data with the provided information. + * + * @param collectionTime Time at which the gauge data was collected. + * @param heapUsed Heap memory that is used. + * @param heapAvailable Heap memory that is available. + * @return Instance of memory gauge data. + */ +- (instancetype)initWithCollectionTime:(NSDate *)collectionTime + heapUsed:(u_long)heapUsed + heapAvailable:(u_long)heapAvailable NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.m new file mode 100644 index 0000000..2c3cd84 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.m @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h" + +@implementation FPRMemoryGaugeData + +- (instancetype)initWithCollectionTime:(NSDate *)collectionTime + heapUsed:(u_long)heapUsed + heapAvailable:(u_long)heapAvailable { + self = [super init]; + if (self) { + _collectionTime = collectionTime; + _heapUsed = heapUsed; + _heapAvailable = heapAvailable; + } + return self; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler+Internal.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler+Internal.h new file mode 100644 index 0000000..0b8f538 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler+Internal.h @@ -0,0 +1,23 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" + +FOUNDATION_EXPORT const NSString *const kGULSwizzlerAssociatedObjectKey; + +@interface FPRObjectSwizzler (Internal) + +- (void)swizzledObjectHasBeenDeallocatedWithGeneratedSubclass:(BOOL)isInstanceOfGeneratedSubclass; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h new file mode 100644 index 0000000..b4a51d6 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h @@ -0,0 +1,123 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** Enums that map to their OBJC-prefixed counterparts. */ +typedef OBJC_ENUM(uintptr_t, GUL_ASSOCIATION){ + + // Is a weak association. + GUL_ASSOCIATION_ASSIGN, + + // Is a nonatomic strong association. + GUL_ASSOCIATION_RETAIN_NONATOMIC, + + // Is a nonatomic copy association. + GUL_ASSOCIATION_COPY_NONATOMIC, + + // Is an atomic strong association. + GUL_ASSOCIATION_RETAIN, + + // Is an atomic copy association. + GUL_ASSOCIATION_COPY}; + +/** This class handles swizzling a specific instance of a class by generating a + * dynamic subclass and installing selectors and properties onto the dynamic + * subclass. Then, the instance's class is set to the dynamic subclass. There + * should be a 1:1 ratio of object swizzlers to swizzled instances. + */ +@interface FPRObjectSwizzler : NSObject + +/** The subclass that is generated. */ +@property(nullable, nonatomic, readonly) Class generatedClass; + +/** Sets an associated object in the runtime. This mechanism can be used to + * simulate adding properties. + * + * @param object The object that will be queried for the associated object. + * @param key The key of the associated object. + * @param value The value to associate to the swizzled object. + * @param association The mechanism to use when associating the objects. + */ ++ (void)setAssociatedObject:(id)object + key:(const void *)key + value:(nullable id)value + association:(GUL_ASSOCIATION)association; + +/** Gets an associated object in the runtime. This mechanism can be used to + * simulate adding properties. + * + * @param object The object that will be queried for the associated object. + * @param key The key of the associated object. + */ ++ (nullable id)getAssociatedObject:(id)object key:(const void *)key; + +/** Please use the designated initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** Instantiates an object swizzler using an object it will operate on. + * Generates a new class pair. + * + * @note There is no need to store this object. After calling -swizzle, this + * object can be found by calling -gul_objectSwizzler + * + * @param object The object to be swizzled. + * @return An instance of this class. + */ +- (instancetype)initWithObject:(id)object NS_DESIGNATED_INITIALIZER; + +/** Sets an associated object in the runtime. This mechanism can be used to + * simulate adding properties. + * + * @param key The key of the associated object. + * @param value The value to associate to the swizzled object. + * @param association The mechanism to use when associating the objects. + */ +- (void)setAssociatedObjectWithKey:(const void *)key + value:(id)value + association:(GUL_ASSOCIATION)association; + +/** Gets an associated object in the runtime. This mechanism can be used to + * simulate adding properties. + * + * @param key The key of the associated object. + */ +- (nullable id)getAssociatedObjectForKey:(const void *)key; + +/** Copies a selector from an existing class onto the generated dynamic subclass + * that this object will adopt. This mechanism can be used to add methods to + * specific instances of a class. + * + * @note Should not be called after calling -swizzle. + * @param selector The selector to add to the instance. + * @param aClass The class supplying an implementation of the method. + * @param isClassSelector A BOOL specifying whether the selector is a class or + * instance selector. + */ +- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector; + +/** Swizzles the object, changing its class to the generated class. Registers + * the class pair. */ +- (void)swizzle; + +/** @return The value of -[objectBeingSwizzled isProxy] */ +- (BOOL)isSwizzlingProxyObject; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.m new file mode 100644 index 0000000..f9b54a4 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.m @@ -0,0 +1,212 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" + +#import + +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler+Internal.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h" + +@implementation FPRObjectSwizzler { + // The swizzled object. + __weak id _swizzledObject; + + // The original class of the object. + Class _originalClass; + + // The dynamically generated subclass of _originalClass. + Class _generatedClass; +} + +#pragma mark - Class methods + ++ (void)setAssociatedObject:(id)object + key:(const void *)key + value:(nullable id)value + association:(GUL_ASSOCIATION)association { + objc_AssociationPolicy resolvedAssociation; + switch (association) { + case GUL_ASSOCIATION_ASSIGN: + resolvedAssociation = OBJC_ASSOCIATION_ASSIGN; + break; + + case GUL_ASSOCIATION_RETAIN_NONATOMIC: + resolvedAssociation = OBJC_ASSOCIATION_RETAIN_NONATOMIC; + break; + + case GUL_ASSOCIATION_COPY_NONATOMIC: + resolvedAssociation = OBJC_ASSOCIATION_COPY_NONATOMIC; + break; + + case GUL_ASSOCIATION_RETAIN: + resolvedAssociation = OBJC_ASSOCIATION_RETAIN; + break; + + case GUL_ASSOCIATION_COPY: + resolvedAssociation = OBJC_ASSOCIATION_COPY; + break; + + default: + break; + } + objc_setAssociatedObject(object, key, value, resolvedAssociation); +} + ++ (nullable id)getAssociatedObject:(id)object key:(const void *)key { + return objc_getAssociatedObject(object, key); +} + +#pragma mark - Instance methods + +/** Instantiates an instance of this class. + * + * @param object The object to swizzle. + * @return An instance of this class. + */ +- (instancetype)initWithObject:(id)object { + if (object == nil) { + return nil; + } + + FPRObjectSwizzler *existingSwizzler = + [[self class] getAssociatedObject:object key:&kGULSwizzlerAssociatedObjectKey]; + if ([existingSwizzler isKindOfClass:[FPRObjectSwizzler class]]) { + // The object has been swizzled already, no need to swizzle again. + return existingSwizzler; + } + + self = [super init]; + if (self) { + _swizzledObject = object; + _originalClass = object_getClass(object); + NSString *newClassName = [NSString stringWithFormat:@"fir_%@_%@", [[NSUUID UUID] UUIDString], + NSStringFromClass(_originalClass)]; + _generatedClass = objc_allocateClassPair(_originalClass, newClassName.UTF8String, 0); + NSAssert(_generatedClass, @"Wasn't able to allocate the class pair."); + } + return self; +} + +- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { + NSAssert(_generatedClass, @"This object has already been unswizzled."); + Method method = isClassSelector ? class_getClassMethod(aClass, selector) + : class_getInstanceMethod(aClass, selector); + Class targetClass = isClassSelector ? object_getClass(_generatedClass) : _generatedClass; + IMP implementation = method_getImplementation(method); + + const char *typeEncoding = method_getTypeEncoding(method); + class_replaceMethod(targetClass, selector, implementation, typeEncoding); +} + +- (void)setAssociatedObjectWithKey:(const void *)key + value:(id)value + association:(GUL_ASSOCIATION)association { + __strong id swizzledObject = _swizzledObject; + if (swizzledObject) { + [[self class] setAssociatedObject:swizzledObject key:key value:value association:association]; + } +} + +- (nullable id)getAssociatedObjectForKey:(const void *)key { + __strong id swizzledObject = _swizzledObject; + if (swizzledObject) { + return [[self class] getAssociatedObject:swizzledObject key:key]; + } + return nil; +} + +- (void)swizzle { + __strong id swizzledObject = _swizzledObject; + FPRObjectSwizzler *existingSwizzler = + [[self class] getAssociatedObject:swizzledObject key:&kGULSwizzlerAssociatedObjectKey]; + if (existingSwizzler != nil) { + NSAssert(existingSwizzler == self, @"The swizzled object has a different swizzler."); + // The object has been swizzled already. + return; + } + + if (swizzledObject) { + [FPRObjectSwizzler setAssociatedObject:swizzledObject + key:&kGULSwizzlerAssociatedObjectKey + value:self + association:GUL_ASSOCIATION_RETAIN]; + + [FPRSwizzledObject copyDonorSelectorsUsingObjectSwizzler:self]; + + NSAssert(_originalClass == object_getClass(swizzledObject), + @"The original class is not the reported class now."); + NSAssert(class_getInstanceSize(_originalClass) == class_getInstanceSize(_generatedClass), + @"The instance size of the generated class must be equal to the original class."); + objc_registerClassPair(_generatedClass); + Class doubleCheckOriginalClass __unused = object_setClass(_swizzledObject, _generatedClass); + NSAssert(_originalClass == doubleCheckOriginalClass, + @"The original class must be the same as the class returned by object_setClass"); + } else { + NSAssert(NO, @"You can't swizzle a nil object"); + } +} + +- (void)dealloc { + // When the Zombies instrument is enabled, a zombie is created for the swizzled object upon + // deallocation. Because this zombie subclasses the generated class, the swizzler should not + // dispose it during the swizzler's deallocation. + // + // There are other special cases where the generated class might be subclassed by a third-party + // generated classes, for example: https://github.com/firebase/firebase-ios-sdk/issues/9083 + // To avoid errors in such cases, the environment variable `GULGeneratedClassDisposeDisabled` can + // be set with `YES`. + NSDictionary *environment = [[NSProcessInfo processInfo] environment]; + if ([[environment objectForKey:@"NSZombieEnabled"] boolValue] || + [[environment objectForKey:@"GULGeneratedClassDisposeDisabled"] boolValue]) { + return; + } + + if (_generatedClass) { + if (_swizzledObject == nil) { + // The swizzled object has been deallocated already, so the generated class can be disposed + // now. + objc_disposeClassPair(_generatedClass); + return; + } + + // FPRSwizzledObject is retained by the swizzled object which means that the swizzled object is + // being deallocated now. Let's see if we should schedule the generated class disposal. + + // If the swizzled object has a different class, it most likely indicates that the object was + // ISA swizzled one more time. In this case it is not safe to dispose the generated class. We + // will have to keep it to prevent a crash. + + // TODO: Consider adding a flag that can be set by the host application to dispose the class + // pair unconditionally. It may be used by apps that use ISA Swizzling themself and are + // confident in disposing their subclasses. + BOOL isSwizzledObjectInstanceOfGeneratedClass = + object_getClass(_swizzledObject) == _generatedClass; + + if (isSwizzledObjectInstanceOfGeneratedClass) { + Class generatedClass = _generatedClass; + + // Schedule the generated class disposal after the swizzled object has been deallocated. + dispatch_async(dispatch_get_main_queue(), ^{ + objc_disposeClassPair(generatedClass); + }); + } + } +} + +- (BOOL)isSwizzlingProxyObject { + return [_swizzledObject isProxy]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h new file mode 100644 index 0000000..353e818 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h @@ -0,0 +1,46 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@class FPRObjectSwizzler; + +/** This class exists as a method donor. These methods will be added to all objects that are + * swizzled by the object swizzler. This class should not be instantiated. + */ +@interface FPRSwizzledObject : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Copies the methods below to the swizzled object. + * + * @param objectSwizzler The swizzler to use when adding the methods below. + */ ++ (void)copyDonorSelectorsUsingObjectSwizzler:(FPRObjectSwizzler *)objectSwizzler; + +#pragma mark - Donor methods. + +/** @return The generated subclass. Used in respondsToSelector: calls. */ +- (Class)gul_class; + +/** @return The object swizzler that manages this object. */ +- (FPRObjectSwizzler *)gul_objectSwizzler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.m new file mode 100644 index 0000000..f7c5b1e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.m @@ -0,0 +1,64 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler+Internal.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h" + +const NSString *const kGULSwizzlerAssociatedObjectKey = @"gul_objectSwizzler"; + +@interface FPRSwizzledObject () + +@end + +@implementation FPRSwizzledObject + ++ (void)copyDonorSelectorsUsingObjectSwizzler:(FPRObjectSwizzler *)objectSwizzler { + [objectSwizzler copySelector:@selector(gul_objectSwizzler) fromClass:self isClassSelector:NO]; + [objectSwizzler copySelector:@selector(gul_class) fromClass:self isClassSelector:NO]; + + // This is needed because NSProxy objects usually override -[NSObjectProtocol respondsToSelector:] + // and ask this question to the underlying object. Since we don't swizzle the underlying object + // but swizzle the proxy, when someone calls -[NSObjectProtocol respondsToSelector:] on the proxy, + // the answer ends up being NO even if we added new methods to the subclass through ISA Swizzling. + // To solve that, we override -[NSObjectProtocol respondsToSelector:] in such a way that takes + // into account the fact that we've added new methods. + if ([objectSwizzler isSwizzlingProxyObject]) { + [objectSwizzler copySelector:@selector(respondsToSelector:) fromClass:self isClassSelector:NO]; + } +} + +- (instancetype)init { + NSAssert(NO, @"Do not instantiate this class, it's only a donor class"); + return nil; +} + +- (FPRObjectSwizzler *)gul_objectSwizzler { + return [FPRObjectSwizzler getAssociatedObject:self key:&kGULSwizzlerAssociatedObjectKey]; +} + +#pragma mark - Donor methods + +- (Class)gul_class { + return [[self gul_objectSwizzler] generatedClass]; +} + +// Only added to a class when we detect it is a proxy. +- (BOOL)respondsToSelector:(SEL)aSelector { + Class gulClass = [[self gul_objectSwizzler] generatedClass]; + return [gulClass instancesRespondToSelector:aSelector] || [super respondsToSelector:aSelector]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric+Private.h new file mode 100644 index 0000000..9422879 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric+Private.h @@ -0,0 +1,37 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +/** + * Extension that is added on top of the class FIRHTTPMetric to make the private properties visible + * between the implementation file and the unit tests. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FIRHTTPMetric () + +/* Network trace to capture the HTTPMetric information. */ +@property(nonatomic, strong) FPRNetworkTrace *networkTrace; + +/** + * Marks the end time of the request. + */ +- (void)markRequestComplete; + +/** + * Marks the start time of the response. + */ +- (void)markResponseStart; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric.m new file mode 100644 index 0000000..93263d4 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric.m @@ -0,0 +1,155 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRHTTPMetric.h" +#import "FirebasePerformance/Sources/Instrumentation/FIRHTTPMetric+Private.h" + +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/FPRDataUtils.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +@interface FIRHTTPMetric () + +/* A placeholder URLRequest used for SDK metric tracking. */ +@property(nonatomic, strong) NSURLRequest *URLRequest; + +@end + +@implementation FIRHTTPMetric + +- (nullable instancetype)initWithURL:(nonnull NSURL *)URL HTTPMethod:(FIRHTTPMethod)httpMethod { + BOOL tracingEnabled = [FPRConfigurations sharedInstance].isDataCollectionEnabled; + if (!tracingEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Trace feature is disabled. Dropping http metric - %@", + URL.absoluteString); + return nil; + } + + BOOL sdkEnabled = [[FPRConfigurations sharedInstance] sdkEnabled]; + if (!sdkEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Dropping event since Performance SDK is disabled."); + return nil; + } + + NSMutableURLRequest *URLRequest = [[NSMutableURLRequest alloc] initWithURL:URL]; + NSString *HTTPMethodString = nil; + switch (httpMethod) { + case FIRHTTPMethodGET: + HTTPMethodString = @"GET"; + break; + + case FIRHTTPMethodPUT: + HTTPMethodString = @"PUT"; + break; + + case FIRHTTPMethodPOST: + HTTPMethodString = @"POST"; + break; + + case FIRHTTPMethodHEAD: + HTTPMethodString = @"HEAD"; + break; + + case FIRHTTPMethodDELETE: + HTTPMethodString = @"DELETE"; + break; + + case FIRHTTPMethodPATCH: + HTTPMethodString = @"PATCH"; + break; + + case FIRHTTPMethodOPTIONS: + HTTPMethodString = @"OPTIONS"; + break; + + case FIRHTTPMethodTRACE: + HTTPMethodString = @"TRACE"; + break; + + case FIRHTTPMethodCONNECT: + HTTPMethodString = @"CONNECT"; + break; + } + [URLRequest setHTTPMethod:HTTPMethodString]; + + if (URLRequest && HTTPMethodString != nil) { + self = [super init]; + _networkTrace = [[FPRNetworkTrace alloc] initWithURLRequest:URLRequest]; + _URLRequest = [URLRequest copy]; + return self; + } + + FPRLogError(kFPRInstrumentationInvalidInputs, @"Invalid URL"); + return nil; +} + +- (void)start { + [self.networkTrace start]; +} + +- (void)markRequestComplete { + [self.networkTrace checkpointState:FPRNetworkTraceCheckpointStateRequestCompleted]; +} + +- (void)markResponseStart { + [self.networkTrace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; +} + +- (void)stop { + self.networkTrace.requestSize = self.requestPayloadSize; + self.networkTrace.responseSize = self.responsePayloadSize; + // Create a dummy URL Response that will be used for data extraction. + NSString *responsePayloadSize = + [[NSString alloc] initWithFormat:@"%ld", self.responsePayloadSize]; + NSMutableDictionary *headerFields = + [[NSMutableDictionary alloc] init]; + if (self.responseContentType) { + [headerFields setObject:self.responseContentType forKey:@"Content-Type"]; + } + [headerFields setObject:responsePayloadSize forKey:@"Content-Length"]; + + if (self.responseCode == 0) { + FPRLogError(kFPRInstrumentationInvalidInputs, @"Response code not set for request - %@", + self.URLRequest.URL); + return; + } + NSHTTPURLResponse *URLResponse = [[NSHTTPURLResponse alloc] initWithURL:self.URLRequest.URL + statusCode:self.responseCode + HTTPVersion:nil + headerFields:headerFields]; + + [self.networkTrace didCompleteRequestWithResponse:URLResponse error:nil]; +} + +#pragma mark - Custom attributes related methods + +- (NSDictionary *)attributes { + return [self.networkTrace attributes]; +} + +- (void)setValue:(NSString *)value forAttribute:(nonnull NSString *)attribute { + [self.networkTrace setValue:value forAttribute:attribute]; +} + +- (NSString *)valueForAttribute:(NSString *)attribute { + return [self.networkTrace valueForAttribute:attribute]; +} + +- (void)removeAttribute:(NSString *)attribute { + [self.networkTrace removeAttribute:attribute]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h new file mode 100644 index 0000000..e0fedd4 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h @@ -0,0 +1,62 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FPRSelectorInstrumentor; + +NS_ASSUME_NONNULL_BEGIN + +/** + * Each instrumented class (even classes within class clusters) needs to have its own instrumentor. + */ +@interface FPRClassInstrumentor : NSObject + +/** The class being instrumented. */ +@property(nonatomic, readonly) Class instrumentedClass; + +/** Please use the designated initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes with a class name and stores a reference to that string. This is the designated + * initializer. + * + * @param aClass The class to be instrumented. + * @return An instance of this class. + */ +- (instancetype)initWithClass:(Class)aClass NS_DESIGNATED_INITIALIZER; + +/** Creates and adds a class selector instrumentor to this class instrumentor. + * + * @param selector The selector to build and add to this class instrumentor; + * @return An FPRSelectorInstrumentor if the class/selector combination exists, nil otherwise. + */ +- (nullable FPRSelectorInstrumentor *)instrumentorForClassSelector:(SEL)selector; + +/** Creates and adds an instance selector instrumentor to this class instrumentor. + * + * @param selector The selector to build and add to this class instrumentor; + * @return An FPRSelectorInstrumentor if the class/selector combination exists, nil otherwise. + */ +- (nullable FPRSelectorInstrumentor *)instrumentorForInstanceSelector:(SEL)selector; + +/** Swizzles the set of selector instrumentors. */ +- (void)swizzle; + +/** Removes all selector instrumentors and unswizzles their implementations. */ +- (BOOL)unswizzle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.m new file mode 100644 index 0000000..b590b1c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.m @@ -0,0 +1,103 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor_Private.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" + +/** Use ivars instead of properties to reduce message sending overhead. */ +@interface FPRClassInstrumentor () { + // The selector instrumentors associated with this class. + NSMutableSet *_selectorInstrumentors; +} + +@end + +@implementation FPRClassInstrumentor + +#pragma mark - Public methods + +- (instancetype)init { + FPRAssert(NO, @"%@: please use the designated initializer.", NSStringFromClass([self class])); + return nil; +} + +- (instancetype)initWithClass:(Class)aClass { + self = [super init]; + if (self) { + FPRAssert(aClass, @"You must supply a class in order to instrument its methods"); + _instrumentedClass = aClass; + _selectorInstrumentors = [[NSMutableSet alloc] init]; + } + return self; +} + +- (nullable FPRSelectorInstrumentor *)instrumentorForClassSelector:(SEL)selector { + return [self buildAndAddSelectorInstrumentorForSelector:selector isClassSelector:YES]; +} + +- (nullable FPRSelectorInstrumentor *)instrumentorForInstanceSelector:(SEL)selector { + return [self buildAndAddSelectorInstrumentorForSelector:selector isClassSelector:NO]; +} + +- (void)swizzle { + for (FPRSelectorInstrumentor *selectorInstrumentor in _selectorInstrumentors) { + [selectorInstrumentor swizzle]; + } +} + +- (BOOL)unswizzle { + for (FPRSelectorInstrumentor *selectorInstrumentor in _selectorInstrumentors) { + [selectorInstrumentor unswizzle]; + } + [_selectorInstrumentors removeAllObjects]; + return _selectorInstrumentors.count == 0; +} + +#pragma mark - Private methods + +/** Creates and adds a selector instrumentor to this class instrumentor. + * + * @param selector The selector to build and add to this class instrumentor; + * @param isClassSelector If YES, then the selector is a class selector. + * @return An FPRSelectorInstrumentor if the class/selector combination exists, nil otherwise. + */ +- (nullable FPRSelectorInstrumentor *)buildAndAddSelectorInstrumentorForSelector:(SEL)selector + isClassSelector: + (BOOL)isClassSelector { + FPRSelectorInstrumentor *selectorInstrumentor = + [[FPRSelectorInstrumentor alloc] initWithSelector:selector + class:_instrumentedClass + isClassSelector:isClassSelector]; + if (selectorInstrumentor) { + [self addSelectorInstrumentor:selectorInstrumentor]; + } + return selectorInstrumentor; +} + +/** Adds a selector instrumentors to an existing running list of instrumented selectors. + * + * @param selectorInstrumentor A non-nil selector instrumentor, whose SEL objects will be swizzled. + */ +- (void)addSelectorInstrumentor:(nonnull FPRSelectorInstrumentor *)selectorInstrumentor { + if ([_selectorInstrumentors containsObject:selectorInstrumentor]) { + FPRAssert(NO, @"You cannot instrument the same selector (%@) twice", + NSStringFromSelector(selectorInstrumentor.selector)); + } + [_selectorInstrumentors addObject:selectorInstrumentor]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor_Private.h new file mode 100644 index 0000000..f292f3c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor_Private.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +NS_ASSUME_NONNULL_BEGIN + +@interface FPRClassInstrumentor () + +/** The set of selector instrumentors on this class. Only used for testing. */ +@property(nonatomic, readonly) NSSet *selectorInstrumentors; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.h new file mode 100644 index 0000000..2484dbb --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.h @@ -0,0 +1,60 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FPRClassInstrumentor; + +NS_ASSUME_NONNULL_BEGIN + +/** FPRInstrument instances can instrument many different classes, but should try to instrument + * only a single class in the general case. Due to class clusters, FPRInstruments need to be able + * to support logical groups of classes, even if the public API is a single class (e.g. + * NSDictionary or NSURLSession. FPRInstrument is expected to be subclassed by other classes that + * actually implement the instrument. Subclasses should provide their own implementations of + * registerInstrumentor + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRInstrument : NSObject + +/** The list of class instrumentors. count should == 1 in most cases, and be > 1 for class clusters. + */ +@property(nonatomic, readonly) NSArray *classInstrumentors; + +/** A set of the instrumented classes. */ +@property(nonatomic, readonly) NSSet *instrumentedClasses; + +/** + * Checks if the given object is instrumentable and returns YES if instrumentable. NO, otherwise. + * + * @param object Object that needs to be validated. + * @return Yes if instrumentable, NO otherwise. + */ +- (BOOL)isObjectInstrumentable:(id)object; + +/** Registers all instrumentors this instrument will utilize. Should be instrumented in a subclass. + * + * @note This method is thread-safe. + */ +- (void)registerInstrumentors; + +/** Deregisters the instrumentors by using API provided by FPRClassInstrumentor. Called by dealloc. + * + * @note This method is thread-safe. + */ +- (void)deregisterInstrumentors; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.m new file mode 100644 index 0000000..8f2f639 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument.m @@ -0,0 +1,78 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h" + +@implementation FPRInstrument { + NSMutableArray *_classInstrumentors; + + NSMutableSet *_instrumentedClasses; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _classInstrumentors = [[NSMutableArray alloc] init]; + _instrumentedClasses = [[NSMutableSet alloc] init]; + } + return self; +} + +- (NSMutableArray *)classInstrumentors { + return _classInstrumentors; +} + +- (NSMutableSet *)instrumentedClasses { + return _instrumentedClasses; +} + +- (void)registerInstrumentors { + FPRAssert(NO, @"registerInstrumentors should be implemented in a concrete subclass."); +} + +- (BOOL)isObjectInstrumentable:(id)object { + if ([object isKindOfClass:[NSOperation class]]) { + return NO; + } + return YES; +} + +- (BOOL)registerClassInstrumentor:(FPRClassInstrumentor *)instrumentor { + @synchronized(self) { + if ([_instrumentedClasses containsObject:instrumentor.instrumentedClass] || + [instrumentor.instrumentedClass instancesRespondToSelector:@selector(gul_class)]) { + return NO; + } + [_instrumentedClasses addObject:instrumentor.instrumentedClass]; + [_classInstrumentors addObject:instrumentor]; + return YES; + } +} + +- (void)deregisterInstrumentors { + @synchronized(self) { + for (FPRClassInstrumentor *classInstrumentor in self.classInstrumentors) { + [classInstrumentor unswizzle]; + } + [_classInstrumentors removeAllObjects]; + [_instrumentedClasses removeAllObjects]; + } +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h new file mode 100644 index 0000000..27bfedb --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h @@ -0,0 +1,30 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FPRInstrument () + +/** Registers an instrumentor for a class. Should be called by subclasses. + * + * @param instrumentor The instrumentor to register. + * @return NO if the class has already been instrumented, YES otherwise. + */ +- (BOOL)registerClassInstrumentor:(FPRClassInstrumentor *)instrumentor; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h new file mode 100644 index 0000000..1eeccbf --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h @@ -0,0 +1,45 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The key for the network instrumentation group. */ +FOUNDATION_EXTERN NSString *const kFPRInstrumentationGroupNetworkKey; + +/** The key for the UIKit instrumentation group. */ +FOUNDATION_EXTERN NSString *const kFPRInstrumentationGroupUIKitKey; + +/** This class manages all automatic instrumentation. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRInstrumentation : NSObject + +/** Registers the instrument group. + * + * @param group The group whose instrumentation should be registered. + * @return The number of instruments in the group. + */ +- (NSUInteger)registerInstrumentGroup:(NSString *)group; + +/** Deregisters the instrument group. + * + * @param group The group whose instrumentation should be deregistered. + * @return YES if there are no registered instruments in the group, NO otherwise. + */ +- (BOOL)deregisterInstrumentGroup:(NSString *)group; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.m new file mode 100644 index 0000000..0544aa2 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.m @@ -0,0 +1,92 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrumentation.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +// The instrumentation group keys. +NSString *const kFPRInstrumentationGroupNetworkKey = @"network"; +NSString *const kFPRInstrumentationGroupUIKitKey = @"uikit"; + +/** Use ivars instead of properties to reduce message sending overhead. */ +@interface FPRInstrumentation () { + // A dictionary of the instrument groups. + NSDictionary *_instrumentGroups; +} + +/** Registers an instrument in the given group. + * + * @param instrument The instrument to register. + * @param group The group to register the instrument in. + */ +- (void)registerInstrument:(FPRInstrument *)instrument group:(NSString *)group; + +@end + +@implementation FPRInstrumentation + +- (instancetype)init { + self = [super init]; + if (self) { + _instrumentGroups = @{ + kFPRInstrumentationGroupNetworkKey : [[NSMutableArray alloc] init], + kFPRInstrumentationGroupUIKitKey : [[NSMutableArray alloc] init] + }; + } + return self; +} + +- (void)registerInstrument:(FPRInstrument *)instrument group:(NSString *)group { + FPRAssert(instrument, @"Instrument must be non-nil."); + FPRAssert(_instrumentGroups[group], @"groups and group must be non-nil, and groups[group] must be" + "non-nil."); + if (instrument != nil) { + [_instrumentGroups[group] addObject:instrument]; + } + [instrument registerInstrumentors]; +} + +- (NSUInteger)registerInstrumentGroup:(NSString *)group { + FPRAssert(_instrumentGroups[group], @"The group key does not exist", group); + FPRAssert(_instrumentGroups[group].count == 0, @"This group is already instrumented"); + + if ([group isEqualToString:kFPRInstrumentationGroupNetworkKey]) { + [self registerInstrument:[[FPRNSURLSessionInstrument alloc] init] group:group]; + [self registerInstrument:[[FPRNSURLConnectionInstrument alloc] init] group:group]; + } + + if ([group isEqualToString:kFPRInstrumentationGroupUIKitKey]) { + [self registerInstrument:[[FPRUIViewControllerInstrument alloc] init] group:group]; + } + + return _instrumentGroups[group].count; +} + +- (BOOL)deregisterInstrumentGroup:(NSString *)group { + FPRAssert(_instrumentGroups[group], @"You're attempting to deregister an invalid group key."); + for (FPRInstrument *instrument in _instrumentGroups[group]) { + [instrument deregisterInstrumentors]; + } + [_instrumentGroups[group] removeAllObjects]; + return _instrumentGroups[group].count == 0; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace+Private.h new file mode 100644 index 0000000..4c12d1e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace+Private.h @@ -0,0 +1,31 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +/** + * Extension that is added on top of the class FPRNetworkTrace to make the private properties + * visible between the implementation file and the unit tests. + */ +@interface FPRNetworkTrace () + +/** @brief List of sessions the trace is associated with. */ +@property(nonatomic, readwrite, nonnull) NSMutableArray *activeSessions; + +/** Serial queue to manage concurrency. */ +@property(nonatomic, readwrite, nonnull) dispatch_queue_t syncQueue; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h new file mode 100644 index 0000000..befa8c2 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h @@ -0,0 +1,195 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +#import "FirebasePerformance/Sources/FIRPerformance+Internal.h" + +/** Possible checkpoint states of network trace */ +typedef NS_ENUM(NSInteger, FPRNetworkTraceCheckpointState) { + FPRNetworkTraceCheckpointStateUnknown, + + // Network request has been initiated. + FPRNetworkTraceCheckpointStateInitiated, + + // Network request is completed (All necessary uploads for the request is complete). + FPRNetworkTraceCheckpointStateRequestCompleted, + + // Network request has received its first response. There could be more. + FPRNetworkTraceCheckpointStateResponseReceived, + + // Network request has completed (Could be network error/request successful completion). + FPRNetworkTraceCheckpointStateResponseCompleted +}; + +@protocol FPRNetworkResponseHandler + +/** + * Records the size of the file that is uploaded during the request. + * + * @param URL The URL object that is being used for uploading from the network request. + */ +- (void)didUploadFileWithURL:(nullable NSURL *)URL; + +/** + * Records the amount of data that is fetched during the request. This can be called multiple times + * when the network delegate comes back with some data. + * + * @param data The data object as received from the network request. + */ +- (void)didReceiveData:(nullable NSData *)data; + +/** + * Records the size of the file that is fetched during the request. This can be called multiple + * times when the network delegate comes back with some data. + * + * @param URL The URL object as received from the network request. + */ +- (void)didReceiveFileURL:(nullable NSURL *)URL; + +/** + * Records the end state of the network request. This is usually called at the end of the network + * request with a valid response or an error. + * + * @param response Response of the network request. + * @param error Error with the network request. + */ +- (void)didCompleteRequestWithResponse:(nullable NSURLResponse *)response + error:(nullable NSError *)error; + +@end + +/** + * FPRNetworkTrace object contains information about an NSURLRequest. Every object contains + * information about the URL, type of request, and details of the response. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNetworkTrace : NSObject + +/** @brief Start time of the trace since epoch. */ +@property(nonatomic, assign, readonly) NSTimeInterval startTimeSinceEpoch; + +/** @brief The size of the request. The value is in bytes. */ +@property(nonatomic) int64_t requestSize; + +/** @brief The response size for the request. The value is in bytes. */ +@property(nonatomic) int64_t responseSize; + +/** @brief The HTTP response code for the request. */ +@property(nonatomic) int32_t responseCode; + +/** @brief Yes if a valid response code is set, NO otherwise. */ +@property(nonatomic) BOOL hasValidResponseCode; + +/** @brief The content type of the request as received from the server. */ +@property(nonatomic, copy, nullable) NSString *responseContentType; + +/** @brief The checkpoint states for the request. The key to the dictionary is the value referred in + * enum FPRNetworkTraceCheckpointState mentioned above. The value is the number of seconds since the + * reference date. + */ +@property(nonatomic, readonly, nullable) NSDictionary *checkpointStates; + +/** @brief The network request object. */ +@property(nonatomic, readonly, nullable) NSURLRequest *URLRequest; + +/** @brief The URL string with all the query params cleaned. The URL string will be of the format: + * scheme:[//[user:password@]host[:port]][/]path. + */ +@property(nonatomic, readonly, nullable) NSString *trimmedURLString; + +/** @brief Error object received with the network response. */ +@property(nonatomic, readonly, nullable) NSError *responseError; + +/** Background state of the trace. */ +@property(nonatomic, readonly) FPRTraceState backgroundTraceState; + +/** @brief List of sessions the trace is associated with. */ +@property(nonnull, atomic, readonly) NSArray *sessions; + +/** @brief Serial queue to manage usage of session Ids. */ +@property(nonatomic, readonly, nonnull) dispatch_queue_t sessionIdSerialQueue; + +/** + * Associate a network trace to an object project. This uses ObjC runtime to associate the network + * trace with the object provided. + * + * @param networkTrace Network trace object to be associated with the provided object. + * @param object The provided object to whom the network trace object will be associated with. + */ ++ (void)addNetworkTrace:(nonnull FPRNetworkTrace *)networkTrace toObject:(nonnull id)object; + +/** + * Gets the network trace associated with the provided object. If the network trace is not + * associated with the object, return nil. This uses ObjC runtime to fetch the object. + * + * @param object The provided object from which the network object would be fetched. + * @return The network trace object associated with the provided object. + */ ++ (nullable FPRNetworkTrace *)networkTraceFromObject:(nonnull id)object; + +/** + * Remove the network trace associated with the provided object. If the network trace is not + * associated with the object, does nothing. This uses ObjC runtime to remove the object. + * + * @param object The provided object from which the network object would be removed. + */ ++ (void)removeNetworkTraceFromObject:(nonnull id)object; + +/** + * Creates an instance of the FPRNetworkTrace with the provided URL and the HTTP method. + * + * @param URLRequest NSURLRequest object. + * @return An instance of FPRNetworkTrace. + */ +- (nullable instancetype)initWithURLRequest:(nonnull NSURLRequest *)URLRequest + NS_DESIGNATED_INITIALIZER; + +- (nullable instancetype)init NS_UNAVAILABLE; + +/** + * Records the beginning of the network request. This is usually called just before initiating the + * request. + */ +- (void)start; + +/** + * Checkpoints a particular state of the network request. Checkpoint states are listed in the enum + * FPRNetworkTraceCheckpointState mentioned above. + * + * @param state A state as mentioned in enum FPRNetworkTraceCheckpointState. + */ +- (void)checkpointState:(FPRNetworkTraceCheckpointState)state; + +/** + * Provides the time difference between the provided checkpoint states in seconds. If the starting + * checkpoint state is greater than the ending checkpoint state, the return value will be negative. + * If either of the states does not exist, returns 0. + * + * @param startState The starting checkpoint state. + * @param endState The ending checkpoint state. + * @return Difference between the ending checkpoint state and starting checkpoint state in seconds. + */ +- (NSTimeInterval)timeIntervalBetweenCheckpointState:(FPRNetworkTraceCheckpointState)startState + andState:(FPRNetworkTraceCheckpointState)endState; +/** + * Checks if the network trace is valid. + * + * @return true if the network trace is valid. + */ +- (BOOL)isValid; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.m new file mode 100644 index 0000000..f08015c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.m @@ -0,0 +1,465 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace+Private.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/FPRDataUtils.h" +#import "FirebasePerformance/Sources/FPRURLFilter.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" + +NSString *const kFPRNetworkTracePropertyName = @"fpr_networkTrace"; + +@interface FPRNetworkTrace () + +@property(nonatomic, readwrite) NSURLRequest *URLRequest; + +@property(nonatomic, readwrite, nullable) NSError *responseError; + +/** State to know if the trace has started. */ +@property(nonatomic) BOOL traceStarted; + +/** State to know if the trace has completed. */ +@property(nonatomic) BOOL traceCompleted; + +/** Background activity tracker to know the background state of the trace. */ +@property(nonatomic) FPRTraceBackgroundActivityTracker *backgroundActivityTracker; + +/** Custom attribute managed internally. */ +@property(nonatomic) NSMutableDictionary *customAttributes; + +/** @brief Serial queue to manage the updation of session Ids. */ +@property(nonatomic, readwrite) dispatch_queue_t sessionIdSerialQueue; + +/** + * Updates the current trace with the current session details. + * @param sessionDetails Updated session details of the currently active session. + */ +- (void)updateTraceWithCurrentSession:(FPRSessionDetails *)sessionDetails; + +@end + +@implementation FPRNetworkTrace { + /** + * @brief Object containing different states of the network request. Stores the information about + * the state of a network request (defined in FPRNetworkTraceCheckpointState) and the time at + * which the event happened. + */ + NSMutableDictionary *_states; +} + +- (nullable instancetype)initWithURLRequest:(NSURLRequest *)URLRequest { + if (URLRequest.URL == nil) { + FPRLogError(kFPRNetworkTraceInvalidInputs, @"Invalid URL. URL is nil."); + return nil; + } + + // Fail early instead of creating a trace here. + // IMPORTANT: Order is important here. This check needs to be done before looking up on remote + // config. Reference bug: b/141861005. + if (![[FPRURLFilter sharedInstance] shouldInstrumentURL:URLRequest.URL.absoluteString]) { + return nil; + } + + BOOL tracingEnabled = [FPRConfigurations sharedInstance].isDataCollectionEnabled; + if (!tracingEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Trace feature is disabled."); + return nil; + } + + BOOL sdkEnabled = [[FPRConfigurations sharedInstance] sdkEnabled]; + if (!sdkEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Dropping event since Performance SDK is disabled."); + return nil; + } + + NSString *trimmedURLString = [FPRNetworkTrace stringByTrimmingURLString:URLRequest]; + if (!trimmedURLString || trimmedURLString.length <= 0) { + FPRLogWarning(kFPRNetworkTraceURLLengthExceeds, @"URL length outside limits, returning nil."); + return nil; + } + + if (![URLRequest.URL.absoluteString isEqualToString:trimmedURLString]) { + FPRLogInfo(kFPRNetworkTraceURLLengthTruncation, + @"URL length exceeds limits, truncating recorded URL - %@.", trimmedURLString); + } + + self = [super init]; + if (self) { + _URLRequest = URLRequest; + _trimmedURLString = trimmedURLString; + _states = [[NSMutableDictionary alloc] init]; + _hasValidResponseCode = NO; + _customAttributes = [[NSMutableDictionary alloc] init]; + _syncQueue = + dispatch_queue_create("com.google.perf.networkTrace.metric", DISPATCH_QUEUE_SERIAL); + _sessionIdSerialQueue = + dispatch_queue_create("com.google.perf.sessionIds.networkTrace", DISPATCH_QUEUE_SERIAL); + _activeSessions = [[NSMutableArray alloc] init]; + if (![FPRNetworkTrace isCompleteAndValidTrimmedURLString:_trimmedURLString + URLRequest:_URLRequest]) { + return nil; + }; + } + return self; +} + +- (instancetype)init { + FPRAssert(NO, @"Not a designated initializer."); + return nil; +} + +- (void)dealloc { + // Safety net to ensure the notifications are not received anymore. + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + [sessionManager.sessionNotificationCenter removeObserver:self + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; +} + +- (NSString *)description { + return [NSString stringWithFormat:@"Request: %@", _URLRequest]; +} + +- (void)sessionChanged:(NSNotification *)notification { + if (self.traceStarted && !self.traceCompleted) { + NSDictionary *userInfo = notification.userInfo; + FPRSessionDetails *sessionDetails = [userInfo valueForKey:kFPRSessionIdNotificationKey]; + if (sessionDetails) { + [self updateTraceWithCurrentSession:sessionDetails]; + } + } +} + +- (void)updateTraceWithCurrentSession:(FPRSessionDetails *)sessionDetails { + if (sessionDetails != nil) { + dispatch_sync(self.sessionIdSerialQueue, ^{ + [self.activeSessions addObject:sessionDetails]; + }); + } +} + +- (NSArray *)sessions { + __block NSArray *sessionInfos = nil; + dispatch_sync(self.sessionIdSerialQueue, ^{ + sessionInfos = [self.activeSessions copy]; + }); + return sessionInfos; +} + +- (NSDictionary *)checkpointStates { + __block NSDictionary *copiedStates; + dispatch_sync(self.syncQueue, ^{ + copiedStates = [_states copy]; + }); + return copiedStates; +} + +- (void)checkpointState:(FPRNetworkTraceCheckpointState)state { + if (!self.traceCompleted && self.traceStarted) { + NSString *stateKey = @(state).stringValue; + if (stateKey) { + dispatch_sync(self.syncQueue, ^{ + NSNumber *existingState = _states[stateKey]; + + if (existingState == nil) { + double intervalSinceEpoch = [[NSDate date] timeIntervalSince1970]; + [_states setObject:@(intervalSinceEpoch) forKey:stateKey]; + } + }); + } else { + FPRAssert(NO, @"stateKey wasn't created for checkpoint state %ld", (long)state); + } + } +} + +- (void)start { + if (!self.traceCompleted) { + [[FPRSessionManager sharedInstance] collectAllGaugesOnce]; + self.traceStarted = YES; + self.backgroundActivityTracker = [[FPRTraceBackgroundActivityTracker alloc] init]; + [self checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + + if ([self.URLRequest.HTTPMethod isEqualToString:@"POST"] || + [self.URLRequest.HTTPMethod isEqualToString:@"PUT"]) { + self.requestSize = self.URLRequest.HTTPBody.length; + } + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + [self updateTraceWithCurrentSession:[sessionManager.sessionDetails copy]]; + [sessionManager.sessionNotificationCenter addObserver:self + selector:@selector(sessionChanged:) + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; + } +} + +- (FPRTraceState)backgroundTraceState { + FPRTraceBackgroundActivityTracker *backgroundActivityTracker = self.backgroundActivityTracker; + if (backgroundActivityTracker) { + return backgroundActivityTracker.traceBackgroundState; + } + + return FPRTraceStateUnknown; +} + +- (NSTimeInterval)startTimeSinceEpoch { + NSString *stateKey = + [NSString stringWithFormat:@"%lu", (unsigned long)FPRNetworkTraceCheckpointStateInitiated]; + __block NSTimeInterval timeSinceEpoch; + dispatch_sync(self.syncQueue, ^{ + timeSinceEpoch = [[_states objectForKey:stateKey] doubleValue]; + }); + return timeSinceEpoch; +} + +#pragma mark - Overrides + +- (void)setResponseCode:(int32_t)responseCode { + _responseCode = responseCode; + if (responseCode != 0) { + _hasValidResponseCode = YES; + } +} + +#pragma mark - FPRNetworkResponseHandler methods + +- (void)didCompleteRequestWithResponse:(NSURLResponse *)response error:(NSError *)error { + if (!self.traceCompleted && self.traceStarted) { + // Extract needed fields for the trace object. + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *HTTPResponse = (NSHTTPURLResponse *)response; + self.responseCode = (int32_t)HTTPResponse.statusCode; + } + self.responseError = error; + self.responseContentType = response.MIMEType; + [self checkpointState:FPRNetworkTraceCheckpointStateResponseCompleted]; + + // Send the network trace for logging. + [[FPRSessionManager sharedInstance] collectAllGaugesOnce]; + [[FPRClient sharedInstance] logNetworkTrace:self]; + + self.traceCompleted = YES; + } + + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + [sessionManager.sessionNotificationCenter removeObserver:self + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; +} + +- (void)didUploadFileWithURL:(NSURL *)URL { + NSNumber *value = nil; + NSError *error = nil; + + if ([URL getResourceValue:&value forKey:NSURLFileSizeKey error:&error]) { + if (error) { + FPRLogNotice(kFPRNetworkTraceFileError, @"Unable to determine the size of file."); + } else { + self.requestSize = value.unsignedIntegerValue; + } + } +} + +- (void)didReceiveData:(NSData *)data { + self.responseSize = data.length; +} + +- (void)didReceiveFileURL:(NSURL *)URL { + NSNumber *value = nil; + NSError *error = nil; + + if ([URL getResourceValue:&value forKey:NSURLFileSizeKey error:&error]) { + if (error) { + FPRLogNotice(kFPRNetworkTraceFileError, @"Unable to determine the size of file."); + } else { + self.responseSize = value.unsignedIntegerValue; + } + } +} + +- (NSTimeInterval)timeIntervalBetweenCheckpointState:(FPRNetworkTraceCheckpointState)startState + andState:(FPRNetworkTraceCheckpointState)endState { + __block NSNumber *startStateTime; + __block NSNumber *endStateTime; + dispatch_sync(self.syncQueue, ^{ + startStateTime = [_states objectForKey:[@(startState) stringValue]]; + endStateTime = [_states objectForKey:[@(endState) stringValue]]; + }); + // Fail fast. If any of the times do not exist, return 0. + if (startStateTime == nil || endStateTime == nil) { + return 0; + } + + NSTimeInterval timeDiff = (endStateTime.doubleValue - startStateTime.doubleValue); + return timeDiff; +} + +/** Trims and validates the URL string of a given NSURLRequest. + * + * @param URLRequest The NSURLRequest containing the URL string to trim. + * @return The trimmed string. + */ ++ (NSString *)stringByTrimmingURLString:(NSURLRequest *)URLRequest { + NSURLComponents *components = [NSURLComponents componentsWithURL:URLRequest.URL + resolvingAgainstBaseURL:NO]; + components.query = nil; + components.fragment = nil; + components.user = nil; + components.password = nil; + NSURL *trimmedURL = [components URL]; + NSString *truncatedURLString = FPRTruncatedURLString(trimmedURL.absoluteString); + + NSURL *truncatedURL = [NSURL URLWithString:truncatedURLString]; + if (!truncatedURL || truncatedURL.host == nil) { + return nil; + } + return truncatedURLString; +} + +/** Validates the trace object by checking that it's http or https, and not a denied URL. + * + * @param trimmedURLString A trimmed URL string from the URLRequest. + * @param URLRequest The NSURLRequest that this trace will operate on. + * @return YES if the trace object is valid, NO otherwise. + */ ++ (BOOL)isCompleteAndValidTrimmedURLString:(NSString *)trimmedURLString + URLRequest:(NSURLRequest *)URLRequest { + if (![[FPRURLFilter sharedInstance] shouldInstrumentURL:trimmedURLString]) { + return NO; + } + + // Check the URL begins with http or https. + NSURLComponents *components = [NSURLComponents componentsWithURL:URLRequest.URL + resolvingAgainstBaseURL:NO]; + NSString *scheme = components.scheme; + if (!scheme || !([scheme caseInsensitiveCompare:@"HTTP"] == NSOrderedSame || + [scheme caseInsensitiveCompare:@"HTTPS"] == NSOrderedSame)) { + FPRLogError(kFPRNetworkTraceInvalidInputs, @"Invalid URL - %@, returning nil.", URLRequest.URL); + return NO; + } + + return YES; +} + +#pragma mark - Custom attributes related methods + +- (NSDictionary *)attributes { + return [self.customAttributes copy]; +} + +- (void)setValue:(NSString *)value forAttribute:(nonnull NSString *)attribute { + BOOL canAddAttribute = YES; + if (self.traceCompleted) { + FPRLogError(kFPRTraceAlreadyStopped, + @"Failed to set attribute %@ because network request %@ has already stopped.", + attribute, self.URLRequest.URL); + canAddAttribute = NO; + } + + NSString *validatedName = FPRReservableAttributeName(attribute); + NSString *validatedValue = FPRValidatedAttributeValue(value); + + if (validatedName == nil) { + FPRLogError(kFPRAttributeNoName, + @"Failed to initialize because of a nil or zero length attribute name."); + canAddAttribute = NO; + } + + if (validatedValue == nil) { + FPRLogError(kFPRAttributeNoValue, + @"Failed to initialize because of a nil or zero length attribute value."); + canAddAttribute = NO; + } + + if (self.customAttributes.allKeys.count >= kFPRMaxGlobalCustomAttributesCount) { + FPRLogError(kFPRMaxAttributesReached, + @"Only %d attributes allowed. Already reached maximum attribute count.", + kFPRMaxGlobalCustomAttributesCount); + canAddAttribute = NO; + } + + if (canAddAttribute) { + // Ensure concurrency during update of attributes. + dispatch_sync(self.syncQueue, ^{ + self.customAttributes[validatedName] = validatedValue; + FPRLogDebug(kFPRClientMetricLogged, @"Setting attribute %@ to %@ on network request %@", + validatedName, validatedValue, self.URLRequest.URL); + }); + } +} + +- (NSString *)valueForAttribute:(NSString *)attribute { + // TODO(b/175053654): Should this be happening on the serial queue for thread safety? + return self.customAttributes[attribute]; +} + +- (void)removeAttribute:(NSString *)attribute { + if (self.traceCompleted) { + FPRLogError(kFPRTraceAlreadyStopped, + @"Failed to remove attribute %@ because network request %@ has already stopped.", + attribute, self.URLRequest.URL); + return; + } + + [self.customAttributes removeObjectForKey:attribute]; +} + +#pragma mark - Class methods related to object association. + ++ (void)addNetworkTrace:(FPRNetworkTrace *)networkTrace toObject:(id)object { + if (object != nil && networkTrace != nil) { + [FPRObjectSwizzler + setAssociatedObject:object + key:(__bridge const void *_Nonnull)kFPRNetworkTracePropertyName + value:networkTrace + association:GUL_ASSOCIATION_RETAIN_NONATOMIC]; + } +} + ++ (FPRNetworkTrace *)networkTraceFromObject:(id)object { + FPRNetworkTrace *networkTrace = nil; + if (object != nil) { + id traceObject = [FPRObjectSwizzler + getAssociatedObject:object + key:(__bridge const void *_Nonnull)kFPRNetworkTracePropertyName]; + if ([traceObject isKindOfClass:[FPRNetworkTrace class]]) { + networkTrace = (FPRNetworkTrace *)traceObject; + } + } + + return networkTrace; +} + ++ (void)removeNetworkTraceFromObject:(id)object { + if (object != nil) { + [FPRObjectSwizzler + setAssociatedObject:object + key:(__bridge const void *_Nonnull)kFPRNetworkTracePropertyName + value:nil + association:GUL_ASSOCIATION_RETAIN_NONATOMIC]; + } +} + +- (BOOL)isValid { + return _hasValidResponseCode; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h new file mode 100644 index 0000000..b016c07 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h @@ -0,0 +1,75 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +#import "FirebasePerformance/Sources/ISASwizzler/FPRSwizzledObject.h" + +@class FPRSelectorInstrumentor; + +NS_ASSUME_NONNULL_BEGIN + +/** Defines the interface that an instrumentor should implement if they are going to instrument + * objects. + */ +@protocol FPRObjectInstrumentorProtocol + +@required + +/** Registers an instance of the delegate class to be instrumented. + * + * @param object The instance to instrument. + */ +- (void)registerObject:(id)object; + +@end + +/** This class allows the instrumentation of specific objects by isa swizzling specific instances + * with a dynamically generated subclass of the object's original class and installing methods + * onto this new class. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRObjectInstrumentor : FPRInstrument + +/** The instrumented object. */ +@property(nonatomic, weak) id instrumentedObject; + +/** YES if there is reason to swizzle, NO if swizzling is not needed. */ +@property(nonatomic) BOOL hasModifications; + +/** Please use the designated initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** Instantiates an instance of this class. The designated initializer. + * + * @param object The object to be instrumented. + * @return An instance of this class. + */ +- (instancetype)initWithObject:(id)object NS_DESIGNATED_INITIALIZER; + +/** Attempts to copy a selector from a donor class onto the dynamically generated subclass that the + * object will adopt when -swizzle is called. + * + * @param selector The selector to use. + * @param aClass The class to copy the selector from. + * @param isClassSelector YES if the selector is a class selector, NO otherwise. + */ +- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector; + +/** Swizzles the isa of the object and sets its class to the dynamically created subclass. */ +- (void)swizzle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.m new file mode 100644 index 0000000..d62e1ab --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.m @@ -0,0 +1,59 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" + +@interface FPRObjectInstrumentor () { + // The object swizzler instance this instrumentor will use. + FPRObjectSwizzler *_objectSwizzler; +} + +@end + +@implementation FPRObjectInstrumentor + +- (instancetype)init { + FPRAssert(NO, @"%@: Please use the designated initializer.", NSStringFromClass([self class])); + return nil; +} + +- (instancetype)initWithObject:(id)object { + self = [super init]; + if (self) { + _objectSwizzler = [[FPRObjectSwizzler alloc] initWithObject:object]; + _instrumentedObject = object; + } + return self; +} + +- (void)copySelector:(SEL)selector fromClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { + __strong id instrumentedObject = _instrumentedObject; + if (instrumentedObject && ![instrumentedObject respondsToSelector:selector]) { + _hasModifications = YES; + [_objectSwizzler copySelector:selector fromClass:aClass isClassSelector:isClassSelector]; + } +} + +- (void)swizzle { + if (_hasModifications) { + [_objectSwizzler swizzle]; + } +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h new file mode 100644 index 0000000..a746e8e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h @@ -0,0 +1,34 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** This class helps the instrumentation deal with objects that have been wrapped with NSProxy + * objects after being swizzled by other SDKs. In particular, Crittercism swizzles NSURLSessions + * and makes every NSURLSession initialization method return an NSProxy subclass. + */ +@interface FPRProxyObjectHelper : NSObject + +/** Registers a proxy object for a given class and runs the onSuccess block whenever an ivar of the + * given class is discovered on the proxy object. + * + * @param proxy The proxy object whose ivars will be iterated. + * @param superclass The superclass all ivars will be compared against. See varFoundHandler. + * @param varFoundHandler The block to run when an ivar isKindOfClass:aClass. + */ ++ (void)registerProxyObject:(id)proxy + forSuperclass:(Class)superclass + varFoundHandler:(void (^)(id ivar))varFoundHandler; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.m new file mode 100644 index 0000000..ae46231 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.m @@ -0,0 +1,32 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h" + +#import + +@implementation FPRProxyObjectHelper + ++ (void)registerProxyObject:(id)proxy + forSuperclass:(Class)superclass + varFoundHandler:(void (^)(id ivar))varFoundHandler { + NSArray *ivars = [GULSwizzler ivarObjectsForObject:proxy]; + for (id ivar in ivars) { + if ([ivar isKindOfClass:superclass]) { + varFoundHandler(ivar); + } + } +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h new file mode 100644 index 0000000..161ea40 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h @@ -0,0 +1,65 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This class is used to manage the swizzling of selectors on classes. An instance of this class + * should be created for every selector that is being swizzled. + */ +@interface FPRSelectorInstrumentor : NSObject + +/** The swizzled selector. */ +@property(nonatomic, readonly) SEL selector; + +/** Please use designated initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes an instance of this class. The designated initializer. + * + * @note Capture the current IMP outside the replacing block which will be the originalIMP once we + * swizzle. + * + * @param selector The selector pointer. + * @param aClass The class to operate on. + * @param isClassSelector YES specifies that the selector is a class selector. + * @return An instance of this class. + */ +- (instancetype)initWithSelector:(SEL)selector + class:(Class)aClass + isClassSelector:(BOOL)isClassSelector NS_DESIGNATED_INITIALIZER; + +/** Sets the instrumentor's replacing block. To be used in conjunction with initWithSelector:. + * + * @param block The block to replace the original implementation with. Make sure to call + * originalImp in your replacing block. + */ +- (void)setReplacingBlock:(id)block; + +/** The current IMP of the swizzled selector. + * + * @return The current IMP for the class, SEL of the FPRSelectorInstrumentor. + */ +- (IMP)currentIMP; + +/** Swizzles the selector. */ +- (void)swizzle; + +/** Causes the original implementation to be run. */ +- (void)unswizzle; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.m new file mode 100644 index 0000000..0f474e5 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.m @@ -0,0 +1,107 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" + +#import +#ifdef UNSWIZZLE_AVAILABLE +#import +#endif + +@implementation FPRSelectorInstrumentor { + // The class this instrumentor operates on. + Class _class; + + // The selector this instrumentor operates on. + SEL _selector; + + // YES indicates the selector swizzled is a class selector, as opposed to an instance selector. + BOOL _isClassSelector; + + // YES indicates that this selector instrumentor has been swizzled. + BOOL _swizzled; + + // A block to replace the original implementation. Can't be used with before/after blocks. + id _replacingBlock; +} + +- (instancetype)init { + FPRAssert(NO, @"%@: Please use the designated initializer", NSStringFromClass([self class])); + return nil; +} + +- (instancetype)initWithSelector:(SEL)selector + class:(Class)aClass + isClassSelector:(BOOL)isClassSelector { + if (![GULSwizzler selector:selector existsInClass:aClass isClassSelector:isClassSelector]) { + return nil; + } + self = [super init]; + if (self) { + _selector = selector; + _class = aClass; + _isClassSelector = isClassSelector; + FPRAssert(_selector, @"A selector to swizzle must be provided."); + FPRAssert(_class, @"You can't swizzle a class that doesn't exist"); + } + return self; +} + +- (void)setReplacingBlock:(id)block { + _replacingBlock = [block copy]; +} + +- (void)swizzle { + _swizzled = YES; + FPRAssert(_replacingBlock, @"A replacingBlock needs to be set."); + + [GULSwizzler swizzleClass:_class + selector:_selector + isClassSelector:_isClassSelector + withBlock:_replacingBlock]; +} + +- (void)unswizzle { + _swizzled = NO; +#ifdef UNSWIZZLE_AVAILABLE + [GULSwizzler unswizzleClass:_class selector:_selector isClassSelector:_isClassSelector]; +#else + NSAssert(NO, @"Unswizzling is disabled."); +#endif +} + +- (IMP)currentIMP { + return [GULSwizzler currentImplementationForClass:_class + selector:_selector + isClassSelector:_isClassSelector]; +} + +- (BOOL)isEqual:(id)object { + if ([object isKindOfClass:[FPRSelectorInstrumentor class]]) { + FPRSelectorInstrumentor *otherObject = object; + return otherObject->_class == _class && otherObject->_selector == _selector && + otherObject->_isClassSelector == _isClassSelector && otherObject->_swizzled == _swizzled; + } + return NO; +} + +- (NSUInteger)hash { + return [[NSString stringWithFormat:@"%@%@%d%d", NSStringFromClass(_class), + NSStringFromSelector(_selector), _isClassSelector, _swizzled] + hash]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h new file mode 100644 index 0000000..fea5915 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLConnectionDelegate : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.m new file mode 100644 index 0000000..f7ae5f0 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.m @@ -0,0 +1,82 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h" + +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +@implementation FPRNSURLConnectionDelegate + +- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didCompleteRequestWithResponse:nil error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; +} + +- (NSURLRequest *)connection:(NSURLConnection *)connection + willSendRequest:(nonnull NSURLRequest *)request + redirectResponse:(nullable NSURLResponse *)response { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + return request; +} + +- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + trace.responseCode = (int32_t)((NSHTTPURLResponse *)response).statusCode; + } + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; +} + +- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + trace.responseSize += data.length; +} + +- (void)connection:(NSURLConnection *)connection + didSendBodyData:(NSInteger)bytesWritten + totalBytesWritten:(NSInteger)totalBytesWritten + totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + trace.requestSize = totalBytesWritten; + if (totalBytesWritten >= totalBytesExpectedToWrite) { + [trace checkpointState:FPRNetworkTraceCheckpointStateRequestCompleted]; + } +} + +- (void)connectionDidFinishLoading:(NSURLConnection *)connection { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didCompleteRequestWithResponse:nil error:nil]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; +} + +- (void)connection:(NSURLConnection *)connection + didWriteData:(long long)bytesWritten + totalBytesWritten:(long long)totalBytesWritten + expectedTotalBytes:(long long)expectedTotalBytes { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + trace.requestSize = totalBytesWritten; +} + +- (void)connectionDidFinishDownloading:(NSURLConnection *)connection + destinationURL:(NSURL *)destinationURL { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didReceiveFileURL:destinationURL]; + [trace didCompleteRequestWithResponse:nil error:nil]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.h new file mode 100644 index 0000000..b532e1d --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.h @@ -0,0 +1,36 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +#import "FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class instruments the delegate methods needed to start/stop trace correctly. This class is + * not intended to be used standalone--it should only be used by FPRNSURLConnectionInstrument. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLConnectionDelegateInstrument : FPRInstrument + +/** Registers an instrument for a delegate class if it hasn't yet been instrumented. + * + * @note This method is thread-safe. + * @param aClass The class to instrument. + */ +- (void)registerClass:(Class)aClass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.m new file mode 100644 index 0000000..a01fb21 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.m @@ -0,0 +1,307 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.h" + +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" + +#pragma mark - NSURLConnectionDelegate methods + +/** Returns the dispatch queue for all instrumentation to occur on. */ +static dispatch_queue_t GetInstrumentationQueue(void) { + static dispatch_queue_t queue; + static dispatch_once_t token; + dispatch_once(&token, ^{ + queue = dispatch_queue_create("com.google.FPRNSURLConnectionDelegateInstrument", + DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +/** Instruments connection:didFailWithError:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidFailWithError(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:didFailWithError:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, NSError *error) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didCompleteRequestWithResponse:nil error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, NSError *); + ((OriginalImp)currentIMP)(object, selector, connection, error); + }]; + } +} + +#pragma mark - NSURLConnectionDataDelegate methods + +/** Instruments connection:willSendRequest:redirectResponse:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionWillSendRequestRedirectResponse(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:willSendRequest:redirectResponse:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object, NSURLConnection *connection, + NSURLRequest *request, NSURLResponse *response) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + typedef NSURLRequest *(*OriginalImp)(id, SEL, NSURLConnection *, NSURLRequest *, + NSURLResponse *); + return ((OriginalImp)currentIMP)(object, selector, connection, request, response); + }]; + } +} + +/** Instruments connection:didReceiveResponse:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidReceiveResponse(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:didReceiveResponse:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, NSURLResponse *response) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + if ([response isKindOfClass:[NSHTTPURLResponse class]]) { + trace.responseCode = (int32_t)((NSHTTPURLResponse *)response).statusCode; + } + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, NSURLResponse *); + ((OriginalImp)currentIMP)(object, selector, connection, response); + }]; + } +} + +/** Instruments connection:didReceiveData:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidReceiveData(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:didReceiveData:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, NSData *data) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + trace.responseSize += data.length; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, NSData *); + ((OriginalImp)currentIMP)(object, selector, connection, data); + }]; + } +} + +/** Instruments connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionAllTheTotals(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, NSInteger bytesWritten, + NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + trace.requestSize = totalBytesWritten; + if (totalBytesWritten >= totalBytesExpectedToWrite) { + [trace checkpointState:FPRNetworkTraceCheckpointStateRequestCompleted]; + } + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, NSInteger, NSInteger, NSInteger); + ((OriginalImp)currentIMP)(object, selector, connection, bytesWritten, totalBytesWritten, + totalBytesExpectedToWrite); + }]; + } +} + +/** Instruments connectionDidFinishLoading:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidFinishLoading(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connectionDidFinishLoading:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object, NSURLConnection *connection) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didCompleteRequestWithResponse:nil error:nil]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *); + ((OriginalImp)currentIMP)(object, selector, connection); + }]; + } +} + +/** Instruments connection:didWriteData:totalBytesWritten:expectedTotalBytes:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidWriteDataTotalBytesWrittenExpectedTotalBytes( + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connection:didWriteData:totalBytesWritten:expectedTotalBytes:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, long long bytesWritten, + long long totalBytesWritten, long long expectedTotalBytes) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + trace.requestSize = totalBytesWritten; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, long long, long long, long long); + ((OriginalImp)currentIMP)(object, selector, connection, bytesWritten, totalBytesWritten, + expectedTotalBytes); + }]; + } +} + +/** Instruments connectionDidFinishDownloading:destinationURL:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionDidFinishDownloadingDestinationURL(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(connectionDidFinishDownloading:destinationURL:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLConnection *connection, NSURL *destinationURL) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didReceiveFileURL:destinationURL]; + [trace didCompleteRequestWithResponse:nil error:nil]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; + typedef void (*OriginalImp)(id, SEL, NSURLConnection *, NSURL *); + ((OriginalImp)currentIMP)(object, selector, connection, destinationURL); + }]; + } +} + +#pragma mark - Helper functions +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void CopySelector(SEL selector, FPRObjectInstrumentor *instrumentor) { + static Class fromClass = Nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + fromClass = [FPRNSURLConnectionDelegate class]; + }); + if (![instrumentor.instrumentedObject respondsToSelector:selector]) { + [instrumentor copySelector:selector fromClass:fromClass isClassSelector:NO]; + } +} + +#pragma mark - FPRNSURLConnectionDelegateInstrument + +@implementation FPRNSURLConnectionDelegateInstrument + +- (void)registerInstrumentors { + // Do nothing by default. classes will be instrumented on-demand upon discovery. +} + +- (void)registerClass:(Class)aClass { + dispatch_sync(GetInstrumentationQueue(), ^{ + // If this class has already been instrumented, just return. + FPRClassInstrumentor *instrumentor = [[FPRClassInstrumentor alloc] initWithClass:aClass]; + if (![self registerClassInstrumentor:instrumentor]) { + return; + } + + InstrumentConnectionDidFailWithError(instrumentor); + InstrumentConnectionWillSendRequestRedirectResponse(instrumentor); + InstrumentConnectionDidReceiveResponse(instrumentor); + InstrumentConnectionDidReceiveData(instrumentor); + InstrumentConnectionAllTheTotals(instrumentor); + InstrumentConnectionDidFinishLoading(instrumentor); + InstrumentConnectionDidWriteDataTotalBytesWrittenExpectedTotalBytes(instrumentor); + InstrumentConnectionDidFinishDownloadingDestinationURL(instrumentor); + + [instrumentor swizzle]; + }); +} + +- (void)registerObject:(id)object { + dispatch_sync(GetInstrumentationQueue(), ^{ + if ([object respondsToSelector:@selector(gul_class)]) { + return; + } + + if (![self isObjectInstrumentable:object]) { + return; + } + + FPRObjectInstrumentor *instrumentor = [[FPRObjectInstrumentor alloc] initWithObject:object]; + + // Register the non-swizzled versions of these methods. + CopySelector(@selector(connection:didFailWithError:), instrumentor); + CopySelector(@selector(connection:willSendRequest:redirectResponse:), instrumentor); + CopySelector(@selector(connection:didReceiveResponse:), instrumentor); + CopySelector(@selector(connection:didReceiveData:), instrumentor); + CopySelector(@selector(connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:), + instrumentor); + if (![object respondsToSelector:@selector(connectionDidFinishDownloading:destinationURL:)]) { + CopySelector(@selector(connectionDidFinishLoading:), instrumentor); + } + + CopySelector(@selector(connection:didWriteData:totalBytesWritten:expectedTotalBytes:), + instrumentor); + if (![object respondsToSelector:@selector(connectionDidFinishLoading:)]) { + CopySelector(@selector(connectionDidFinishDownloading:destinationURL:), instrumentor); + } + + [instrumentor swizzle]; + }); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h new file mode 100644 index 0000000..740ca52 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** This class exists as a supplier of implementations for delegates that do not implement all + * methods. While swizzling a delegate, if their class doesn't implement the below methods, these + * implementations will be copied onto the delegate class. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLSessionDelegate : NSObject + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.m new file mode 100644 index 0000000..75a44a5 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.m @@ -0,0 +1,84 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h" + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" + +@implementation FPRNSURLSessionDelegate + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + @try { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + [trace didCompleteRequestWithResponse:task.response error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:task]; + } @catch (NSException *exception) { + FPRLogWarning(kFPRNetworkTraceNotTrackable, @"Unable to track network request."); + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didSendBodyData:(int64_t)bytesSent + totalBytesSent:(int64_t)totalBytesSent + totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend { + @try { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + trace.requestSize = totalBytesSent; + if (totalBytesSent >= totalBytesExpectedToSend) { + [trace checkpointState:FPRNetworkTraceCheckpointStateRequestCompleted]; + } + } @catch (NSException *exception) { + FPRLogWarning(kFPRNetworkTraceNotTrackable, @"Unable to track network request."); + } +} + +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:dataTask]; + [trace didReceiveData:data]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didFinishDownloadingToURL:(NSURL *)location { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace didReceiveFileURL:location]; + [trace didCompleteRequestWithResponse:downloadTask.response error:downloadTask.error]; + [FPRNetworkTrace removeNetworkTraceFromObject:downloadTask]; +} + +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)downloadTask + didWriteData:(int64_t)bytesWritten + totalBytesWritten:(int64_t)totalBytesWritten + totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + trace.responseSize = totalBytesWritten; + if (totalBytesWritten >= totalBytesExpectedToWrite) { + if ([downloadTask.response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *response = (NSHTTPURLResponse *)downloadTask.response; + [trace didCompleteRequestWithResponse:response error:downloadTask.error]; + [FPRNetworkTrace removeNetworkTraceFromObject:downloadTask]; + } + } +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.h new file mode 100644 index 0000000..f300491 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.h @@ -0,0 +1,36 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +#import "FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class instruments the delegate methods needed to start/stop traces correctly. This class is + * not intended to be used standalone--it should only be used by FPRNSURLSessionInstrument. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLSessionDelegateInstrument : FPRInstrument + +/** Registers an instrumentor for a delegate class if it hasn't yet been instrumented. + * + * @note This method is thread-safe. + * @param aClass The class to instrument. + */ +- (void)registerClass:(Class)aClass; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.m new file mode 100644 index 0000000..c636d3e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.m @@ -0,0 +1,266 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.h" + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" + +/** Returns the dispatch queue for all instrumentation to occur on. */ +static dispatch_queue_t GetInstrumentationQueue(void) { + static dispatch_queue_t queue; + static dispatch_once_t token; + dispatch_once(&token, ^{ + queue = dispatch_queue_create("com.google.FPRNSURLSessionDelegateInstrument", + DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +#pragma mark - NSURLSessionTaskDelegate methods + +/** Instruments URLSession:task:didCompleteWithError:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentURLSessionTaskDidCompleteWithError(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(URLSession:task:didCompleteWithError:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object, NSURLSession *session, + NSURLSessionTask *task, NSError *error) { + @try { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + [trace didCompleteRequestWithResponse:task.response error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:task]; + } @catch (NSException *exception) { + FPRLogWarning(kFPRNetworkTraceNotTrackable, @"Unable to track network request."); + } @finally { + typedef void (*OriginalImp)(id, SEL, NSURLSession *, NSURLSessionTask *, NSError *); + ((OriginalImp)currentIMP)(object, selector, session, task, error); + } + }]; + } +} + +/** Instruments URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentURLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend( + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(URLSession: + task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLSession *session, NSURLSessionTask *task, + int64_t bytesSent, int64_t totalBytesSent, + int64_t totalBytesExpectedToSend) { + @try { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + trace.requestSize = totalBytesSent; + if (totalBytesSent >= totalBytesExpectedToSend) { + [trace checkpointState:FPRNetworkTraceCheckpointStateRequestCompleted]; + } + } @catch (NSException *exception) { + FPRLogWarning(kFPRNetworkTraceNotTrackable, @"Unable to track network request."); + } @finally { + typedef void (*OriginalImp)(id, SEL, NSURLSession *, NSURLSessionTask *, int64_t, + int64_t, int64_t); + ((OriginalImp)currentIMP)(object, selector, session, task, bytesSent, totalBytesSent, + totalBytesExpectedToSend); + } + }]; + } +} + +#pragma mark - NSURLSessionDataDelegate methods + +/** Instruments URLSession:dataTask:didReceiveData:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentURLSessionDataTaskDidReceiveData(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(URLSession:dataTask:didReceiveData:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object, NSURLSession *session, + NSURLSessionDataTask *dataTask, NSData *data) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:dataTask]; + [trace didReceiveData:data]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + typedef void (*OriginalImp)(id, SEL, NSURLSession *, NSURLSessionDataTask *, NSData *); + ((OriginalImp)currentIMP)(object, selector, session, dataTask, data); + }]; + } +} + +#pragma mark - NSURLSessionDownloadDelegate methods. + +/** Instruments URLSession:downloadTask:didFinishDownloadingToURL:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentURLSessionDownloadTaskDidFinishDownloadToURL(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(URLSession:downloadTask:didFinishDownloadingToURL:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLSession *session, + NSURLSessionDownloadTask *downloadTask, NSURL *location) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace didReceiveFileURL:location]; + [trace didCompleteRequestWithResponse:downloadTask.response error:downloadTask.error]; + [FPRNetworkTrace removeNetworkTraceFromObject:downloadTask]; + typedef void (*OriginalImp)(id, SEL, NSURLSession *, NSURLSessionDownloadTask *, NSURL *); + ((OriginalImp)currentIMP)(object, selector, session, downloadTask, location); + }]; + } +} + +/** Instruments URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentURLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite( + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(URLSession: + downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:); + FPRSelectorInstrumentor *selectorInstrumentor = + [instrumentor instrumentorForInstanceSelector:selector]; + if (selectorInstrumentor) { + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id object, NSURLSession *session, + NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, + int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace checkpointState:FPRNetworkTraceCheckpointStateResponseReceived]; + trace.responseSize = totalBytesWritten; + if (totalBytesWritten >= totalBytesExpectedToWrite) { + if ([downloadTask.response isKindOfClass:[NSHTTPURLResponse class]]) { + NSHTTPURLResponse *response = (NSHTTPURLResponse *)downloadTask.response; + [trace didCompleteRequestWithResponse:response error:downloadTask.error]; + [FPRNetworkTrace removeNetworkTraceFromObject:downloadTask]; + } + } + typedef void (*OriginalImp)(id, SEL, NSURLSession *, NSURLSessionDownloadTask *, int64_t, + int64_t, int64_t); + ((OriginalImp)currentIMP)(object, selector, session, downloadTask, bytesWritten, + totalBytesWritten, totalBytesExpectedToWrite); + }]; + } +} + +#pragma mark - Helper functions + +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void CopySelector(SEL selector, FPRObjectInstrumentor *instrumentor) { + static Class fromClass = Nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + fromClass = [FPRNSURLSessionDelegate class]; + }); + if (![instrumentor.instrumentedObject respondsToSelector:selector]) { + [instrumentor copySelector:selector fromClass:fromClass isClassSelector:NO]; + } +} + +#pragma mark - FPRNSURLSessionDelegateInstrument + +@implementation FPRNSURLSessionDelegateInstrument + +- (void)registerInstrumentors { + // Do nothing by default; classes will be instrumented on-demand upon discovery. +} + +- (void)registerClass:(Class)aClass { + dispatch_sync(GetInstrumentationQueue(), ^{ + // If this class has already been instrumented, just return. + FPRClassInstrumentor *instrumentor = [[FPRClassInstrumentor alloc] initWithClass:aClass]; + if (![self registerClassInstrumentor:instrumentor]) { + return; + } + + // NSURLSessionTaskDelegate methods. + InstrumentURLSessionTaskDidCompleteWithError(instrumentor); + InstrumentURLSessionTaskDidSendBodyDataTotalBytesSentTotalBytesExpectedToSend(instrumentor); + + // NSURLSessionDataDelegate methods. + InstrumentURLSessionDataTaskDidReceiveData(instrumentor); + + // NSURLSessionDownloadDelegate methods. + InstrumentURLSessionDownloadTaskDidFinishDownloadToURL(instrumentor); + InstrumentURLSessionDownloadTaskDidWriteDataTotalBytesWrittenTotalBytesExpectedToWrite( + instrumentor); + + [instrumentor swizzle]; + }); +} + +- (void)registerObject:(id)object { + dispatch_sync(GetInstrumentationQueue(), ^{ + if ([object respondsToSelector:@selector(gul_class)]) { + return; + } + FPRObjectInstrumentor *instrumentor = [[FPRObjectInstrumentor alloc] initWithObject:object]; + + // Register the non-swizzled versions of these methods. + // NSURLSessionTaskDelegate methods. + CopySelector(@selector(URLSession:task:didCompleteWithError:), instrumentor); + CopySelector(@selector(URLSession: + task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:), + instrumentor); + + // NSURLSessionDataDelegate methods. + CopySelector(@selector(URLSession:dataTask:didReceiveData:), instrumentor); + + // NSURLSessionDownloadDelegate methods. + CopySelector(@selector(URLSession:downloadTask:didFinishDownloadingToURL:), instrumentor); + CopySelector(@selector(URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes:), + instrumentor); + CopySelector(@selector(URLSession: + downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite:), + instrumentor); + + [instrumentor swizzle]; + }); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h new file mode 100644 index 0000000..3a37a40 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class instruments the NSURLConnection class. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLConnectionInstrument : FPRInstrument + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.m new file mode 100644 index 0000000..a3534ed --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.m @@ -0,0 +1,236 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument_Private.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRObjectInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegate.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +static NSString *const kFPRDelegateKey = @"kFPRDelegateKey"; + +typedef void (^FPRNSURLConnectionCompletionHandler)(NSURLResponse *_Nullable response, + NSData *_Nullable data, + NSError *_Nullable connectionError); + +/** Returns the dispatch queue for all instrumentation to occur on. */ +static dispatch_queue_t GetInstrumentationQueue(void) { + static dispatch_queue_t queue = nil; + static dispatch_once_t token = 0; + dispatch_once(&token, ^{ + queue = dispatch_queue_create("com.google.FPRNSURLConnectionInstrumentation", + DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +/** Instruments +sendAsynchronousRequest:queue:completionHandler:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentSendAsynchronousRequestQueueCompletionHandler(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(sendAsynchronousRequest:queue:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id connection, NSURLRequest *request, NSOperationQueue *queue, + FPRNSURLConnectionCompletionHandler completionHandler) { + FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:request]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + + // The completionHandler needs to be there for FPRNetworkTrace purposes, even if originally + // nil. + FPRNSURLConnectionCompletionHandler wrappedCompletionHandler = + ^(NSURLResponse *_Nullable response, NSData *_Nullable data, + NSError *_Nullable connectionError) { + [trace didReceiveData:data]; + [trace didCompleteRequestWithResponse:response error:connectionError]; + if (completionHandler) { + completionHandler(response, data, connectionError); + } + }; + typedef void (*OriginalImp)(id, SEL, NSURLRequest *, NSOperationQueue *, + FPRNSURLConnectionCompletionHandler); + ((OriginalImp)currentIMP)(connection, selector, request, queue, wrappedCompletionHandler); + }]; +} + +/** Instruments -initWithRequest:delegate:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + * @param delegateInstrument The FPRNSURLConnectionDelegateInstrument to potentially add a new + * class to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentInitWithRequestDelegate(FPRClassInstrumentor *instrumentor, + FPRNSURLConnectionDelegateInstrument *delegateInstrument) { + SEL selector = @selector(initWithRequest:delegate:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + + [selectorInstrumentor setReplacingBlock:^(id connection, NSURLRequest *request, id delegate) { + if (delegate) { + [delegateInstrument registerClass:[delegate class]]; + [delegateInstrument registerObject:delegate]; + [FPRObjectSwizzler setAssociatedObject:connection + key:(__bridge const void *_Nonnull)kFPRDelegateKey + value:delegate + association:GUL_ASSOCIATION_ASSIGN]; + } else { + delegate = [[FPRNSURLConnectionDelegate alloc] init]; + [FPRObjectSwizzler setAssociatedObject:connection + key:(__bridge const void *_Nonnull)kFPRDelegateKey + value:delegate + association:GUL_ASSOCIATION_ASSIGN]; + } + typedef NSURLConnection *(*OriginalImp)(id, SEL, NSURLRequest *, id); + return ((OriginalImp)currentIMP)(connection, selector, request, delegate); + }]; +} + +/** Instruments -initWithRequest:delegate:startImmediately:. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + * @param delegateInstrument The FPRNSURLConnectionDelegateInstrument to potentially add a new + * class to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentInitWithRequestDelegateStartImmediately( + FPRClassInstrumentor *instrumentor, FPRNSURLConnectionDelegateInstrument *delegateInstrument) { + SEL selector = @selector(initWithRequest:delegate:startImmediately:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id connection, NSURLRequest *request, id delegate, + BOOL startImmediately) { + if (delegate) { + [delegateInstrument registerClass:[delegate class]]; + [delegateInstrument registerObject:delegate]; + + [FPRObjectSwizzler setAssociatedObject:connection + key:(__bridge const void *_Nonnull)kFPRDelegateKey + value:delegate + association:GUL_ASSOCIATION_ASSIGN]; + } else { + delegate = [[FPRNSURLConnectionDelegate alloc] init]; + [FPRObjectSwizzler setAssociatedObject:connection + key:(__bridge const void *_Nonnull)kFPRDelegateKey + value:delegate + association:GUL_ASSOCIATION_ASSIGN]; + } + typedef NSURLConnection *(*OriginalImp)(id, SEL, NSURLRequest *, id, BOOL); + return ((OriginalImp)currentIMP)(connection, selector, request, delegate, startImmediately); + }]; +} + +/** Instruments -start. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionStart(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(start); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object) { + typedef void (*OriginalImp)(id, SEL); + NSURLConnection *connection = (NSURLConnection *)object; + if ([FPRObjectSwizzler getAssociatedObject:connection + key:(__bridge const void *_Nonnull)kFPRDelegateKey]) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:connection.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:connection]; + } + ((OriginalImp)currentIMP)(connection, selector); + }]; +} + +/** Instruments -cancel. + * + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentConnectionCancel(FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(cancel); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id object) { + typedef void (*OriginalImp)(id, SEL); + NSURLConnection *connection = (NSURLConnection *)object; + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:connection]; + [trace didCompleteRequestWithResponse:nil error:nil]; + [FPRNetworkTrace removeNetworkTraceFromObject:connection]; + ((OriginalImp)currentIMP)(connection, selector); + }]; +} + +@implementation FPRNSURLConnectionInstrument + +- (instancetype)init { + self = [super init]; + if (self) { + _delegateInstrument = [[FPRNSURLConnectionDelegateInstrument alloc] init]; + [_delegateInstrument registerInstrumentors]; + } + return self; +} + +- (void)dealloc { + [_delegateInstrument deregisterInstrumentors]; +} + +- (void)registerInstrumentors { + dispatch_sync(GetInstrumentationQueue(), ^{ + FPRClassInstrumentor *instrumentor = + [[FPRClassInstrumentor alloc] initWithClass:[NSURLConnection class]]; + + if (![self registerClassInstrumentor:instrumentor]) { + FPRAssert(NO, @"NSURLConnection should only be instrumented once."); + } + + InstrumentSendAsynchronousRequestQueueCompletionHandler(instrumentor); + + InstrumentInitWithRequestDelegate(instrumentor, _delegateInstrument); + InstrumentInitWithRequestDelegateStartImmediately(instrumentor, _delegateInstrument); + + InstrumentConnectionStart(instrumentor); + InstrumentConnectionCancel(instrumentor); + + [instrumentor swizzle]; + }); +} + +- (void)deregisterInstrumentors { + [_delegateInstrument deregisterInstrumentors]; + [super deregisterInstrumentors]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument_Private.h new file mode 100644 index 0000000..cb5222e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument_Private.h @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLConnectionInstrument.h" + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLConnectionDelegateInstrument.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FPRNSURLConnectionInstrument () + +/** The delegate instrument. */ +@property(nonatomic) FPRNSURLConnectionDelegateInstrument *delegateInstrument; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h new file mode 100644 index 0000000..a93dadd --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h @@ -0,0 +1,27 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class instruments the NSURLSession class cluster. As new classes are discovered, they will + * be swizzled on a shared queue. Completion blocks and delegate methods are also wrapped. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLSessionInstrument : FPRInstrument + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.m new file mode 100644 index 0000000..5739407 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.m @@ -0,0 +1,715 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** NSURLSession is a class cluster and the type of class you get back from the various + * initialization methods might not actually be NSURLSession. Inside those methods, this class + * keeps track of seen NSURLSession subclasses and lazily swizzles them if they've not been seen. + * Consequently, swizzling needs to occur on a serial queue for thread safety. + */ + +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h" + +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/ISASwizzler/FPRObjectSwizzler.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRNetworkTrace.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRProxyObjectHelper.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegate.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" + +// Declared for use in instrumentation functions below. +@interface FPRNSURLSessionInstrument () + +/** Registers an instrumentor for an NSURLSession subclass if it hasn't yet been instrumented. + * + * @param aClass The class we wish to instrument. + */ +- (void)registerInstrumentorForClass:(Class)aClass; + +/** Registers an instrumentor for an NSURLSession proxy object if it hasn't yet been instrumented. + * + * @param proxy The proxy object we wish to instrument. + */ +- (void)registerProxyObject:(id)proxy; + +@end + +/** Returns the dispatch queue for all instrumentation to occur on. */ +static dispatch_queue_t GetInstrumentationQueue(void) { + static dispatch_queue_t queue = nil; + static dispatch_once_t token = 0; + dispatch_once(&token, ^{ + queue = + dispatch_queue_create("com.google.FPRNSURLSessionInstrumentation", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +// This completion handler type is commonly used throughout NSURLSession. +typedef void (^FPRDataTaskCompletionHandler)(NSData *_Nullable, + NSURLResponse *_Nullable, + NSError *_Nullable); + +typedef void (^FPRDownloadTaskCompletionHandler)(NSURL *_Nullable location, + NSURLResponse *_Nullable response, + NSError *_Nullable error); + +#pragma mark - Instrumentation Functions + +/** Wraps +sharedSession. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentSharedSession(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(sharedSession); + Class instrumentedClass = instrumentor.instrumentedClass; + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass); + } + typedef NSURLSession *(*OriginalImp)(id, SEL); + NSURLSession *sharedSession = ((OriginalImp)currentIMP)(session, selector); + if ([sharedSession isProxy]) { + [strongInstrument registerProxyObject:sharedSession]; + } else { + [strongInstrument registerInstrumentorForClass:[sharedSession class]]; + } + return sharedSession; + }]; +} + +/** Wraps +sessionWithConfiguration:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentSessionWithConfiguration(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(sessionWithConfiguration:); + Class instrumentedClass = instrumentor.instrumentedClass; + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLSessionConfiguration *configuration) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass); + } + typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *); + NSURLSession *sessionInstance = ((OriginalImp)currentIMP)(session, selector, configuration); + if ([sessionInstance isProxy]) { + [strongInstrument registerProxyObject:sessionInstance]; + } else { + [strongInstrument registerInstrumentorForClass:[sessionInstance class]]; + } + return sessionInstance; + }]; +} + +/** Wraps +sessionWithConfiguration:delegate:delegateQueue:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + * @param delegateInstrument The FPRNSURLSessionDelegateInstrument that will track the delegate + * selectors. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentSessionWithConfigurationDelegateDelegateQueue( + FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor, + FPRNSURLSessionDelegateInstrument *delegateInstrument) { + SEL selector = @selector(sessionWithConfiguration:delegate:delegateQueue:); + Class instrumentedClass = instrumentor.instrumentedClass; + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, YES); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor + setReplacingBlock:^(id session, NSURLSessionConfiguration *configuration, + id delegate, NSOperationQueue *queue) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentedClass); + } + if (delegate) { + [delegateInstrument registerClass:[delegate class]]; + [delegateInstrument registerObject:delegate]; + + } else { + delegate = [[FPRNSURLSessionDelegate alloc] init]; + } + typedef NSURLSession *(*OriginalImp)(id, SEL, NSURLSessionConfiguration *, + id, NSOperationQueue *); + NSURLSession *sessionInstance = + ((OriginalImp)currentIMP)([session class], selector, configuration, delegate, queue); + if ([sessionInstance isProxy]) { + [strongInstrument registerProxyObject:sessionInstance]; + } else { + [strongInstrument registerInstrumentorForClass:[sessionInstance class]]; + } + return sessionInstance; + }]; +} + +/** Wraps -dataTaskWithURL:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ + +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDataTaskWithURL(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(dataTaskWithURL:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURL *url) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURL *); + NSURLSessionDataTask *dataTask = ((OriginalImp)currentIMP)(session, selector, url); + if (dataTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:dataTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:dataTask]; + } + + return dataTask; + }]; +} + +/** Instruments -dataTaskWithURL:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDataTaskWithURLCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(dataTaskWithURL:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURL *URL, + FPRDataTaskCompletionHandler completionHandler) { + __block NSURLSessionDataTask *task = nil; + FPRDataTaskCompletionHandler wrappedCompletionHandler = nil; + if (completionHandler) { + wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + [trace didReceiveData:data]; + [trace didCompleteRequestWithResponse:response error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:task]; + completionHandler(data, response, error); + }; + } + typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURL *, FPRDataTaskCompletionHandler); + task = ((OriginalImp)currentIMP)(session, selector, URL, wrappedCompletionHandler); + + // Add the network trace object only when the trace object is not added to the task object. + if ([FPRNetworkTrace networkTraceFromObject:task] == nil) { + FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:task.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:task]; + } + return task; + }]; +} + +/** Wraps -dataTaskWithRequest:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ + +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDataTaskWithRequest(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(dataTaskWithRequest:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURLRequest *); + NSURLSessionDataTask *dataTask = ((OriginalImp)currentIMP)(session, selector, request); + if (dataTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:dataTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:dataTask]; + } + + return dataTask; + }]; +} + +/** Instruments -dataTaskWithRequest:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDataTaskWithRequestCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(dataTaskWithRequest:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, + FPRDataTaskCompletionHandler completionHandler) { + __block NSURLSessionDataTask *task = nil; + FPRDataTaskCompletionHandler wrappedCompletionHandler = nil; + if (completionHandler) { + wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:task]; + [trace didReceiveData:data]; + [trace didCompleteRequestWithResponse:response error:error]; + [FPRNetworkTrace removeNetworkTraceFromObject:task]; + completionHandler(data, response, error); + }; + } + typedef NSURLSessionDataTask *(*OriginalImp)(id, SEL, NSURLRequest *, + FPRDataTaskCompletionHandler); + task = ((OriginalImp)currentIMP)(session, selector, request, wrappedCompletionHandler); + + // Add the network trace object only when the trace object is not added to the task object. + if ([FPRNetworkTrace networkTraceFromObject:task] == nil) { + FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:task.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:task]; + } + return task; + }]; +} + +/** Instruments -uploadTaskWithRequest:fromFile:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentUploadTaskWithRequestFromFile(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(uploadTaskWithRequest:fromFile:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSURL *fileURL) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSURL *); + NSURLSessionUploadTask *uploadTask = + ((OriginalImp)currentIMP)(session, selector, request, fileURL); + if (uploadTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask]; + } + return uploadTask; + }]; +} + +/** Instruments -uploadTaskWithRequest:fromFile:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentUploadTaskWithRequestFromFileCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(uploadTaskWithRequest:fromFile:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSURL *fileURL, + FPRDataTaskCompletionHandler completionHandler) { + FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:request]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [trace didUploadFileWithURL:fileURL]; + FPRDataTaskCompletionHandler wrappedCompletionHandler = nil; + if (completionHandler) { + wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) { + [trace didReceiveData:data]; + [trace didCompleteRequestWithResponse:response error:error]; + completionHandler(data, response, error); + }; + } + typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSURL *, + FPRDataTaskCompletionHandler); + return ((OriginalImp)currentIMP)(session, selector, request, fileURL, wrappedCompletionHandler); + }]; +} + +/** Instruments -uploadTaskWithRequest:fromData:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentUploadTaskWithRequestFromData(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(uploadTaskWithRequest:fromData:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSData *bodyData) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSData *); + // To avoid a runtime warning in Xcode 15, the given `URLRequest` + // should have a nil `HTTPBody`. To workaround this, the `HTTPBody` data is removed + // and requestData is replaced with it, if it bodyData was `nil`. + NSMutableURLRequest *requestWithoutHTTPBody = [request mutableCopy]; + NSData *requestData = bodyData ?: requestWithoutHTTPBody.HTTPBody; + requestWithoutHTTPBody.HTTPBody = nil; + NSURLSessionUploadTask *uploadTask = + ((OriginalImp)currentIMP)(session, selector, requestWithoutHTTPBody, requestData); + if (uploadTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest]; + [trace start]; + trace.requestSize = bodyData.length; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask]; + } + return uploadTask; + }]; +} + +/** Instruments -uploadTaskWithRequest:fromData:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentUploadTaskWithRequestFromDataCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(uploadTaskWithRequest:fromData:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, NSData *bodyData, + FPRDataTaskCompletionHandler completionHandler) { + FPRNetworkTrace *trace = [[FPRNetworkTrace alloc] initWithURLRequest:request]; + [trace start]; + trace.requestSize = bodyData.length; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + FPRDataTaskCompletionHandler wrappedCompletionHandler = nil; + if (completionHandler) { + wrappedCompletionHandler = ^(NSData *data, NSURLResponse *response, NSError *error) { + [trace didReceiveData:data]; + [trace didCompleteRequestWithResponse:response error:error]; + completionHandler(data, response, error); + }; + } + typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSData *, + FPRDataTaskCompletionHandler); + // To avoid a runtime warning in Xcode 15, the given `URLRequest` + // should have a nil `HTTPBody`. To workaround this, the `HTTPBody` data is removed + // and requestData is replaced with it, if it bodyData was `nil`. + NSMutableURLRequest *requestWithoutHTTPBody = [request mutableCopy]; + NSData *requestData = bodyData ?: requestWithoutHTTPBody.HTTPBody; + requestWithoutHTTPBody.HTTPBody = nil; + return ((OriginalImp)currentIMP)(session, selector, requestWithoutHTTPBody, requestData, + wrappedCompletionHandler); + }]; +} + +/** Instruments -uploadTaskWithStreamedRequest:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentUploadTaskWithStreamedRequest(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(uploadTaskWithStreamedRequest:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionUploadTask *(*OriginalImp)(id, SEL, NSURLRequest *, NSData *); + // To avoid a runtime warning in Xcode 15, the given `URLRequest` + // should have a nil `HTTPBody`. To workaround this, the `HTTPBody` data is removed + // and requestData is replaced with it, if it bodyData was `nil`. + NSMutableURLRequest *requestWithoutHTTPBody = [request mutableCopy]; + NSData *requestData = requestWithoutHTTPBody.HTTPBody; + requestWithoutHTTPBody.HTTPBody = nil; + NSURLSessionUploadTask *uploadTask = + ((OriginalImp)currentIMP)(session, selector, request, requestData); + if (uploadTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:uploadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:uploadTask]; + } + return uploadTask; + }]; +} + +/** Instruments -downloadTaskWithURL:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDownloadTaskWithURL(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(downloadTaskWithURL:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURL *url) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURL *); + NSURLSessionDownloadTask *downloadTask = ((OriginalImp)currentIMP)(session, selector, url); + if (downloadTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask]; + } + return downloadTask; + }]; +} + +/** Instruments -downloadTaskWithURL:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDownloadTaskWithURLCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(downloadTaskWithURL:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURL *URL, + FPRDownloadTaskCompletionHandler completionHandler) { + __block NSURLSessionDownloadTask *downloadTask = nil; + FPRDownloadTaskCompletionHandler wrappedCompletionHandler = nil; + if (completionHandler) { + wrappedCompletionHandler = ^(NSURL *location, NSURLResponse *response, NSError *error) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace didReceiveFileURL:location]; + [trace didCompleteRequestWithResponse:response error:error]; + completionHandler(location, response, error); + }; + } + typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURL *, + FPRDownloadTaskCompletionHandler); + downloadTask = ((OriginalImp)currentIMP)(session, selector, URL, wrappedCompletionHandler); + + // Add the network trace object only when the trace object is not added to the task object. + if ([FPRNetworkTrace networkTraceFromObject:downloadTask] == nil) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask]; + } + return downloadTask; + }]; +} + +/** Instruments -downloadTaskWithRequest:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDownloadTaskWithRequest(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(downloadTaskWithRequest:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + __weak FPRNSURLSessionInstrument *weakInstrument = instrument; + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request) { + __strong FPRNSURLSessionInstrument *strongInstrument = weakInstrument; + if (!strongInstrument) { + ThrowExceptionBecauseInstrumentHasBeenDeallocated(selector, instrumentor.instrumentedClass); + } + typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURLRequest *); + NSURLSessionDownloadTask *downloadTask = ((OriginalImp)currentIMP)(session, selector, request); + if (downloadTask.originalRequest) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask]; + } + return downloadTask; + }]; +} + +/** Instruments -downloadTaskWithRequest:completionHandler:. + * + * @param instrument The FPRNSURLSessionInstrument instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentDownloadTaskWithRequestCompletionHandler(FPRNSURLSessionInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(downloadTaskWithRequest:completionHandler:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP currentIMP = selectorInstrumentor.currentIMP; + [selectorInstrumentor setReplacingBlock:^(id session, NSURLRequest *request, + FPRDownloadTaskCompletionHandler completionHandler) { + __block NSURLSessionDownloadTask *downloadTask = nil; + FPRDownloadTaskCompletionHandler wrappedCompletionHandler = nil; + + if (completionHandler) { + wrappedCompletionHandler = ^(NSURL *location, NSURLResponse *response, NSError *error) { + FPRNetworkTrace *trace = [FPRNetworkTrace networkTraceFromObject:downloadTask]; + [trace didReceiveFileURL:location]; + [trace didCompleteRequestWithResponse:response error:error]; + completionHandler(location, response, error); + }; + } + typedef NSURLSessionDownloadTask *(*OriginalImp)(id, SEL, NSURLRequest *, + FPRDownloadTaskCompletionHandler); + downloadTask = ((OriginalImp)currentIMP)(session, selector, request, wrappedCompletionHandler); + + // Add the network trace object only when the trace object is not added to the task object. + if ([FPRNetworkTrace networkTraceFromObject:downloadTask] == nil) { + FPRNetworkTrace *trace = + [[FPRNetworkTrace alloc] initWithURLRequest:downloadTask.originalRequest]; + [trace start]; + [trace checkpointState:FPRNetworkTraceCheckpointStateInitiated]; + [FPRNetworkTrace addNetworkTrace:trace toObject:downloadTask]; + } + return downloadTask; + }]; +} + +#pragma mark - FPRNSURLSessionInstrument + +@implementation FPRNSURLSessionInstrument + +- (instancetype)init { + self = [super init]; + if (self) { + _delegateInstrument = [[FPRNSURLSessionDelegateInstrument alloc] init]; + [_delegateInstrument registerInstrumentors]; + } + return self; +} + +- (void)registerInstrumentors { + [self registerInstrumentorForClass:[NSURLSession class]]; +} + +- (void)deregisterInstrumentors { + [_delegateInstrument deregisterInstrumentors]; + [super deregisterInstrumentors]; +} + +- (void)registerInstrumentorForClass:(Class)aClass { + dispatch_sync(GetInstrumentationQueue(), ^{ + FPRAssert([aClass isSubclassOfClass:[NSURLSession class]], + @"Class %@ is not a subclass of " + "NSURLSession", + aClass); + // If this class has already been instrumented, just return. + FPRClassInstrumentor *instrumentor = [[FPRClassInstrumentor alloc] initWithClass:aClass]; + if (![self registerClassInstrumentor:instrumentor]) { + return; + } + + InstrumentSharedSession(self, instrumentor); + + InstrumentSessionWithConfiguration(self, instrumentor); + InstrumentSessionWithConfigurationDelegateDelegateQueue(self, instrumentor, + _delegateInstrument); + + InstrumentDataTaskWithURL(self, instrumentor); + InstrumentDataTaskWithURLCompletionHandler(self, instrumentor); + InstrumentDataTaskWithRequest(self, instrumentor); + InstrumentDataTaskWithRequestCompletionHandler(self, instrumentor); + + InstrumentUploadTaskWithRequestFromFile(self, instrumentor); + InstrumentUploadTaskWithRequestFromFileCompletionHandler(self, instrumentor); + InstrumentUploadTaskWithRequestFromData(self, instrumentor); + InstrumentUploadTaskWithRequestFromDataCompletionHandler(self, instrumentor); + InstrumentUploadTaskWithStreamedRequest(self, instrumentor); + + InstrumentDownloadTaskWithURL(self, instrumentor); + InstrumentDownloadTaskWithURLCompletionHandler(self, instrumentor); + InstrumentDownloadTaskWithRequest(self, instrumentor); + InstrumentDownloadTaskWithRequestCompletionHandler(self, instrumentor); + + [instrumentor swizzle]; + }); +} + +- (void)registerProxyObject:(id)proxy { + [FPRProxyObjectHelper registerProxyObject:proxy + forSuperclass:[NSURLSession class] + varFoundHandler:^(id ivar) { + [self registerInstrumentorForClass:[ivar class]]; + }]; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h new file mode 100644 index 0000000..8e7cd9f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument_Private.h @@ -0,0 +1,28 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNSURLSessionInstrument.h" + +#import "FirebasePerformance/Sources/Instrumentation/Network/Delegates/FPRNSURLSessionDelegateInstrument.h" + +NS_ASSUME_NONNULL_BEGIN +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRNSURLSessionInstrument () + +/** The delegate instrument. */ +@property(nonatomic) FPRNSURLSessionDelegateInstrument *delegateInstrument; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h new file mode 100644 index 0000000..ebd1dd8 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h @@ -0,0 +1,73 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@class FPRSelectorInstrumentor; +@class FPRClassInstrumentor; + +/** Throws an exception declaring that the selector was not found on the class. This is a + * convenience function. + * + * This should only be invoked when one of two things has happened: + * - The underlying iOS implementation removes a method on a class and we haven't detected it yet. + * - We instrument a new method using the wrong selector/class combo and don't discover that + * through unit tests or other kinds of testing or development. + * + * @param selector The selector being invoked. + * @param aClass The class the selector belongs to. + * @throws An exception if invoked. + */ +FOUNDATION_EXTERN +void ThrowExceptionBecauseSelectorNotFoundOnClass(SEL selector, Class aClass); + +/** Throws an exception declaring that the selector instrumentor has been deallocated. This is a + * convenience function. + * + * This should only be invoked when the selector instrumentor has been deallocated, but for some + * reason -unswizzle was not called. + * + * @param selector The selector being invoked. + * @param aClass The class the selector belongs to. + * @throws An exception if invoked. + */ +FOUNDATION_EXTERN +void ThrowExceptionBecauseSelectorInstrumentorHasBeenDeallocated(SEL selector, Class aClass); + +/** Throws an exception declaring that the instrument attempting to register a class has been + * deallocated. + * + * This should only be invoked when the instrument of an iOS class cluster has been deallocated, + * but not unswizzled. + * + * @param selector The selector being invoked. + * @param aClass The class the selector belongs to. + * @throws An exception if invoked. + */ +FOUNDATION_EXTERN +void ThrowExceptionBecauseInstrumentHasBeenDeallocated(SEL selector, Class aClass); + +/** Returns an FPRSelectorInstrumentor given a SEL and FPRClassInstrumentor. This is a convenience + * function. + * + * @param selector The selector to instrument. + * @param instrumentor The class instrumentor to generate the selector instrumentor from. + * @param isClassSelector YES if the selector is a class selector, NO otherwise. + * @return An FPRSelectorInstrumentor instance if the selector is on the class. + * @throws An exception if the selector is NOT found on the class. + */ +FOUNDATION_EXTERN +FPRSelectorInstrumentor *SelectorInstrumentor(SEL selector, + FPRClassInstrumentor *instrumentor, + BOOL isClassSelector); diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.m new file mode 100644 index 0000000..43bf4de --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.m @@ -0,0 +1,61 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" + +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" + +FOUNDATION_EXTERN_INLINE +void ThrowExceptionBecauseSelectorNotFoundOnClass(SEL selector, Class aClass) { + [NSException raise:NSInternalInconsistencyException + format:@"Selector %@ not found on class %@", NSStringFromSelector(selector), + NSStringFromClass(aClass)]; +} + +FOUNDATION_EXTERN_INLINE +void ThrowExceptionBecauseSelectorInstrumentorHasBeenDeallocated(SEL selector, Class aClass) { + [NSException raise:NSInternalInconsistencyException + format:@"Selector instrumentor has been deallocated: %@|%@", + NSStringFromSelector(selector), NSStringFromClass(aClass)]; +} + +FOUNDATION_EXTERN_INLINE +void ThrowExceptionBecauseInstrumentHasBeenDeallocated(SEL selector, Class aClass) { + [NSException raise:NSInternalInconsistencyException + format:@"The instrument has been deallocated: %@|%@", NSStringFromSelector(selector), + NSStringFromClass(aClass)]; +} + +/** Returns an FPRSelectorInstrumentor given a SEL and FPRClassInstrumentor. This is a convenience + * function. + * + * @param selector The selector to instrument. + * @param instrumentor The class instrumentor to generate the selector instrumentor from. + * @param isClassSelector YES if the selector is a class selector, NO otherwise. + * @return An FPRSelectorInstrumentor instance if the selector is on the class. + * @throws An exception if the selector is NOT found on the class. + */ +FOUNDATION_EXTERN_INLINE +FPRSelectorInstrumentor *SelectorInstrumentor(SEL selector, + FPRClassInstrumentor *instrumentor, + BOOL isClassSelector) { + FPRSelectorInstrumentor *selectorInstrumentor = + isClassSelector ? [instrumentor instrumentorForClassSelector:selector] + : [instrumentor instrumentorForInstanceSelector:selector]; + if (!selectorInstrumentor) { + ThrowExceptionBecauseSelectorNotFoundOnClass(selector, instrumentor.instrumentedClass); + } + return selectorInstrumentor; +} diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.h new file mode 100644 index 0000000..f766ed7 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.h @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class instruments the UIViewController class. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRUIViewControllerInstrument : FPRInstrument + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m new file mode 100644 index 0000000..147b53c --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.m @@ -0,0 +1,120 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRScreenTraceTracker+Private.h" +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRClassInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRInstrument_Private.h" +#import "FirebasePerformance/Sources/Instrumentation/FPRSelectorInstrumentor.h" +#import "FirebasePerformance/Sources/Instrumentation/Network/FPRNetworkInstrumentHelpers.h" +#import "FirebasePerformance/Sources/Instrumentation/UIKit/FPRUIViewControllerInstrument.h" + +#import +#import + +/** Returns the dispatch queue for all instrumentation to occur on. */ +static dispatch_queue_t GetInstrumentationQueue(void) { + static dispatch_queue_t queue = nil; + static dispatch_once_t token = 0; + dispatch_once(&token, ^{ + queue = dispatch_queue_create("com.google.FPRUIViewControllerInstrumentation", + DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +// Returns the singleton UIApplication of the application this is currently running in or nil if +// it's in an app extension. +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +static UIApplication *FPRSharedApplication(void) { + if ([GULAppEnvironmentUtil isAppExtension]) { + return nil; + } + return [UIApplication sharedApplication]; +} + +@implementation FPRUIViewControllerInstrument + +/** Wraps -viewDidAppear: + * + * @param instrument The FPRUIViewController instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentViewDidAppear(FPRUIViewControllerInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(viewDidAppear:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP oldViewDidAppearIMP = [selectorInstrumentor currentIMP]; + [selectorInstrumentor setReplacingBlock:^void(id _self, BOOL animated) { + if (oldViewDidAppearIMP) { + GUL_INVOKE_ORIGINAL_IMP1(_self, selector, void, oldViewDidAppearIMP, animated); + } + + // This has to be called on the main thread and so it's done here instead of in + // FPRScreenTraceTracker. + // TODO(#13067): Replace keyWindow usage (deprecated in iOS and unavailable in visionOS). +#if !defined(TARGET_OS_VISION) || !TARGET_OS_VISION +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + if ([((UIViewController *)_self).view isDescendantOfView:FPRSharedApplication().keyWindow]) { +#pragma clang diagnostic pop + [[FPRScreenTraceTracker sharedInstance] viewControllerDidAppear:_self]; + } +#endif + }]; +} + +/** Wraps -viewDidDisappear: + * + * @param instrument The FPRUIViewController instance. + * @param instrumentor The FPRClassInstrumentor to add the selector instrumentor to. + */ +FOUNDATION_STATIC_INLINE +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +void InstrumentViewDidDisappear(FPRUIViewControllerInstrument *instrument, + FPRClassInstrumentor *instrumentor) { + SEL selector = @selector(viewDidDisappear:); + FPRSelectorInstrumentor *selectorInstrumentor = SelectorInstrumentor(selector, instrumentor, NO); + IMP oldViewDidDisappearIMP = [selectorInstrumentor currentIMP]; + [selectorInstrumentor setReplacingBlock:^void(id _self, BOOL animated) { + if (oldViewDidDisappearIMP) { + GUL_INVOKE_ORIGINAL_IMP1(_self, selector, void, oldViewDidDisappearIMP, animated); + } + [[FPRScreenTraceTracker sharedInstance] viewControllerDidDisappear:_self]; + }]; +} + +- (void)registerInstrumentors { + dispatch_sync(GetInstrumentationQueue(), ^{ + FPRClassInstrumentor *instrumentor = + [[FPRClassInstrumentor alloc] initWithClass:[UIViewController class]]; + + if (![self registerClassInstrumentor:instrumentor]) { + FPRAssert(NO, @"UIViewController should only be instrumented once."); + } + + InstrumentViewDidAppear(self, instrumentor); + InstrumentViewDidDisappear(self, instrumentor); + + [instrumentor swizzle]; + }); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.h new file mode 100644 index 0000000..bb6d8be --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.h @@ -0,0 +1,38 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Google Data Transport event wrapper used for converting Fireperf nanopb object to + * GDTEvent object. + */ +@interface FPRGDTEvent : NSObject + +/** firebase_perf_v1_PerfMetric that is going to be converted. */ +@property(nonatomic, readonly) firebase_perf_v1_PerfMetric metric; + +- (instancetype)init NS_UNAVAILABLE; + +/** Converts a firebase_perf_v1_PerfMetric object to a GDTEvent. */ ++ (instancetype)gdtEventForPerfMetric:(firebase_perf_v1_PerfMetric)perfMetric; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.m new file mode 100644 index 0000000..2fab358 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTEvent.m @@ -0,0 +1,83 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import +#import + +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h" + +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +@interface FPRGDTEvent () + +/** Perf metric that is going to be converted. */ +@property(nonatomic) firebase_perf_v1_PerfMetric metric; + +/** + * Creates an instance of FPRGDTEvent. + * + * @param perfMetric Performance Event proto object that needs to be converted to FPRGDTEvent. + * @return Instance of FPRGDTEvent. + */ +- (instancetype)initForPerfMetric:(firebase_perf_v1_PerfMetric)perfMetric; + +@end + +@implementation FPRGDTEvent + ++ (instancetype)gdtEventForPerfMetric:(firebase_perf_v1_PerfMetric)perfMetric { + FPRGDTEvent *event = [[FPRGDTEvent alloc] initForPerfMetric:perfMetric]; + return event; +} + +- (instancetype)initForPerfMetric:(firebase_perf_v1_PerfMetric)perfMetric { + if (self = [super init]) { + _metric = perfMetric; + } + + return self; +} + +#pragma mark - GDTCOREventDataObject protocol methods + +- (NSData *)transportBytes { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, firebase_perf_v1_PerfMetric_fields, &_metric)) { + FPRLogError(kFPRTransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, firebase_perf_v1_PerfMetric_fields, &_metric)) { + FPRLogError(kFPRTransportBytesError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + return CFBridgingRelease(dataRef); +} + +- (void)dealloc { + pb_release(firebase_perf_v1_PerfMetric_fields, &_metric); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler+Private.h new file mode 100644 index 0000000..ec2e9a1 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler+Private.h @@ -0,0 +1,35 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h" + +@class FPRConfigurations; + +/** + * Extension that is added on top of the class FPRGDTLogSampler to aid unit tests. + */ +@interface FPRGDTLogSampler () + +/** + * A custom initializer used only in the case of testing. + * + * @param flags Configuration flags to be initialized with. + * @param bucket Bucket identifier to decide on dropping or sending the events based on the sampling + * rate for traces. + * @return Instance of FPRLogSampler. + */ +- (nullable instancetype)initWithFlags:(nonnull FPRConfigurations *)flags + samplingThreshold:(double)bucket NS_DESIGNATED_INITIALIZER; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h new file mode 100644 index 0000000..90704ef --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h @@ -0,0 +1,26 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * A log transformer that determines if a Firebase Performance event should be sampled. + */ +@interface FPRGDTLogSampler : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.m new file mode 100644 index 0000000..19fb3a8 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.m @@ -0,0 +1,135 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h" + +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h" + +@class FPRGDTEvent; + +@interface FPRGDTLogSampler () + +/** Configuration flags that are used for sampling. */ +@property(nonatomic, readonly) FPRConfigurations *flags; + +/** Vendor identifier used as the random seed for sampling. */ +@property(nonatomic, readonly) double samplingBucketId; + +@end + +@implementation FPRGDTLogSampler + +- (instancetype)init { + double randomNumberBetween0And1 = ((double)arc4random() / UINT_MAX); + return [self initWithFlags:[FPRConfigurations sharedInstance] + samplingThreshold:randomNumberBetween0And1]; +} + +- (instancetype)initWithFlags:(FPRConfigurations *)flags samplingThreshold:(double)bucket { + self = [super init]; + if (self) { + _flags = flags; + + _samplingBucketId = bucket; + if (bucket > 1 || bucket < 0.0) { + _samplingBucketId = 1.0; + } + } + return self; +} + +/** + * Samples PerfMetric Events based on sampling logic, event that should be + * dropped will return nil in this transformer. + * + * @param event The event to be evaluated by sampling logic. + * @return A transformed event, or nil if the transformation dropped the event. + */ +- (GDTCOREvent *)transformGDTEvent:(GDTCOREvent *)event { + // An event is sampled means that the event is dropped. + + // If the current active session is verbose, do not sample any event. + if (![event.dataObject isKindOfClass:[FPRGDTEvent class]]) { + return event; + } + + FPRGDTEvent *gdtEvent = (FPRGDTEvent *)event.dataObject; + firebase_perf_v1_PerfMetric perfMetric = gdtEvent.metric; + + // If it is a gaugeEvent, do not sample. + if (perfMetric.has_gauge_metric) { + return event; + } + + // If the traceMetric contains a verbose session, do not sample. + if (perfMetric.has_trace_metric) { + firebase_perf_v1_TraceMetric traceMetric = perfMetric.trace_metric; + // Sessions are ordered so that the first session is the most verbose one. + if (traceMetric.perf_sessions_count > 0) { + firebase_perf_v1_PerfSession firstSession = traceMetric.perf_sessions[0]; + if (firstSession.session_verbosity_count > 0) { + firebase_perf_v1_SessionVerbosity firstVerbosity = firstSession.session_verbosity[0]; + if (firstVerbosity == firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS) { + return event; + } + } + } + } + + // If the networkMetric contains a verbose session, do not sample. + if (perfMetric.has_network_request_metric) { + firebase_perf_v1_NetworkRequestMetric networkMetric = perfMetric.network_request_metric; + // Sessions are ordered so that the first session is the most verbose one. + if (networkMetric.perf_sessions_count > 0) { + firebase_perf_v1_PerfSession firstSession = networkMetric.perf_sessions[0]; + if (firstSession.session_verbosity_count > 0) { + firebase_perf_v1_SessionVerbosity firstVerbosity = firstSession.session_verbosity[0]; + if (firstVerbosity == firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS) { + return event; + } + } + } + } + + if ([self shouldDropEvent:perfMetric]) { + return nil; + } + + return event; +} + +/** + * Determines if the log should be dropped based on sampling configuration from remote + * configuration. + * + * @param event The event on which the decision would be made. + * @return Boolean value of YES if the log should be dropped/sampled out. Otherwise, NO. + */ +- (BOOL)shouldDropEvent:(firebase_perf_v1_PerfMetric)event { + // Find the correct sampling rate and make the decision to drop or log the event. + float samplingRate = [self.flags logTraceSamplingRate]; + if (event.has_network_request_metric) { + samplingRate = [self.flags logNetworkSamplingRate]; + } + + return self.samplingBucketId >= samplingRate; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.h new file mode 100644 index 0000000..fb7d8dd --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.h @@ -0,0 +1,48 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Logger used to dispatch events to Google Data Transport layer. */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRGDTLogger : NSObject + +/** Log source initialized against. */ +@property(nonatomic, readonly) NSInteger logSource; + +/** Default initializer. */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Instantiates an instance of this class. + * + * @param logSource The log source for this logger to be used. + * @return Instance of FPRGDTLogger. + */ +- (instancetype)initWithLogSource:(NSInteger)logSource NS_DESIGNATED_INITIALIZER; + +/** + * Logs an event that needs to be dispatched. + * + * @remark Events are logged/dispatched asynchronously using a serial dispatch queue. + * @param event The event to log. + */ +- (void)logEvent:(firebase_perf_v1_PerfMetric)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.m new file mode 100644 index 0000000..fb66b36 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger.m @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogger.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogger_Private.h" + +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogSampler.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h" + +#import + +#import "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +@implementation FPRGDTLogger + +- (instancetype)initWithLogSource:(NSInteger)logSource { + if (self = [super init]) { + _logSource = logSource; + + _queue = dispatch_queue_create("com.google.FPRGDTLogger", DISPATCH_QUEUE_SERIAL); + _configurations = [FPRConfigurations sharedInstance]; + FPRGDTLogSampler *logSampler = [[FPRGDTLogSampler alloc] init]; + FPRGDTRateLimiter *rateLimiter = [[FPRGDTRateLimiter alloc] init]; + + _gdtfllTransport = [[GDTCORTransport alloc] initWithMappingID:@(logSource).stringValue + transformers:@[ logSampler, rateLimiter ] + target:kGDTCORTargetFLL]; + _isSimulator = NO; + // If app is running on simulator, environment variable SIMULATOR_UDID exists. + // Otherwise, SIMULATOR_UDID is not provided when app is running on real device. + // For development, developers can dispatch performance events immediately if + // they are running app on simulator, so it can expedite development process. + if ([[[NSProcessInfo processInfo] environment] objectForKey:@"SIMULATOR_UDID"]) { + _isSimulator = YES; + } + + _instanceSeed = -1.0; // -1.0 means instanceSeed has not been computed. + } + + return self; +} + +- (void)logEvent:(firebase_perf_v1_PerfMetric)event { + GDTCORTransport *eventTransporter = self.gdtfllTransport; + + dispatch_async(self.queue, ^{ + GDTCOREvent *gdtEvent = [eventTransporter eventForTransport]; + if (self.isSimulator) { + gdtEvent.qosTier = GDTCOREventQoSFast; + } else { + gdtEvent.qosTier = GDTCOREventQosDefault; + } + gdtEvent.dataObject = [FPRGDTEvent gdtEventForPerfMetric:event]; + [eventTransporter sendDataEvent:gdtEvent]; + }); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger_Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger_Private.h new file mode 100644 index 0000000..ee144bd --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTLogger_Private.h @@ -0,0 +1,46 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FirebasePerformance/Sources/Loggers/FPRGDTLogger.h" + +#import +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +/** FPRGDTLogger private definition used for unit testing. */ +@interface FPRGDTLogger () + +/** Log source for which the logger is being used. */ +@property(nonatomic, readwrite) NSInteger logSource; + +/** Google Data Transport instance for FLL. */ +@property(nonatomic, readwrite) GDTCORTransport *gdtfllTransport; + +/** Serial queue used for logging events to the GDT Transport layer. */ +@property(nonatomic, readonly) dispatch_queue_t queue; + +/** Boolean to see if the App is running on simulator or actual device. + * isSimulator is set to YES if environment variable contains SIMULATOR_UDID, NO otherwise.*/ +@property(nonatomic, readwrite) BOOL isSimulator; + +/** Boolean to see if the App is built in debug mode or release mode. + * isDebugBuild is set to YES if !NDEBUG, NO otherwise.*/ +@property(nonatomic, readwrite) FPRConfigurations *configurations; + +/** Seed value decided based on installation ID to determine if the event should be sent to FLL. + */ +@property(nonatomic, readwrite) float instanceSeed; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter+Private.h new file mode 100644 index 0000000..7cf4ede --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter+Private.h @@ -0,0 +1,73 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h" + +#import + +#import "FirebasePerformance/Sources/Common/FPRPerfDate.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * Extension that is added on top of the class FPRGDTRateLimiter to make the + * private methods visible between the implementation file and the unit tests. + */ +@interface FPRGDTRateLimiter () + +/** + * Number of events that are allowed per minute. This is an internal variable used only for unit + * testing. + */ +@property(nonatomic) CGFloat overrideRate; + +/** + * Number of network events that are allowed per minute. This is an internal variable used only for + * unit testing. + */ +@property(nonatomic) CGFloat overrideNetworkRate; + +/** Number of trace events that can be sent in burst per minute. */ +@property(nonatomic) NSInteger traceEventBurstSize; + +/** Number of network events that can be sent in burst per minute. */ +@property(nonatomic) NSInteger networkEventburstSize; + +/** Total number of trace events that are allowed to be sent . */ +@property(nonatomic) NSInteger allowedTraceEventsCount; + +/** Number of network events that are allowed to be sent . */ +@property(nonatomic) NSInteger allowedNetworkEventsCount; + +/** Time at which the last trace event was sent. */ +@property(nonatomic) NSDate *lastTraceEventTime; + +/** Time at which the last network event was sent. */ +@property(nonatomic) NSDate *lastNetworkEventTime; + +/** @brief Override configurations. */ +@property(nonatomic) FPRConfigurations *configurations; + +/** + * Creates an instance of the FPRGDTRateLimiter with the defined date. + * + * @param date The date object used for time calculations. + * @return An instance of the rate limiter. + */ +- (instancetype)initWithDate:(id)date; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h new file mode 100644 index 0000000..7c6a632 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * FPRGDTRateLimiter class helps in limiting the number of events that are sent + * to the backend. This is based on the token bucket rate limiting algorithm. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FPRGDTRateLimiter : NSObject + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.m new file mode 100644 index 0000000..f7a7f42 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.m @@ -0,0 +1,219 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTRateLimiter+Private.h" + +#import +#import + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" +#import "FirebasePerformance/Sources/Common/FPRPerfDate.h" +#import "FirebasePerformance/Sources/Loggers/FPRGDTEvent.h" + +#import + +@interface FPRGDTRateLimiter () + +/** + * Internal date object for setting the time of transformers, which will be used for setting the + * time for trace events and network events. + */ +@property(nonatomic) id date; + +@end + +@implementation FPRGDTRateLimiter + +- (instancetype)initWithDate:(id)date { + FPRGDTRateLimiter *transformer = [[self.class alloc] init]; + transformer.date = date; + transformer.lastTraceEventTime = [date now]; + transformer.lastNetworkEventTime = [date now]; + return transformer; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _date = [[FPRPerfDate alloc] init]; + + // Set lastTraceEventTime to default as this would get reset once we receive the first event. + _lastTraceEventTime = [_date now]; + _lastNetworkEventTime = [_date now]; + + _configurations = [FPRConfigurations sharedInstance]; + + _allowedTraceEventsCount = [_configurations foregroundEventCount]; + _allowedNetworkEventsCount = [_configurations foregroundNetworkEventCount]; + if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) { + _allowedTraceEventsCount = [_configurations backgroundEventCount]; + _allowedNetworkEventsCount = [_configurations backgroundNetworkEventCount]; + } + } + return self; +} + +#pragma mark - Transformer methods +/** + * Rate limit PerfMetric Events based on rate limiting logic, event that should be + * dropped will return nil in this transformer. + * + * @param logEvent The event to be evaluated by rate limiting logic. + * @return A transformed event, or nil if the transformation dropped the event. + */ +- (GDTCOREvent *)transformGDTEvent:(nonnull GDTCOREvent *)logEvent { + if ([logEvent.dataObject isKindOfClass:[FPRGDTEvent class]]) { + FPRGDTEvent *gdtEvent = (FPRGDTEvent *)logEvent.dataObject; + firebase_perf_v1_PerfMetric perfMetric = gdtEvent.metric; + + if (perfMetric.has_trace_metric) { + firebase_perf_v1_TraceMetric traceMetric = perfMetric.trace_metric; + // If it is an internal trace event, skip rate limiting. + if (traceMetric.is_auto) { + return logEvent; + } + } + } + + CGFloat rate = [self resolvedTraceRate]; + NSInteger eventCount = self.allowedTraceEventsCount; + NSInteger eventBurstSize = self.traceEventBurstSize; + NSDate *currentTime = [self.date now]; + NSTimeInterval interval = [currentTime timeIntervalSinceDate:self.lastTraceEventTime]; + if ([self isNetworkEvent:logEvent]) { + rate = [self resolvedNetworkRate]; + interval = [currentTime timeIntervalSinceDate:self.lastNetworkEventTime]; + eventCount = self.allowedNetworkEventsCount; + eventBurstSize = self.networkEventburstSize; + } + + eventCount = [self numberOfAllowedEvents:eventCount + timeInterval:interval + burstSize:eventBurstSize + eventRate:rate]; + + // Dispatch events only if the allowedEventCount is greater than zero, else drop the event. + if (eventCount > 0) { + if ([self isNetworkEvent:logEvent]) { + self.allowedNetworkEventsCount = --eventCount; + self.lastNetworkEventTime = currentTime; + } else { + self.allowedTraceEventsCount = --eventCount; + self.lastTraceEventTime = currentTime; + } + return logEvent; + } + + // Find the type of the log event. + FPRAppActivityTracker *appActivityTracker = [FPRAppActivityTracker sharedInstance]; + NSString *counterName = kFPRAppCounterNameTraceEventsRateLimited; + if ([self isNetworkEvent:logEvent]) { + counterName = kFPRAppCounterNameNetworkTraceEventsRateLimited; + } + [appActivityTracker.activeTrace incrementMetric:counterName byInt:1]; + + return nil; +} + +/** + * Calculates the number of allowed events given the time interval, rate and burst size. Token rate + * limiting algorithm implementation. + * + * @param allowedEventsCount Allowed events count on top of which new event count will be added. + * @param timeInterval Time interval for which event count needs to be calculated. + * @param burstSize Maximum number of events that can be allowed at any moment in time. + * @param rate Rate at which events should be added. + * @return Number of allowed events calculated. + */ +- (NSInteger)numberOfAllowedEvents:(NSInteger)allowedEventsCount + timeInterval:(NSTimeInterval)timeInterval + burstSize:(NSInteger)burstSize + eventRate:(CGFloat)rate { + NSTimeInterval minutesPassed = timeInterval / 60; + NSInteger newTokens = MAX(0, round(minutesPassed * rate)); + NSInteger calculatedAllowedEventsCount = MIN(allowedEventsCount + newTokens, burstSize); + return calculatedAllowedEventsCount; +} + +#pragma mark - Trace event rate related methods + +/** + * Rate at which the trace events can be accepted for a given log source. + * + * @return Event rate for the log source. This is based on the application's background or + * foreground state. + */ +- (CGFloat)resolvedTraceRate { + if (self.overrideRate > 0) { + return self.overrideRate; + } + + NSInteger eventCount = [self.configurations foregroundEventCount]; + NSInteger timeLimitInMinutes = [self.configurations foregroundEventTimeLimit]; + + if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) { + eventCount = [self.configurations backgroundEventCount]; + timeLimitInMinutes = [self.configurations backgroundEventTimeLimit]; + } + + CGFloat resolvedRate = eventCount / timeLimitInMinutes; + self.traceEventBurstSize = eventCount; + return resolvedRate; +} + +/** + * Rate at which the network events can be accepted for a given log source. + * + * @return Network event rate for the log source. This is based on the application's background or + * foreground state. + */ +- (CGFloat)resolvedNetworkRate { + if (self.overrideNetworkRate > 0) { + return self.overrideNetworkRate; + } + + NSInteger eventCount = [self.configurations foregroundNetworkEventCount]; + NSInteger timeLimitInMinutes = [self.configurations foregroundNetworkEventTimeLimit]; + + if ([FPRAppActivityTracker sharedInstance].applicationState == FPRApplicationStateBackground) { + eventCount = [self.configurations backgroundNetworkEventCount]; + timeLimitInMinutes = [self.configurations backgroundNetworkEventTimeLimit]; + } + + CGFloat resolvedRate = eventCount / timeLimitInMinutes; + self.networkEventburstSize = eventCount; + return resolvedRate; +} + +#pragma mark - Util methods + +/** + * Given an event, returns if it is a network event. No, otherwise. + * + * @param logEvent The event to transform. + * @return Yes if the event is a network event. Otherwise, No. + */ +- (BOOL)isNetworkEvent:(GDTCOREvent *)logEvent { + if ([logEvent.dataObject isKindOfClass:[FPRGDTEvent class]]) { + FPRGDTEvent *gdtEvent = (FPRGDTEvent *)logEvent.dataObject; + firebase_perf_v1_PerfMetric perfMetric = gdtEvent.metric; + if (perfMetric.has_network_request_metric) { + return YES; + } + } + return NO; +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.c b/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.c new file mode 100644 index 0000000..a56062e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.c @@ -0,0 +1,219 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const firebase_perf_v1_NetworkConnectionInfo_NetworkType firebase_perf_v1_NetworkConnectionInfo_network_type_default = firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE; +const firebase_perf_v1_NetworkConnectionInfo_MobileSubtype firebase_perf_v1_NetworkConnectionInfo_mobile_subtype_default = firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; + + +const pb_field_t firebase_perf_v1_PerfMetric_fields[6] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, firebase_perf_v1_PerfMetric, application_info, application_info, &firebase_perf_v1_ApplicationInfo_fields), + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_PerfMetric, trace_metric, application_info, &firebase_perf_v1_TraceMetric_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_PerfMetric, network_request_metric, trace_metric, &firebase_perf_v1_NetworkRequestMetric_fields), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_PerfMetric, gauge_metric, network_request_metric, &firebase_perf_v1_GaugeMetric_fields), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_PerfMetric, transport_info, gauge_metric, &firebase_perf_v1_TransportInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_TraceMetric_fields[9] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_TraceMetric, name, name, 0), + PB_FIELD( 2, BOOL , OPTIONAL, STATIC , OTHER, firebase_perf_v1_TraceMetric, is_auto, name, 0), + PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_TraceMetric, client_start_time_us, is_auto, 0), + PB_FIELD( 5, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_TraceMetric, duration_us, client_start_time_us, 0), + PB_FIELD( 6, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_TraceMetric, counters, duration_us, &firebase_perf_v1_TraceMetric_CountersEntry_fields), + PB_FIELD( 7, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_TraceMetric, subtraces, counters, &firebase_perf_v1_TraceMetric_fields), + PB_FIELD( 8, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_TraceMetric, custom_attributes, subtraces, &firebase_perf_v1_TraceMetric_CustomAttributesEntry_fields), + PB_FIELD( 9, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_TraceMetric, perf_sessions, custom_attributes, &firebase_perf_v1_PerfSession_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_TraceMetric_CountersEntry_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_TraceMetric_CountersEntry, key, key, 0), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_TraceMetric_CountersEntry, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_TraceMetric_CustomAttributesEntry_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_TraceMetric_CustomAttributesEntry, key, key, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_TraceMetric_CustomAttributesEntry, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_NetworkRequestMetric_fields[14] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_NetworkRequestMetric, url, url, 0), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, http_method, url, 0), + PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, request_payload_bytes, http_method, 0), + PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, response_payload_bytes, request_payload_bytes, 0), + PB_FIELD( 5, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, http_response_code, response_payload_bytes, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_NetworkRequestMetric, response_content_type, http_response_code, 0), + PB_FIELD( 7, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, client_start_time_us, response_content_type, 0), + PB_FIELD( 8, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, time_to_request_completed_us, client_start_time_us, 0), + PB_FIELD( 9, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, time_to_response_initiated_us, time_to_request_completed_us, 0), + PB_FIELD( 10, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, time_to_response_completed_us, time_to_response_initiated_us, 0), + PB_FIELD( 11, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkRequestMetric, network_client_error_reason, time_to_response_completed_us, 0), + PB_FIELD( 12, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_NetworkRequestMetric, custom_attributes, network_client_error_reason, &firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_fields), + PB_FIELD( 13, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_NetworkRequestMetric, perf_sessions, custom_attributes, &firebase_perf_v1_PerfSession_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry, key, key, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_PerfSession_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_PerfSession, session_id, session_id, 0), + PB_FIELD( 2, UENUM , REPEATED, POINTER , OTHER, firebase_perf_v1_PerfSession, session_verbosity, session_id, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_GaugeMetric_fields[6] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_GaugeMetric, session_id, session_id, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_GaugeMetric, cpu_metric_readings, session_id, &firebase_perf_v1_CpuMetricReading_fields), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetric, gauge_metadata, cpu_metric_readings, &firebase_perf_v1_GaugeMetadata_fields), + PB_FIELD( 4, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_GaugeMetric, android_memory_readings, gauge_metadata, &firebase_perf_v1_AndroidMemoryReading_fields), + PB_FIELD( 5, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_GaugeMetric, ios_memory_readings, android_memory_readings, &firebase_perf_v1_IosMemoryReading_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_CpuMetricReading_fields[4] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, firebase_perf_v1_CpuMetricReading, client_time_us, client_time_us, 0), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_CpuMetricReading, user_time_us, client_time_us, 0), + PB_FIELD( 3, INT64 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_CpuMetricReading, system_time_us, user_time_us, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_IosMemoryReading_fields[4] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, firebase_perf_v1_IosMemoryReading, client_time_us, client_time_us, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_IosMemoryReading, used_app_heap_memory_kb, client_time_us, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_IosMemoryReading, free_app_heap_memory_kb, used_app_heap_memory_kb, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_AndroidMemoryReading_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, firebase_perf_v1_AndroidMemoryReading, client_time_us, client_time_us, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_AndroidMemoryReading, used_app_java_heap_memory_kb, client_time_us, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_GaugeMetadata_fields[7] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_GaugeMetadata, process_name, process_name, 0), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetadata, cpu_clock_rate_khz, process_name, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetadata, device_ram_size_kb, cpu_clock_rate_khz, 0), + PB_FIELD( 4, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetadata, max_app_java_heap_memory_kb, device_ram_size_kb, 0), + PB_FIELD( 5, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetadata, max_encouraged_app_java_heap_memory_kb, max_app_java_heap_memory_kb, 0), + PB_FIELD( 6, INT32 , OPTIONAL, STATIC , OTHER, firebase_perf_v1_GaugeMetadata, cpu_processor_count, max_encouraged_app_java_heap_memory_kb, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_ApplicationInfo_fields[8] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_ApplicationInfo, google_app_id, google_app_id, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_ApplicationInfo, app_instance_id, google_app_id, 0), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_ApplicationInfo, android_app_info, app_instance_id, &firebase_perf_v1_AndroidApplicationInfo_fields), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_ApplicationInfo, ios_app_info, android_app_info, &firebase_perf_v1_IosApplicationInfo_fields), + PB_FIELD( 5, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_ApplicationInfo, application_process_state, ios_app_info, 0), + PB_FIELD( 6, MESSAGE , REPEATED, POINTER , OTHER, firebase_perf_v1_ApplicationInfo, custom_attributes, application_process_state, &firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_fields), + PB_FIELD( 7, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_ApplicationInfo, web_app_info, custom_attributes, &firebase_perf_v1_WebApplicationInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_fields[3] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_ApplicationInfo_CustomAttributesEntry, key, key, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_ApplicationInfo_CustomAttributesEntry, value, key, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_WebApplicationInfo_fields[6] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_WebApplicationInfo, sdk_version, sdk_version, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_WebApplicationInfo, page_url, sdk_version, 0), + PB_FIELD( 3, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_WebApplicationInfo, service_worker_status, page_url, 0), + PB_FIELD( 4, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_WebApplicationInfo, visibility_state, service_worker_status, 0), + PB_FIELD( 5, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_WebApplicationInfo, effective_connection_type, visibility_state, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_AndroidApplicationInfo_fields[4] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_AndroidApplicationInfo, package_name, package_name, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_AndroidApplicationInfo, sdk_version, package_name, 0), + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_AndroidApplicationInfo, version_name, sdk_version, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_NetworkConnectionInfo_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, firebase_perf_v1_NetworkConnectionInfo, network_type, network_type, &firebase_perf_v1_NetworkConnectionInfo_network_type_default), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, firebase_perf_v1_NetworkConnectionInfo, mobile_subtype, network_type, &firebase_perf_v1_NetworkConnectionInfo_mobile_subtype_default), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_IosApplicationInfo_fields[5] = { + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , FIRST, firebase_perf_v1_IosApplicationInfo, sdk_version, sdk_version, 0), + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_IosApplicationInfo, bundle_short_version, sdk_version, 0), + PB_FIELD( 4, BYTES , OPTIONAL, POINTER , OTHER, firebase_perf_v1_IosApplicationInfo, mcc_mnc, bundle_short_version, 0), + PB_FIELD( 5, MESSAGE , OPTIONAL, STATIC , OTHER, firebase_perf_v1_IosApplicationInfo, network_connection_info, mcc_mnc, &firebase_perf_v1_NetworkConnectionInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_perf_v1_TransportInfo_fields[2] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, firebase_perf_v1_TransportInfo, dispatch_destination, dispatch_destination, 0), + PB_LAST_FIELD +}; + + + + + + + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(firebase_perf_v1_PerfMetric, application_info) < 65536 && pb_membersize(firebase_perf_v1_PerfMetric, trace_metric) < 65536 && pb_membersize(firebase_perf_v1_PerfMetric, network_request_metric) < 65536 && pb_membersize(firebase_perf_v1_PerfMetric, gauge_metric) < 65536 && pb_membersize(firebase_perf_v1_PerfMetric, transport_info) < 65536 && pb_membersize(firebase_perf_v1_GaugeMetric, gauge_metadata) < 65536 && pb_membersize(firebase_perf_v1_ApplicationInfo, android_app_info) < 65536 && pb_membersize(firebase_perf_v1_ApplicationInfo, ios_app_info) < 65536 && pb_membersize(firebase_perf_v1_ApplicationInfo, web_app_info) < 65536 && pb_membersize(firebase_perf_v1_IosApplicationInfo, network_connection_info) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_firebase_perf_v1_PerfMetric_firebase_perf_v1_TraceMetric_firebase_perf_v1_TraceMetric_CountersEntry_firebase_perf_v1_TraceMetric_CustomAttributesEntry_firebase_perf_v1_NetworkRequestMetric_firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_firebase_perf_v1_PerfSession_firebase_perf_v1_GaugeMetric_firebase_perf_v1_CpuMetricReading_firebase_perf_v1_IosMemoryReading_firebase_perf_v1_AndroidMemoryReading_firebase_perf_v1_GaugeMetadata_firebase_perf_v1_ApplicationInfo_firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_firebase_perf_v1_WebApplicationInfo_firebase_perf_v1_AndroidApplicationInfo_firebase_perf_v1_NetworkConnectionInfo_firebase_perf_v1_IosApplicationInfo_firebase_perf_v1_TransportInfo) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(firebase_perf_v1_PerfMetric, application_info) < 256 && pb_membersize(firebase_perf_v1_PerfMetric, trace_metric) < 256 && pb_membersize(firebase_perf_v1_PerfMetric, network_request_metric) < 256 && pb_membersize(firebase_perf_v1_PerfMetric, gauge_metric) < 256 && pb_membersize(firebase_perf_v1_PerfMetric, transport_info) < 256 && pb_membersize(firebase_perf_v1_GaugeMetric, gauge_metadata) < 256 && pb_membersize(firebase_perf_v1_ApplicationInfo, android_app_info) < 256 && pb_membersize(firebase_perf_v1_ApplicationInfo, ios_app_info) < 256 && pb_membersize(firebase_perf_v1_ApplicationInfo, web_app_info) < 256 && pb_membersize(firebase_perf_v1_IosApplicationInfo, network_connection_info) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_firebase_perf_v1_PerfMetric_firebase_perf_v1_TraceMetric_firebase_perf_v1_TraceMetric_CountersEntry_firebase_perf_v1_TraceMetric_CustomAttributesEntry_firebase_perf_v1_NetworkRequestMetric_firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_firebase_perf_v1_PerfSession_firebase_perf_v1_GaugeMetric_firebase_perf_v1_CpuMetricReading_firebase_perf_v1_IosMemoryReading_firebase_perf_v1_AndroidMemoryReading_firebase_perf_v1_GaugeMetadata_firebase_perf_v1_ApplicationInfo_firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_firebase_perf_v1_WebApplicationInfo_firebase_perf_v1_AndroidApplicationInfo_firebase_perf_v1_NetworkConnectionInfo_firebase_perf_v1_IosApplicationInfo_firebase_perf_v1_TransportInfo) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h new file mode 100644 index 0000000..a8b5592 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Protogen/nanopb/perf_metric.nanopb.h @@ -0,0 +1,548 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_FIREBASE_PERF_V1_PERF_METRIC_NANOPB_H_INCLUDED +#define PB_FIREBASE_PERF_V1_PERF_METRIC_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _firebase_perf_v1_ApplicationProcessState { + firebase_perf_v1_ApplicationProcessState_APPLICATION_PROCESS_STATE_UNKNOWN = 0, + firebase_perf_v1_ApplicationProcessState_FOREGROUND = 1, + firebase_perf_v1_ApplicationProcessState_BACKGROUND = 2, + firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND = 3 +} firebase_perf_v1_ApplicationProcessState; +#define _firebase_perf_v1_ApplicationProcessState_MIN firebase_perf_v1_ApplicationProcessState_APPLICATION_PROCESS_STATE_UNKNOWN +#define _firebase_perf_v1_ApplicationProcessState_MAX firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND +#define _firebase_perf_v1_ApplicationProcessState_ARRAYSIZE ((firebase_perf_v1_ApplicationProcessState)(firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND+1)) + +typedef enum _firebase_perf_v1_SessionVerbosity { + firebase_perf_v1_SessionVerbosity_SESSION_VERBOSITY_NONE = 0, + firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS = 1 +} firebase_perf_v1_SessionVerbosity; +#define _firebase_perf_v1_SessionVerbosity_MIN firebase_perf_v1_SessionVerbosity_SESSION_VERBOSITY_NONE +#define _firebase_perf_v1_SessionVerbosity_MAX firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS +#define _firebase_perf_v1_SessionVerbosity_ARRAYSIZE ((firebase_perf_v1_SessionVerbosity)(firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS+1)) + +typedef enum _firebase_perf_v1_VisibilityState { + firebase_perf_v1_VisibilityState_VISIBILITY_STATE_UNKNOWN = 0, + firebase_perf_v1_VisibilityState_VISIBLE = 1, + firebase_perf_v1_VisibilityState_HIDDEN = 2, + firebase_perf_v1_VisibilityState_PRERENDER = 3, + firebase_perf_v1_VisibilityState_UNLOADED = 4 +} firebase_perf_v1_VisibilityState; +#define _firebase_perf_v1_VisibilityState_MIN firebase_perf_v1_VisibilityState_VISIBILITY_STATE_UNKNOWN +#define _firebase_perf_v1_VisibilityState_MAX firebase_perf_v1_VisibilityState_UNLOADED +#define _firebase_perf_v1_VisibilityState_ARRAYSIZE ((firebase_perf_v1_VisibilityState)(firebase_perf_v1_VisibilityState_UNLOADED+1)) + +typedef enum _firebase_perf_v1_ServiceWorkerStatus { + firebase_perf_v1_ServiceWorkerStatus_SERVICE_WORKER_STATUS_UNKNOWN = 0, + firebase_perf_v1_ServiceWorkerStatus_UNSUPPORTED = 1, + firebase_perf_v1_ServiceWorkerStatus_CONTROLLED = 2, + firebase_perf_v1_ServiceWorkerStatus_UNCONTROLLED = 3 +} firebase_perf_v1_ServiceWorkerStatus; +#define _firebase_perf_v1_ServiceWorkerStatus_MIN firebase_perf_v1_ServiceWorkerStatus_SERVICE_WORKER_STATUS_UNKNOWN +#define _firebase_perf_v1_ServiceWorkerStatus_MAX firebase_perf_v1_ServiceWorkerStatus_UNCONTROLLED +#define _firebase_perf_v1_ServiceWorkerStatus_ARRAYSIZE ((firebase_perf_v1_ServiceWorkerStatus)(firebase_perf_v1_ServiceWorkerStatus_UNCONTROLLED+1)) + +typedef enum _firebase_perf_v1_EffectiveConnectionType { + firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_UNKNOWN = 0, + firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_SLOW_2G = 1, + firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_2G = 2, + firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_3G = 3, + firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_4G = 4 +} firebase_perf_v1_EffectiveConnectionType; +#define _firebase_perf_v1_EffectiveConnectionType_MIN firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_UNKNOWN +#define _firebase_perf_v1_EffectiveConnectionType_MAX firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_4G +#define _firebase_perf_v1_EffectiveConnectionType_ARRAYSIZE ((firebase_perf_v1_EffectiveConnectionType)(firebase_perf_v1_EffectiveConnectionType_EFFECTIVE_CONNECTION_TYPE_4G+1)) + +typedef enum _firebase_perf_v1_NetworkRequestMetric_HttpMethod { + firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN = 0, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_GET = 1, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_PUT = 2, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_POST = 3, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_DELETE = 4, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_HEAD = 5, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_PATCH = 6, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_OPTIONS = 7, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_TRACE = 8, + firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT = 9 +} firebase_perf_v1_NetworkRequestMetric_HttpMethod; +#define _firebase_perf_v1_NetworkRequestMetric_HttpMethod_MIN firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN +#define _firebase_perf_v1_NetworkRequestMetric_HttpMethod_MAX firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT +#define _firebase_perf_v1_NetworkRequestMetric_HttpMethod_ARRAYSIZE ((firebase_perf_v1_NetworkRequestMetric_HttpMethod)(firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT+1)) + +typedef enum _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason { + firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_NETWORK_CLIENT_ERROR_REASON_UNKNOWN = 0, + firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR = 1 +} firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason; +#define _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_MIN firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_NETWORK_CLIENT_ERROR_REASON_UNKNOWN +#define _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_MAX firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR +#define _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_ARRAYSIZE ((firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason)(firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR+1)) + +typedef enum _firebase_perf_v1_NetworkConnectionInfo_NetworkType { + firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE = -1, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE = 0, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIFI = 1, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIMAX = 6, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_DUMMY = 8, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_ETHERNET = 9, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_PROXY = 16, + firebase_perf_v1_NetworkConnectionInfo_NetworkType_VPN = 17 +} firebase_perf_v1_NetworkConnectionInfo_NetworkType; +#define _firebase_perf_v1_NetworkConnectionInfo_NetworkType_MIN firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE +#define _firebase_perf_v1_NetworkConnectionInfo_NetworkType_MAX firebase_perf_v1_NetworkConnectionInfo_NetworkType_VPN +#define _firebase_perf_v1_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((firebase_perf_v1_NetworkConnectionInfo_NetworkType)(firebase_perf_v1_NetworkConnectionInfo_NetworkType_VPN+1)) + +typedef enum _firebase_perf_v1_NetworkConnectionInfo_MobileSubtype { + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_GPRS = 1, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EDGE = 2, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UMTS = 3, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA = 4, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_RTT = 7, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSDPA = 8, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSUPA = 9, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSPA = 10, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_IDEN = 11, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_LTE = 13, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EHRPD = 14, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSPAP = 15, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_GSM = 16, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_IWLAN = 18, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19, + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_COMBINED = 100 +} firebase_perf_v1_NetworkConnectionInfo_MobileSubtype; +#define _firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_MIN firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE +#define _firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_MAX firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_COMBINED +#define _firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((firebase_perf_v1_NetworkConnectionInfo_MobileSubtype)(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_COMBINED+1)) + +typedef enum _firebase_perf_v1_TransportInfo_DispatchDestination { + firebase_perf_v1_TransportInfo_DispatchDestination_SOURCE_UNKNOWN = 0, + firebase_perf_v1_TransportInfo_DispatchDestination_FL_LEGACY_V1 = 1 +} firebase_perf_v1_TransportInfo_DispatchDestination; +#define _firebase_perf_v1_TransportInfo_DispatchDestination_MIN firebase_perf_v1_TransportInfo_DispatchDestination_SOURCE_UNKNOWN +#define _firebase_perf_v1_TransportInfo_DispatchDestination_MAX firebase_perf_v1_TransportInfo_DispatchDestination_FL_LEGACY_V1 +#define _firebase_perf_v1_TransportInfo_DispatchDestination_ARRAYSIZE ((firebase_perf_v1_TransportInfo_DispatchDestination)(firebase_perf_v1_TransportInfo_DispatchDestination_FL_LEGACY_V1+1)) + +/* Struct definitions */ +typedef struct _firebase_perf_v1_AndroidApplicationInfo { + pb_bytes_array_t *package_name; + pb_bytes_array_t *sdk_version; + pb_bytes_array_t *version_name; +/* @@protoc_insertion_point(struct:firebase_perf_v1_AndroidApplicationInfo) */ +} firebase_perf_v1_AndroidApplicationInfo; + +typedef struct _firebase_perf_v1_ApplicationInfo_CustomAttributesEntry { + pb_bytes_array_t *key; + pb_bytes_array_t *value; +/* @@protoc_insertion_point(struct:firebase_perf_v1_ApplicationInfo_CustomAttributesEntry) */ +} firebase_perf_v1_ApplicationInfo_CustomAttributesEntry; + +typedef struct _firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry { + pb_bytes_array_t *key; + pb_bytes_array_t *value; +/* @@protoc_insertion_point(struct:firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry) */ +} firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry; + +typedef struct _firebase_perf_v1_PerfSession { + pb_bytes_array_t *session_id; + pb_size_t session_verbosity_count; + firebase_perf_v1_SessionVerbosity *session_verbosity; +/* @@protoc_insertion_point(struct:firebase_perf_v1_PerfSession) */ +} firebase_perf_v1_PerfSession; + +typedef struct _firebase_perf_v1_TraceMetric_CustomAttributesEntry { + pb_bytes_array_t *key; + pb_bytes_array_t *value; +/* @@protoc_insertion_point(struct:firebase_perf_v1_TraceMetric_CustomAttributesEntry) */ +} firebase_perf_v1_TraceMetric_CustomAttributesEntry; + +typedef struct _firebase_perf_v1_AndroidMemoryReading { + bool has_client_time_us; + int64_t client_time_us; + bool has_used_app_java_heap_memory_kb; + int32_t used_app_java_heap_memory_kb; +/* @@protoc_insertion_point(struct:firebase_perf_v1_AndroidMemoryReading) */ +} firebase_perf_v1_AndroidMemoryReading; + +typedef struct _firebase_perf_v1_CpuMetricReading { + bool has_client_time_us; + int64_t client_time_us; + bool has_user_time_us; + int64_t user_time_us; + bool has_system_time_us; + int64_t system_time_us; +/* @@protoc_insertion_point(struct:firebase_perf_v1_CpuMetricReading) */ +} firebase_perf_v1_CpuMetricReading; + +typedef struct _firebase_perf_v1_GaugeMetadata { + pb_bytes_array_t *process_name; + bool has_cpu_clock_rate_khz; + int32_t cpu_clock_rate_khz; + bool has_device_ram_size_kb; + int32_t device_ram_size_kb; + bool has_max_app_java_heap_memory_kb; + int32_t max_app_java_heap_memory_kb; + bool has_max_encouraged_app_java_heap_memory_kb; + int32_t max_encouraged_app_java_heap_memory_kb; + bool has_cpu_processor_count; + int32_t cpu_processor_count; +/* @@protoc_insertion_point(struct:firebase_perf_v1_GaugeMetadata) */ +} firebase_perf_v1_GaugeMetadata; + +typedef struct _firebase_perf_v1_IosMemoryReading { + bool has_client_time_us; + int64_t client_time_us; + bool has_used_app_heap_memory_kb; + int32_t used_app_heap_memory_kb; + bool has_free_app_heap_memory_kb; + int32_t free_app_heap_memory_kb; +/* @@protoc_insertion_point(struct:firebase_perf_v1_IosMemoryReading) */ +} firebase_perf_v1_IosMemoryReading; + +typedef struct _firebase_perf_v1_NetworkConnectionInfo { + bool has_network_type; + firebase_perf_v1_NetworkConnectionInfo_NetworkType network_type; + bool has_mobile_subtype; + firebase_perf_v1_NetworkConnectionInfo_MobileSubtype mobile_subtype; +/* @@protoc_insertion_point(struct:firebase_perf_v1_NetworkConnectionInfo) */ +} firebase_perf_v1_NetworkConnectionInfo; + +typedef struct _firebase_perf_v1_NetworkRequestMetric { + pb_bytes_array_t *url; + bool has_http_method; + firebase_perf_v1_NetworkRequestMetric_HttpMethod http_method; + bool has_request_payload_bytes; + int64_t request_payload_bytes; + bool has_response_payload_bytes; + int64_t response_payload_bytes; + bool has_http_response_code; + int32_t http_response_code; + pb_bytes_array_t *response_content_type; + bool has_client_start_time_us; + int64_t client_start_time_us; + bool has_time_to_request_completed_us; + int64_t time_to_request_completed_us; + bool has_time_to_response_initiated_us; + int64_t time_to_response_initiated_us; + bool has_time_to_response_completed_us; + int64_t time_to_response_completed_us; + bool has_network_client_error_reason; + firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason network_client_error_reason; + pb_size_t custom_attributes_count; + struct _firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry *custom_attributes; + pb_size_t perf_sessions_count; + struct _firebase_perf_v1_PerfSession *perf_sessions; +/* @@protoc_insertion_point(struct:firebase_perf_v1_NetworkRequestMetric) */ +} firebase_perf_v1_NetworkRequestMetric; + +typedef struct _firebase_perf_v1_TraceMetric { + pb_bytes_array_t *name; + bool has_is_auto; + bool is_auto; + bool has_client_start_time_us; + int64_t client_start_time_us; + bool has_duration_us; + int64_t duration_us; + pb_size_t counters_count; + struct _firebase_perf_v1_TraceMetric_CountersEntry *counters; + pb_size_t subtraces_count; + struct _firebase_perf_v1_TraceMetric *subtraces; + pb_size_t custom_attributes_count; + struct _firebase_perf_v1_TraceMetric_CustomAttributesEntry *custom_attributes; + pb_size_t perf_sessions_count; + struct _firebase_perf_v1_PerfSession *perf_sessions; +/* @@protoc_insertion_point(struct:firebase_perf_v1_TraceMetric) */ +} firebase_perf_v1_TraceMetric; + +typedef struct _firebase_perf_v1_TraceMetric_CountersEntry { + pb_bytes_array_t *key; + bool has_value; + int64_t value; +/* @@protoc_insertion_point(struct:firebase_perf_v1_TraceMetric_CountersEntry) */ +} firebase_perf_v1_TraceMetric_CountersEntry; + +typedef struct _firebase_perf_v1_TransportInfo { + bool has_dispatch_destination; + firebase_perf_v1_TransportInfo_DispatchDestination dispatch_destination; +/* @@protoc_insertion_point(struct:firebase_perf_v1_TransportInfo) */ +} firebase_perf_v1_TransportInfo; + +typedef struct _firebase_perf_v1_WebApplicationInfo { + pb_bytes_array_t *sdk_version; + pb_bytes_array_t *page_url; + bool has_service_worker_status; + firebase_perf_v1_ServiceWorkerStatus service_worker_status; + bool has_visibility_state; + firebase_perf_v1_VisibilityState visibility_state; + bool has_effective_connection_type; + firebase_perf_v1_EffectiveConnectionType effective_connection_type; +/* @@protoc_insertion_point(struct:firebase_perf_v1_WebApplicationInfo) */ +} firebase_perf_v1_WebApplicationInfo; + +typedef struct _firebase_perf_v1_GaugeMetric { + pb_bytes_array_t *session_id; + pb_size_t cpu_metric_readings_count; + struct _firebase_perf_v1_CpuMetricReading *cpu_metric_readings; + bool has_gauge_metadata; + firebase_perf_v1_GaugeMetadata gauge_metadata; + pb_size_t android_memory_readings_count; + struct _firebase_perf_v1_AndroidMemoryReading *android_memory_readings; + pb_size_t ios_memory_readings_count; + struct _firebase_perf_v1_IosMemoryReading *ios_memory_readings; +/* @@protoc_insertion_point(struct:firebase_perf_v1_GaugeMetric) */ +} firebase_perf_v1_GaugeMetric; + +typedef struct _firebase_perf_v1_IosApplicationInfo { + pb_bytes_array_t *sdk_version; + pb_bytes_array_t *bundle_short_version; + pb_bytes_array_t *mcc_mnc; + bool has_network_connection_info; + firebase_perf_v1_NetworkConnectionInfo network_connection_info; +/* @@protoc_insertion_point(struct:firebase_perf_v1_IosApplicationInfo) */ +} firebase_perf_v1_IosApplicationInfo; + +typedef struct _firebase_perf_v1_ApplicationInfo { + pb_bytes_array_t *google_app_id; + pb_bytes_array_t *app_instance_id; + bool has_android_app_info; + firebase_perf_v1_AndroidApplicationInfo android_app_info; + bool has_ios_app_info; + firebase_perf_v1_IosApplicationInfo ios_app_info; + bool has_application_process_state; + firebase_perf_v1_ApplicationProcessState application_process_state; + pb_size_t custom_attributes_count; + struct _firebase_perf_v1_ApplicationInfo_CustomAttributesEntry *custom_attributes; + bool has_web_app_info; + firebase_perf_v1_WebApplicationInfo web_app_info; +/* @@protoc_insertion_point(struct:firebase_perf_v1_ApplicationInfo) */ +} firebase_perf_v1_ApplicationInfo; + +typedef struct _firebase_perf_v1_PerfMetric { + bool has_application_info; + firebase_perf_v1_ApplicationInfo application_info; + bool has_trace_metric; + firebase_perf_v1_TraceMetric trace_metric; + bool has_network_request_metric; + firebase_perf_v1_NetworkRequestMetric network_request_metric; + bool has_gauge_metric; + firebase_perf_v1_GaugeMetric gauge_metric; + bool has_transport_info; + firebase_perf_v1_TransportInfo transport_info; +/* @@protoc_insertion_point(struct:firebase_perf_v1_PerfMetric) */ +} firebase_perf_v1_PerfMetric; + +/* Default values for struct fields */ +extern const firebase_perf_v1_NetworkConnectionInfo_NetworkType firebase_perf_v1_NetworkConnectionInfo_network_type_default; +extern const firebase_perf_v1_NetworkConnectionInfo_MobileSubtype firebase_perf_v1_NetworkConnectionInfo_mobile_subtype_default; + +/* Initializer values for message structs */ +#define firebase_perf_v1_PerfMetric_init_default {false, firebase_perf_v1_ApplicationInfo_init_default, false, firebase_perf_v1_TraceMetric_init_default, false, firebase_perf_v1_NetworkRequestMetric_init_default, false, firebase_perf_v1_GaugeMetric_init_default, false, firebase_perf_v1_TransportInfo_init_default} +#define firebase_perf_v1_TraceMetric_init_default {NULL, false, 0, false, 0, false, 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL} +#define firebase_perf_v1_TraceMetric_CountersEntry_init_default {NULL, false, 0} +#define firebase_perf_v1_TraceMetric_CustomAttributesEntry_init_default {NULL, NULL} +#define firebase_perf_v1_NetworkRequestMetric_init_default {NULL, false, _firebase_perf_v1_NetworkRequestMetric_HttpMethod_MIN, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, false, 0, false, 0, false, _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_MIN, 0, NULL, 0, NULL} +#define firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_init_default {NULL, NULL} +#define firebase_perf_v1_PerfSession_init_default {NULL, 0, NULL} +#define firebase_perf_v1_GaugeMetric_init_default {NULL, 0, NULL, false, firebase_perf_v1_GaugeMetadata_init_default, 0, NULL, 0, NULL} +#define firebase_perf_v1_CpuMetricReading_init_default {false, 0, false, 0, false, 0} +#define firebase_perf_v1_IosMemoryReading_init_default {false, 0, false, 0, false, 0} +#define firebase_perf_v1_AndroidMemoryReading_init_default {false, 0, false, 0} +#define firebase_perf_v1_GaugeMetadata_init_default {NULL, false, 0, false, 0, false, 0, false, 0, false, 0} +#define firebase_perf_v1_ApplicationInfo_init_default {NULL, NULL, false, firebase_perf_v1_AndroidApplicationInfo_init_default, false, firebase_perf_v1_IosApplicationInfo_init_default, false, _firebase_perf_v1_ApplicationProcessState_MIN, 0, NULL, false, firebase_perf_v1_WebApplicationInfo_init_default} +#define firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_init_default {NULL, NULL} +#define firebase_perf_v1_WebApplicationInfo_init_default {NULL, NULL, false, _firebase_perf_v1_ServiceWorkerStatus_MIN, false, _firebase_perf_v1_VisibilityState_MIN, false, _firebase_perf_v1_EffectiveConnectionType_MIN} +#define firebase_perf_v1_AndroidApplicationInfo_init_default {NULL, NULL, NULL} +#define firebase_perf_v1_NetworkConnectionInfo_init_default {false, firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE, false, firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE} +#define firebase_perf_v1_IosApplicationInfo_init_default {NULL, NULL, NULL, false, firebase_perf_v1_NetworkConnectionInfo_init_default} +#define firebase_perf_v1_TransportInfo_init_default {false, _firebase_perf_v1_TransportInfo_DispatchDestination_MIN} +#define firebase_perf_v1_PerfMetric_init_zero {false, firebase_perf_v1_ApplicationInfo_init_zero, false, firebase_perf_v1_TraceMetric_init_zero, false, firebase_perf_v1_NetworkRequestMetric_init_zero, false, firebase_perf_v1_GaugeMetric_init_zero, false, firebase_perf_v1_TransportInfo_init_zero} +#define firebase_perf_v1_TraceMetric_init_zero {NULL, false, 0, false, 0, false, 0, 0, NULL, 0, NULL, 0, NULL, 0, NULL} +#define firebase_perf_v1_TraceMetric_CountersEntry_init_zero {NULL, false, 0} +#define firebase_perf_v1_TraceMetric_CustomAttributesEntry_init_zero {NULL, NULL} +#define firebase_perf_v1_NetworkRequestMetric_init_zero {NULL, false, _firebase_perf_v1_NetworkRequestMetric_HttpMethod_MIN, false, 0, false, 0, false, 0, NULL, false, 0, false, 0, false, 0, false, 0, false, _firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_MIN, 0, NULL, 0, NULL} +#define firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_init_zero {NULL, NULL} +#define firebase_perf_v1_PerfSession_init_zero {NULL, 0, NULL} +#define firebase_perf_v1_GaugeMetric_init_zero {NULL, 0, NULL, false, firebase_perf_v1_GaugeMetadata_init_zero, 0, NULL, 0, NULL} +#define firebase_perf_v1_CpuMetricReading_init_zero {false, 0, false, 0, false, 0} +#define firebase_perf_v1_IosMemoryReading_init_zero {false, 0, false, 0, false, 0} +#define firebase_perf_v1_AndroidMemoryReading_init_zero {false, 0, false, 0} +#define firebase_perf_v1_GaugeMetadata_init_zero {NULL, false, 0, false, 0, false, 0, false, 0, false, 0} +#define firebase_perf_v1_ApplicationInfo_init_zero {NULL, NULL, false, firebase_perf_v1_AndroidApplicationInfo_init_zero, false, firebase_perf_v1_IosApplicationInfo_init_zero, false, _firebase_perf_v1_ApplicationProcessState_MIN, 0, NULL, false, firebase_perf_v1_WebApplicationInfo_init_zero} +#define firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_init_zero {NULL, NULL} +#define firebase_perf_v1_WebApplicationInfo_init_zero {NULL, NULL, false, _firebase_perf_v1_ServiceWorkerStatus_MIN, false, _firebase_perf_v1_VisibilityState_MIN, false, _firebase_perf_v1_EffectiveConnectionType_MIN} +#define firebase_perf_v1_AndroidApplicationInfo_init_zero {NULL, NULL, NULL} +#define firebase_perf_v1_NetworkConnectionInfo_init_zero {false, _firebase_perf_v1_NetworkConnectionInfo_NetworkType_MIN, false, _firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_MIN} +#define firebase_perf_v1_IosApplicationInfo_init_zero {NULL, NULL, NULL, false, firebase_perf_v1_NetworkConnectionInfo_init_zero} +#define firebase_perf_v1_TransportInfo_init_zero {false, _firebase_perf_v1_TransportInfo_DispatchDestination_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define firebase_perf_v1_AndroidApplicationInfo_package_name_tag 1 +#define firebase_perf_v1_AndroidApplicationInfo_sdk_version_tag 2 +#define firebase_perf_v1_AndroidApplicationInfo_version_name_tag 3 +#define firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_key_tag 1 +#define firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_value_tag 2 +#define firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_key_tag 1 +#define firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_value_tag 2 +#define firebase_perf_v1_PerfSession_session_id_tag 1 +#define firebase_perf_v1_PerfSession_session_verbosity_tag 2 +#define firebase_perf_v1_TraceMetric_CustomAttributesEntry_key_tag 1 +#define firebase_perf_v1_TraceMetric_CustomAttributesEntry_value_tag 2 +#define firebase_perf_v1_AndroidMemoryReading_client_time_us_tag 1 +#define firebase_perf_v1_AndroidMemoryReading_used_app_java_heap_memory_kb_tag 2 +#define firebase_perf_v1_CpuMetricReading_client_time_us_tag 1 +#define firebase_perf_v1_CpuMetricReading_user_time_us_tag 2 +#define firebase_perf_v1_CpuMetricReading_system_time_us_tag 3 +#define firebase_perf_v1_GaugeMetadata_process_name_tag 1 +#define firebase_perf_v1_GaugeMetadata_cpu_clock_rate_khz_tag 2 +#define firebase_perf_v1_GaugeMetadata_cpu_processor_count_tag 6 +#define firebase_perf_v1_GaugeMetadata_device_ram_size_kb_tag 3 +#define firebase_perf_v1_GaugeMetadata_max_app_java_heap_memory_kb_tag 4 +#define firebase_perf_v1_GaugeMetadata_max_encouraged_app_java_heap_memory_kb_tag 5 +#define firebase_perf_v1_IosMemoryReading_client_time_us_tag 1 +#define firebase_perf_v1_IosMemoryReading_used_app_heap_memory_kb_tag 2 +#define firebase_perf_v1_IosMemoryReading_free_app_heap_memory_kb_tag 3 +#define firebase_perf_v1_NetworkConnectionInfo_network_type_tag 1 +#define firebase_perf_v1_NetworkConnectionInfo_mobile_subtype_tag 2 +#define firebase_perf_v1_NetworkRequestMetric_url_tag 1 +#define firebase_perf_v1_NetworkRequestMetric_http_method_tag 2 +#define firebase_perf_v1_NetworkRequestMetric_request_payload_bytes_tag 3 +#define firebase_perf_v1_NetworkRequestMetric_response_payload_bytes_tag 4 +#define firebase_perf_v1_NetworkRequestMetric_network_client_error_reason_tag 11 +#define firebase_perf_v1_NetworkRequestMetric_http_response_code_tag 5 +#define firebase_perf_v1_NetworkRequestMetric_response_content_type_tag 6 +#define firebase_perf_v1_NetworkRequestMetric_client_start_time_us_tag 7 +#define firebase_perf_v1_NetworkRequestMetric_time_to_request_completed_us_tag 8 +#define firebase_perf_v1_NetworkRequestMetric_time_to_response_initiated_us_tag 9 +#define firebase_perf_v1_NetworkRequestMetric_time_to_response_completed_us_tag 10 +#define firebase_perf_v1_NetworkRequestMetric_custom_attributes_tag 12 +#define firebase_perf_v1_NetworkRequestMetric_perf_sessions_tag 13 +#define firebase_perf_v1_TraceMetric_name_tag 1 +#define firebase_perf_v1_TraceMetric_is_auto_tag 2 +#define firebase_perf_v1_TraceMetric_client_start_time_us_tag 4 +#define firebase_perf_v1_TraceMetric_duration_us_tag 5 +#define firebase_perf_v1_TraceMetric_counters_tag 6 +#define firebase_perf_v1_TraceMetric_subtraces_tag 7 +#define firebase_perf_v1_TraceMetric_custom_attributes_tag 8 +#define firebase_perf_v1_TraceMetric_perf_sessions_tag 9 +#define firebase_perf_v1_TraceMetric_CountersEntry_key_tag 1 +#define firebase_perf_v1_TraceMetric_CountersEntry_value_tag 2 +#define firebase_perf_v1_TransportInfo_dispatch_destination_tag 1 +#define firebase_perf_v1_WebApplicationInfo_sdk_version_tag 1 +#define firebase_perf_v1_WebApplicationInfo_page_url_tag 2 +#define firebase_perf_v1_WebApplicationInfo_service_worker_status_tag 3 +#define firebase_perf_v1_WebApplicationInfo_visibility_state_tag 4 +#define firebase_perf_v1_WebApplicationInfo_effective_connection_type_tag 5 +#define firebase_perf_v1_GaugeMetric_session_id_tag 1 +#define firebase_perf_v1_GaugeMetric_gauge_metadata_tag 3 +#define firebase_perf_v1_GaugeMetric_cpu_metric_readings_tag 2 +#define firebase_perf_v1_GaugeMetric_android_memory_readings_tag 4 +#define firebase_perf_v1_GaugeMetric_ios_memory_readings_tag 5 +#define firebase_perf_v1_IosApplicationInfo_sdk_version_tag 2 +#define firebase_perf_v1_IosApplicationInfo_bundle_short_version_tag 3 +#define firebase_perf_v1_IosApplicationInfo_mcc_mnc_tag 4 +#define firebase_perf_v1_IosApplicationInfo_network_connection_info_tag 5 +#define firebase_perf_v1_ApplicationInfo_google_app_id_tag 1 +#define firebase_perf_v1_ApplicationInfo_app_instance_id_tag 2 +#define firebase_perf_v1_ApplicationInfo_android_app_info_tag 3 +#define firebase_perf_v1_ApplicationInfo_ios_app_info_tag 4 +#define firebase_perf_v1_ApplicationInfo_web_app_info_tag 7 +#define firebase_perf_v1_ApplicationInfo_application_process_state_tag 5 +#define firebase_perf_v1_ApplicationInfo_custom_attributes_tag 6 +#define firebase_perf_v1_PerfMetric_application_info_tag 1 +#define firebase_perf_v1_PerfMetric_trace_metric_tag 2 +#define firebase_perf_v1_PerfMetric_network_request_metric_tag 3 +#define firebase_perf_v1_PerfMetric_gauge_metric_tag 4 +#define firebase_perf_v1_PerfMetric_transport_info_tag 5 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t firebase_perf_v1_PerfMetric_fields[6]; +extern const pb_field_t firebase_perf_v1_TraceMetric_fields[9]; +extern const pb_field_t firebase_perf_v1_TraceMetric_CountersEntry_fields[3]; +extern const pb_field_t firebase_perf_v1_TraceMetric_CustomAttributesEntry_fields[3]; +extern const pb_field_t firebase_perf_v1_NetworkRequestMetric_fields[14]; +extern const pb_field_t firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_fields[3]; +extern const pb_field_t firebase_perf_v1_PerfSession_fields[3]; +extern const pb_field_t firebase_perf_v1_GaugeMetric_fields[6]; +extern const pb_field_t firebase_perf_v1_CpuMetricReading_fields[4]; +extern const pb_field_t firebase_perf_v1_IosMemoryReading_fields[4]; +extern const pb_field_t firebase_perf_v1_AndroidMemoryReading_fields[3]; +extern const pb_field_t firebase_perf_v1_GaugeMetadata_fields[7]; +extern const pb_field_t firebase_perf_v1_ApplicationInfo_fields[8]; +extern const pb_field_t firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_fields[3]; +extern const pb_field_t firebase_perf_v1_WebApplicationInfo_fields[6]; +extern const pb_field_t firebase_perf_v1_AndroidApplicationInfo_fields[4]; +extern const pb_field_t firebase_perf_v1_NetworkConnectionInfo_fields[3]; +extern const pb_field_t firebase_perf_v1_IosApplicationInfo_fields[5]; +extern const pb_field_t firebase_perf_v1_TransportInfo_fields[2]; + +/* Maximum encoded size of messages (where known) */ +/* firebase_perf_v1_PerfMetric_size depends on runtime parameters */ +/* firebase_perf_v1_TraceMetric_size depends on runtime parameters */ +/* firebase_perf_v1_TraceMetric_CountersEntry_size depends on runtime parameters */ +/* firebase_perf_v1_TraceMetric_CustomAttributesEntry_size depends on runtime parameters */ +/* firebase_perf_v1_NetworkRequestMetric_size depends on runtime parameters */ +/* firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry_size depends on runtime parameters */ +/* firebase_perf_v1_PerfSession_size depends on runtime parameters */ +/* firebase_perf_v1_GaugeMetric_size depends on runtime parameters */ +#define firebase_perf_v1_CpuMetricReading_size 33 +#define firebase_perf_v1_IosMemoryReading_size 33 +#define firebase_perf_v1_AndroidMemoryReading_size 22 +/* firebase_perf_v1_GaugeMetadata_size depends on runtime parameters */ +/* firebase_perf_v1_ApplicationInfo_size depends on runtime parameters */ +/* firebase_perf_v1_ApplicationInfo_CustomAttributesEntry_size depends on runtime parameters */ +/* firebase_perf_v1_WebApplicationInfo_size depends on runtime parameters */ +/* firebase_perf_v1_AndroidApplicationInfo_size depends on runtime parameters */ +#define firebase_perf_v1_NetworkConnectionInfo_size 13 +/* firebase_perf_v1_IosApplicationInfo_size depends on runtime parameters */ +#define firebase_perf_v1_TransportInfo_size 2 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define PERF_METRIC_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRHTTPMetric.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRHTTPMetric.h new file mode 100644 index 0000000..460efba --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRHTTPMetric.h @@ -0,0 +1,95 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FIRPerformanceAttributable.h" + +// clang-format off +// clang-format12 does a weird cascading indent of this enum. +/* Different HTTP methods. */ +typedef NS_ENUM(NSInteger, FIRHTTPMethod) { + /** HTTP Method GET */ + FIRHTTPMethodGET NS_SWIFT_NAME(get), + /** HTTP Method PUT */ + FIRHTTPMethodPUT NS_SWIFT_NAME(put), + /** HTTP Method POST */ + FIRHTTPMethodPOST NS_SWIFT_NAME(post), + /** HTTP Method DELETE */ + FIRHTTPMethodDELETE NS_SWIFT_NAME(delete), + /** HTTP Method HEAD */ + FIRHTTPMethodHEAD NS_SWIFT_NAME(head), + /** HTTP Method PATCH */ + FIRHTTPMethodPATCH NS_SWIFT_NAME(patch), + /** HTTP Method OPTIONS */ + FIRHTTPMethodOPTIONS NS_SWIFT_NAME(options), + /** HTTP Method TRACE */ + FIRHTTPMethodTRACE NS_SWIFT_NAME(trace), + /** HTTP Method CONNECT */ + FIRHTTPMethodCONNECT NS_SWIFT_NAME(connect) +} NS_SWIFT_NAME(HTTPMethod); +// clang-format on + +/** + * Instances of `HTTPMetric` can be used to record HTTP network request information. + */ +NS_SWIFT_NAME(HTTPMetric) +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +@interface FIRHTTPMetric : NSObject + +/** + * Creates HTTPMetric object for a network request. + * @param URL The URL for which the metrics are recorded. + * @param httpMethod HTTP method used by the request. + */ +- (nullable instancetype)initWithURL:(nonnull NSURL *)URL + HTTPMethod:(FIRHTTPMethod)httpMethod NS_SWIFT_NAME(init(url:httpMethod:)); + +/** + * Use `init(url:httpMethod:)` for Swift and `initWithURL:HTTPMethod:` for Objective-C. + */ +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + * @brief HTTP Response code. Values are greater than 0. + */ +@property(nonatomic, assign) NSInteger responseCode; + +/** + * @brief Size of the request payload. + */ +@property(nonatomic, assign) long requestPayloadSize; + +/** + * @brief Size of the response payload. + */ +@property(nonatomic, assign) long responsePayloadSize; + +/** + * @brief HTTP Response content type. + */ +@property(nonatomic, nullable, copy) NSString *responseContentType; + +/** + * Marks the start time of the request. + */ +- (void)start; + +/** + * Marks the end time of the response and queues the network request metric on the device for + * transmission. Check the logs if the metric is valid. + */ +- (void)stop; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h new file mode 100644 index 0000000..e9d1ed9 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h @@ -0,0 +1,76 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FIRTrace.h" + +/** + * This class allows you to configure the Firebase Performance Reporting SDK. It also provides the + * interfaces to create timers and enable or disable automatic metrics capture. + * + * This SDK uses a Firebase Installations ID to identify the app instance and periodically sends + * data to the Firebase backend (see `Installations.installationID(completion:)`). + * To stop this periodic sync, call `Installations.delete(completion:)` and + * either disable this SDK or set Performance.dataCollectionEnabled to false. + */ +NS_EXTENSION_UNAVAILABLE("FirebasePerformance does not support app extensions at this time.") +NS_SWIFT_NAME(Performance) +@interface FIRPerformance : NSObject + +/** + * Controls the capture of performance data. When this value is set to NO, none of the performance + * data will sent to the server. Default is true. + * + * This setting is persisted, and is applied on future invocations of your application. Once + * explicitly set, it overrides any settings in your Info.plist. + */ +@property(nonatomic, assign, getter=isDataCollectionEnabled) BOOL dataCollectionEnabled; + +/** + * Controls the instrumentation of the app to capture performance data. Setting this value to false + * has immediate effect only if it is done so before calling FirebaseApp.configure(). Otherwise it + * takes effect on the next app start. + * + * If set to false, the app will not be instrumented to collect performance + * data (in scenarios like `app_start`, networking monitoring). Default is true. + * + * This setting is persisted, and is applied on future invocations of your application. Once + * explicitly set, it overrides any settings in your `Info.plist`. + */ +@property(nonatomic, assign, getter=isInstrumentationEnabled) BOOL instrumentationEnabled; + +/** @return The shared instance. */ ++ (nonnull instancetype)sharedInstance NS_SWIFT_NAME(sharedInstance()); + +/** + * Creates an instance of Trace after creating the shared instance of Performance. The trace + * will automatically be started on a successful creation of the instance. The `name` of the trace + * cannot be an empty string. + * + * @param name The name of the trace. + * @return The Trace object. + */ ++ (nullable FIRTrace *)startTraceWithName:(nonnull NSString *)name NS_SWIFT_NAME(startTrace(name:)); + +/** + * Creates an instance of Trace. This API does not start the trace. To start the trace, use the + * `start()` method on the returned Trace object. The `name` cannot be an empty string. + * + * @param name The name of the Trace. + * @return The FIRTrace object. + */ +- (nullable FIRTrace *)traceWithName:(nonnull NSString *)name NS_SWIFT_NAME(trace(name:)); + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformanceAttributable.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformanceAttributable.h new file mode 100644 index 0000000..65f695e --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformanceAttributable.h @@ -0,0 +1,51 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** Defines the interface that allows adding/removing attributes to any object. + */ +NS_SWIFT_NAME(PerformanceAttributable) +@protocol FIRPerformanceAttributable + +/** List of attributes. */ +@property(nonatomic, nonnull, readonly) NSDictionary *attributes; + +/** + * Sets a value as a string for the specified attribute. Updates the value of the attribute if a + * value had already existed. + * + * @param value The value that needs to be set/updated for an attribute. If the length of the value + * exceeds the maximum allowed, the value will be truncated to the maximum allowed. + * @param attribute The name of the attribute. If the length of the value exceeds the maximum + * allowed, the value will be truncated to the maximum allowed. + */ +- (void)setValue:(nonnull NSString *)value forAttribute:(nonnull NSString *)attribute; + +/** + * Reads the value for the specified attribute. If the attribute does not exist, returns nil. + * + * @param attribute The name of the attribute. + * @return The value for the attribute. Returns nil if the attribute does not exist. + */ +- (nullable NSString *)valueForAttribute:(nonnull NSString *)attribute; + +/** + * Removes an attribute from the list. Does nothing if the attribute does not exist. + * + * @param attribute The name of the attribute. + */ +- (void)removeAttribute:(nonnull NSString *)attribute; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h new file mode 100644 index 0000000..bb487f5 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h @@ -0,0 +1,77 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "FIRPerformanceAttributable.h" + +/** + * FIRTrace objects contain information about a "Trace", which is a sequence of steps. Traces can be + * used to measure the time taken for a sequence of steps. + * Traces also include "Counters". Counters are used to track information which is cumulative in + * nature (e.g., Bytes downloaded). Counters are scoped to an FIRTrace object. + */ +NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.") +NS_SWIFT_NAME(Trace) +@interface FIRTrace : NSObject + +/** @brief Name of the trace. */ +@property(nonatomic, copy, readonly, nonnull) NSString *name; + +/** @brief Not a valid initializer. */ +- (nonnull instancetype)init NS_UNAVAILABLE; + +/** + * Starts the trace. + */ +- (void)start; + +/** + * Stops the trace if the trace is active. + */ +- (void)stop; + +#pragma mark - Metrics API + +/** + * Atomically increments the metric for the provided metric name with the provided value. If it is a + * new metric name, the metric value will be initialized to the value. Does nothing if the trace + * has not been started or has already been stopped. + * + * @param metricName The name of the metric to increment. + * @param incrementValue The value to increment the metric by. + */ +- (void)incrementMetric:(nonnull NSString *)metricName + byInt:(int64_t)incrementValue NS_SWIFT_NAME(incrementMetric(_:by:)); + +/** + * Gets the value of the metric for the provided metric name. If the metric doesn't exist, a 0 is + * returned. + * + * @param metricName The name of metric whose value to get. + * @return The value of the given metric or 0 if it hasn't yet been set. + */ +- (int64_t)valueForIntMetric:(nonnull NSString *)metricName NS_SWIFT_NAME(valueForMetric(_:)); + +/** + * Sets the value of the metric for the provided metric name to the provided value. Does nothing if + * the trace has not been started or has already been stopped. + * + * @param metricName The name of the metric to set. + * @param value The value to set the metric to. + */ +- (void)setIntValue:(int64_t)value + forMetric:(nonnull NSString *)metricName NS_SWIFT_NAME(setValue(_:forMetric:)); + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FirebasePerformance.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FirebasePerformance.h new file mode 100644 index 0000000..67bf9ae --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Public/FirebasePerformance/FirebasePerformance.h @@ -0,0 +1,18 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FIRHTTPMetric.h" +#import "FIRPerformance.h" +#import "FIRPerformanceAttributable.h" +#import "FIRTrace.h" diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Internal.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Internal.h new file mode 100644 index 0000000..3bd034b --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Internal.h @@ -0,0 +1,96 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Timer/FPRCounterList.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +#import "FirebasePerformance/Sources/FIRPerformance+Internal.h" + +/** + * Extension that is added on top of the class FIRTrace to make certain methods used internally + * within the SDK, but not public facing. A category could be ideal, but Firebase recommends not + * using categories as that mandates including -ObjC flag for build which is an extra step for the + * developer. + */ +@interface FIRTrace () + +/** @brief List of currently active counters. */ +@property(atomic, readonly, nonnull) NSDictionary *counters; + +/** @brief The number of active counters on the given trace. */ +@property(atomic, readonly) NSUInteger numberOfCounters; + +/** Denotes if the trace is internal. */ +@property(nonatomic, getter=isInternal) BOOL internal; + +/** @brief List of sessions the trace is associated with. */ +@property(nonnull, atomic, readonly) NSArray *sessions; + +/** + * Creates an instance of FIRTrace. + * + * @param name The name of the Trace. Name cannot be an empty string. + * + * @return An instance of FIRTrace. + */ +- (nullable instancetype)initWithName:(nonnull NSString *)name; + +/** + * Creates an instance of FIRTrace. + * + * @param name Name of the Trace. Name cannot be an empty string. + * + * @return An instance of FIRTrace. + */ +- (nullable instancetype)initTraceWithName:(nonnull NSString *)name NS_DESIGNATED_INITIALIZER; + +/** + * Creates an instance of internal FIRTrace. Internal FIRTrace objects do not have any validation on + * the name provided except that it cannot be empty. + * + * @param name Name of the Trace. Name cannot be an empty string. + * + * @return An instance of FIRTrace. + */ +- (nullable instancetype)initInternalTraceWithName:(nonnull NSString *)name; + +/** + * Starts the trace with a specified start time. + * + * @param startTime Start time of the trace. If the startTime is nil, current time will be set. + */ +- (void)startWithStartTime:(nullable NSDate *)startTime; + +/** + * Creates a stage inside the trace with a defined start time. This stops the already existing + * active stage if any and starts the new stage with the name provided. If the startTime is nil, the + * start time of the stage is set to the current date. + + * @param stageName Name of the stages. + * @param startTime Start time of the stage. + */ +- (void)startStageNamed:(nonnull NSString *)stageName startTime:(nullable NSDate *)startTime; + +/** Cancels the trace without sending an event to Google Data Transport. */ +- (void)cancel; + +/** + * Deletes a metric with the given name. If the metric doesnt exist, this has no effect. + * + * @param metricName The name of the metric to delete. + */ +- (void)deleteMetric:(nonnull NSString *)metricName; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Private.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Private.h new file mode 100644 index 0000000..52dd8ea --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace+Private.h @@ -0,0 +1,72 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Timer/FPRCounterList.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRSessionDetails.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRTraceBackgroundActivityTracker.h" + +#import "FirebasePerformance/Sources/FPRClient+Private.h" +#import "FirebasePerformance/Sources/FPRClient.h" + +/** + * Extension that is added on top of the class FIRTrace to make the private properties visible + * between the implementation file and the unit tests. + */ +@interface FIRTrace () + +/** @brief NSTimeInterval for which the trace was active. */ +@property(nonatomic, assign, readonly) NSTimeInterval totalTraceTimeInterval; + +/** @brief Start time of the trace since epoch. */ +@property(nonatomic, assign, readonly) NSTimeInterval startTimeSinceEpoch; + +/** + * Starts a stage with the given name. Multiple stages can have a same name. Starting a new stage + * would stop the previous active stage if any. + * + * @param stageName name of the Stage. + */ +- (void)startStageNamed:(nonnull NSString *)stageName; + +/** @brief List of stages in the trace. */ +@property(nonnull, nonatomic) FPRClient *fprClient; + +/** @brief List of stages in the trace. */ +@property(nonnull, nonatomic) NSMutableArray *stages; + +/** @brief The current active stage. */ +@property(nullable, nonatomic) FIRTrace *activeStage; + +/** List of counters managed by the Trace. */ +@property(nonnull, nonatomic, readonly) FPRCounterList *counterList; + +/** Background state of the trace. */ +@property(nonatomic, readonly) FPRTraceState backgroundTraceState; + +/** @brief List of sessions the trace is associated with. */ +@property(nonatomic, readwrite, nonnull) NSMutableArray *activeSessions; + +/** @brief Serial queue to manage sessionId updates. */ +@property(nonnull, nonatomic, readonly) dispatch_queue_t sessionIdSerialQueue; + +/** + * Verifies if the trace contains all necessary and valid information. + * + * @return A boolean stating if the Trace is complete. + */ +- (BOOL)isCompleteAndValid; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace.m new file mode 100644 index 0000000..dad096f --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FIRTrace.m @@ -0,0 +1,434 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRTrace.h" + +#import "FirebasePerformance/Sources/AppActivity/FPRAppActivityTracker.h" +#import "FirebasePerformance/Sources/AppActivity/FPRSessionManager.h" +#import "FirebasePerformance/Sources/Common/FPRConstants.h" +#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h" +#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h" +#import "FirebasePerformance/Sources/FPRClient.h" +#import "FirebasePerformance/Sources/FPRConsoleLogger.h" +#import "FirebasePerformance/Sources/FPRDataUtils.h" +#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h" +#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h" + +@interface FIRTrace () + +@property(nonatomic, copy, readwrite) NSString *name; + +/** Custom attributes managed internally. */ +@property(nonatomic) NSMutableDictionary *customAttributes; + +/** Serial queue to manage mutation of attributes. */ +@property(nonatomic, readwrite) dispatch_queue_t customAttributesSerialQueue; + +@property(nonatomic, readwrite) NSDate *startTime; + +@property(nonatomic, readwrite) NSDate *stopTime; + +/** Background activity tracker to know the background state of the trace. */ +@property(nonatomic) FPRTraceBackgroundActivityTracker *backgroundActivityTracker; + +/** Property that denotes if the trace is a stage. */ +@property(nonatomic) BOOL isStage; + +/** Stops an active stage that is currently active. */ +- (void)stopActiveStage; + +/** + * Updates the current trace with the session id. + * @param sessionDetails Updated session details of the currently active session. + */ +- (void)updateTraceWithSessionId:(FPRSessionDetails *)sessionDetails; + +@end + +@implementation FIRTrace + +- (instancetype)initWithName:(NSString *)name { + NSString *validatedName = FPRReservableName(name); + + FIRTrace *trace = [self initTraceWithName:validatedName]; + trace.internal = NO; + return trace; +} + +- (instancetype)initInternalTraceWithName:(NSString *)name { + FIRTrace *trace = [self initTraceWithName:name]; + trace.internal = YES; + return trace; +} + +- (instancetype)initTraceWithName:(NSString *)name { + BOOL tracingEnabled = [FPRConfigurations sharedInstance].isDataCollectionEnabled; + if (!tracingEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Trace feature is disabled."); + return nil; + } + + BOOL sdkEnabled = [[FPRConfigurations sharedInstance] sdkEnabled]; + if (!sdkEnabled) { + FPRLogInfo(kFPRTraceDisabled, @"Dropping event since Performance SDK is disabled."); + return nil; + } + + FPRAssert(name != nil, @"Name cannot be nil"); + FPRAssert(name.length > 0, @"Name cannot be an empty string"); + + if (name == nil || name.length == 0) { + FPRLogError(kFPRTraceNoName, @"Failed to initialize because of a nil or zero length name."); + return nil; + } + + self = [super init]; + if (self) { + _name = [name copy]; + _stages = [[NSMutableArray alloc] init]; + _counterList = [[FPRCounterList alloc] init]; + _customAttributes = [[NSMutableDictionary alloc] init]; + _customAttributesSerialQueue = + dispatch_queue_create("com.google.perf.customAttributes.trace", DISPATCH_QUEUE_SERIAL); + _sessionIdSerialQueue = + dispatch_queue_create("com.google.perf.sessionIds.trace", DISPATCH_QUEUE_SERIAL); + _activeSessions = [[NSMutableArray alloc] init]; + _isStage = NO; + _fprClient = [FPRClient sharedInstance]; + } + + return self; +} + +- (instancetype)init { + FPRAssert(NO, @"Not a valid initializer."); + return nil; +} + +- (void)dealloc { + // Track the number of traces that have started and not stopped. + if (!self.isStage && [self isTraceStarted] && ![self isTraceStopped]) { + FIRTrace *activeTrace = [FPRAppActivityTracker sharedInstance].activeTrace; + [activeTrace incrementMetric:kFPRAppCounterNameTraceNotStopped byInt:1]; + FPRLogError(kFPRTraceStartedNotStopped, @"Trace name %@ started, not stopped", self.name); + } + + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + [sessionManager.sessionNotificationCenter removeObserver:self + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; +} + +#pragma mark - Public instance methods + +- (void)start { + if (![self isTraceStarted]) { + if (!self.isStage) { + [[FPRSessionManager sharedInstance] collectAllGaugesOnce]; + } + self.startTime = [NSDate date]; + self.backgroundActivityTracker = [[FPRTraceBackgroundActivityTracker alloc] init]; + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + if (!self.isStage) { + [self updateTraceWithSessionId:[sessionManager.sessionDetails copy]]; + [sessionManager.sessionNotificationCenter addObserver:self + selector:@selector(sessionChanged:) + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; + } + } else { + FPRLogError(kFPRTraceAlreadyStopped, + @"Failed to start trace %@ because it has already been started and stopped.", + self.name); + } +} + +- (void)startWithStartTime:(NSDate *)startTime { + [self start]; + if (startTime) { + self.startTime = startTime; + } +} + +- (void)stop { + [self stopActiveStage]; + + if ([self isTraceActive]) { + self.stopTime = [NSDate date]; + [self.fprClient logTrace:self]; + if (!self.isStage) { + [[FPRSessionManager sharedInstance] collectAllGaugesOnce]; + } + } else { + FPRLogError(kFPRTraceNotStarted, + @"Failed to stop the trace %@ because it has not been started.", self.name); + } + + FPRSessionManager *sessionManager = [FPRSessionManager sharedInstance]; + [sessionManager.sessionNotificationCenter removeObserver:self + name:kFPRSessionIdUpdatedNotification + object:sessionManager]; +} + +- (void)cancel { + [self stopActiveStage]; + + if ([self isTraceActive]) { + self.stopTime = [NSDate date]; + } else { + FPRLogError(kFPRTraceNotStarted, + @"Failed to stop the trace %@ because it has not been started.", self.name); + } +} + +- (NSTimeInterval)totalTraceTimeInterval { + return [self.stopTime timeIntervalSinceDate:self.startTime]; +} + +- (NSTimeInterval)startTimeSinceEpoch { + return [self.startTime timeIntervalSince1970]; +} + +- (BOOL)isCompleteAndValid { + // Check if the trace time interval is valid. + if (self.totalTraceTimeInterval <= 0) { + return NO; + } + + // Check if the counter list is valid. + if (![self.counterList isValid]) { + return NO; + } + + // Check if the stages are valid. + __block BOOL validTrace = YES; + [self.stages enumerateObjectsUsingBlock:^(FIRTrace *stage, NSUInteger idx, BOOL *stop) { + validTrace = [stage isCompleteAndValid]; + if (!validTrace) { + *stop = YES; + } + }]; + + return validTrace; +} + +- (FPRTraceState)backgroundTraceState { + FPRTraceBackgroundActivityTracker *backgroundActivityTracker = self.backgroundActivityTracker; + if (backgroundActivityTracker) { + return backgroundActivityTracker.traceBackgroundState; + } + + return FPRTraceStateUnknown; +} + +- (NSArray *)sessions { + __block NSArray *sessionInfos = nil; + dispatch_sync(self.sessionIdSerialQueue, ^{ + sessionInfos = [self.activeSessions copy]; + }); + return sessionInfos; +} + +#pragma mark - Stage related methods + +- (void)startStageNamed:(NSString *)stageName startTime:(NSDate *)startTime { + if ([self isTraceActive]) { + [self stopActiveStage]; + + if (self.isInternal) { + self.activeStage = [[FIRTrace alloc] initInternalTraceWithName:stageName]; + [self.activeStage startWithStartTime:startTime]; + } else { + NSString *validatedStageName = FPRReservableName(stageName); + if (validatedStageName.length > 0) { + self.activeStage = [[FIRTrace alloc] initWithName:validatedStageName]; + [self.activeStage startWithStartTime:startTime]; + } else { + FPRLogError(kFPRTraceEmptyName, @"The stage name cannot be empty."); + } + } + + self.activeStage.isStage = YES; + // Do not track background activity tracker for stages. + self.activeStage.backgroundActivityTracker = nil; + } else { + FPRLogError(kFPRTraceNotStarted, + @"Failed to create stage %@ because the trace has not been started.", stageName); + } +} + +- (void)startStageNamed:(NSString *)stageName { + [self startStageNamed:stageName startTime:nil]; +} + +- (void)stopActiveStage { + if (self.activeStage) { + [self.activeStage cancel]; + [self.stages addObject:self.activeStage]; + self.activeStage = nil; + } +} + +#pragma mark - Counter related methods + +- (NSDictionary *)counters { + return [self.counterList counters]; +} + +- (NSUInteger)numberOfCounters { + return [self.counterList numberOfCounters]; +} + +#pragma mark - Metrics related methods + +- (int64_t)valueForIntMetric:(nonnull NSString *)metricName { + return [self.counterList valueForIntMetric:metricName]; +} + +- (void)setIntValue:(int64_t)value forMetric:(nonnull NSString *)metricName { + if ([self isTraceActive]) { + NSString *validatedMetricName = self.isInternal ? metricName : FPRReservableName(metricName); + if (validatedMetricName.length > 0) { + [self.counterList setIntValue:value forMetric:validatedMetricName]; + [self.activeStage setIntValue:value forMetric:validatedMetricName]; + } else { + FPRLogError(kFPRTraceInvalidName, @"The metric name is invalid."); + } + } else { + FPRLogError(kFPRTraceNotStarted, + @"Failed to set value for metric %@ because trace %@ has not been started.", + metricName, self.name); + } +} + +- (void)incrementMetric:(nonnull NSString *)metricName byInt:(int64_t)incrementValue { + if ([self isTraceActive]) { + NSString *validatedMetricName = self.isInternal ? metricName : FPRReservableName(metricName); + if (validatedMetricName.length > 0) { + [self.counterList incrementMetric:validatedMetricName byInt:incrementValue]; + [self.activeStage incrementMetric:validatedMetricName byInt:incrementValue]; + FPRLogDebug(kFPRClientMetricLogged, @"Incrementing metric %@ to %lld on trace %@", + validatedMetricName, [self valueForIntMetric:metricName], self.name); + } else { + FPRLogError(kFPRTraceInvalidName, @"The metric name is invalid."); + } + } else { + FPRLogError(kFPRTraceNotStarted, + @"Failed to increment the trace metric %@ because trace %@ has not been started.", + metricName, self.name); + } +} + +- (void)deleteMetric:(nonnull NSString *)metricName { + if ([self isTraceActive]) { + [self.counterList deleteMetric:metricName]; + [self.activeStage deleteMetric:metricName]; + } +} + +#pragma mark - Custom attributes related methods + +- (NSDictionary *)attributes { + return [self.customAttributes copy]; +} + +- (void)setValue:(NSString *)value forAttribute:(nonnull NSString *)attribute { + BOOL canAddAttribute = YES; + if ([self isTraceStopped]) { + FPRLogError(kFPRTraceAlreadyStopped, + @"Failed to set attribute %@ because trace %@ has already stopped.", attribute, + self.name); + canAddAttribute = NO; + } + + NSString *validatedName = FPRReservableAttributeName(attribute); + NSString *validatedValue = FPRValidatedAttributeValue(value); + + if (validatedName == nil) { + FPRLogError(kFPRAttributeNoName, + @"Failed to initialize because of a nil or zero length attribute name."); + canAddAttribute = NO; + } + + if (validatedValue == nil) { + FPRLogError(kFPRAttributeNoValue, + @"Failed to initialize because of a nil or zero length attribute value."); + canAddAttribute = NO; + } + + if (self.customAttributes.allKeys.count >= kFPRMaxTraceCustomAttributesCount) { + FPRLogError(kFPRMaxAttributesReached, + @"Only %d attributes allowed. Already reached maximum attribute count.", + kFPRMaxTraceCustomAttributesCount); + canAddAttribute = NO; + } + + if (canAddAttribute) { + // Ensure concurrency during update of attributes. + dispatch_sync(self.customAttributesSerialQueue, ^{ + self.customAttributes[validatedName] = validatedValue; + }); + } + FPRLogDebug(kFPRClientMetricLogged, @"Setting attribute %@ to %@ on trace %@", validatedName, + validatedValue, self.name); +} + +- (NSString *)valueForAttribute:(NSString *)attribute { + // TODO(b/175053654): Should this be happening on the serial queue for thread safety? + return self.customAttributes[attribute]; +} + +- (void)removeAttribute:(NSString *)attribute { + if ([self isTraceStopped]) { + FPRLogError(kFPRTraceNotStarted, + @"Failed to remove attribute %@ because trace %@ has already stopped.", attribute, + self.name); + return; + } + + [self.customAttributes removeObjectForKey:attribute]; +} + +#pragma mark - Utility methods + +- (void)sessionChanged:(NSNotification *)notification { + if ([self isTraceActive]) { + NSDictionary *userInfo = notification.userInfo; + FPRSessionDetails *sessionDetails = [userInfo valueForKey:kFPRSessionIdNotificationKey]; + if (sessionDetails) { + [self updateTraceWithSessionId:sessionDetails]; + } + } +} + +- (void)updateTraceWithSessionId:(FPRSessionDetails *)sessionDetails { + dispatch_sync(self.sessionIdSerialQueue, ^{ + [self.activeSessions addObject:sessionDetails]; + }); +} + +- (BOOL)isTraceStarted { + return self.startTime != nil; +} + +- (BOOL)isTraceStopped { + return (self.startTime != nil && self.stopTime != nil); +} + +- (BOOL)isTraceActive { + return (self.startTime != nil && self.stopTime == nil); +} + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.h b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.h new file mode 100644 index 0000000..42a29d4 --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.h @@ -0,0 +1,82 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/** + * FPRCounterList contains information about a list of counters. Every item in the list is a + * key value pair, where the key is the reference to the name of a counter and the value is the + * current count for the key. Counter values can be incremented. + */ +@interface FPRCounterList : NSObject + +@property(atomic, nonnull, readonly) NSDictionary *counters; + +/** + * The number of counters. + */ +@property(atomic, readonly) NSUInteger numberOfCounters; + +/** Serial queue to manage incrementing counters. */ +@property(nonatomic, nonnull, readonly) dispatch_queue_t counterSerialQueue; + +/** + * Increments the counter for the provided counter name with the provided value. + * + * @param counterName Name of the counter. + * @param incrementValue Value the counter would be incremented with. + */ +- (void)incrementCounterNamed:(nonnull NSString *)counterName by:(NSInteger)incrementValue; + +/** + * Verifies if the metrics are valid. + * + * @return A boolean stating if the metrics are valid. + */ +- (BOOL)isValid; + +/** + * Increments the metric for the provided metric name with the provided value. + * + * @param metricName Name of the metric. + * @param incrementValue Value the metric would be incremented with. + */ +- (void)incrementMetric:(nonnull NSString *)metricName byInt:(int64_t)incrementValue; + +/** + * Gets the value of the metric for the provided metric name. If the metric doesn't exist, a 0 is + * returned. + * + * @param metricName The name of metric whose value to get. + */ +- (int64_t)valueForIntMetric:(nonnull NSString *)metricName; + +/** + * Sets the value of the metric for the provided metric name to the provided value. If it is a new + * counter name, the counter value will be initialized to the value. Does nothing if the trace has + * not been started or has already been stopped. + * + * @param metricName The name of the metric whose value to set. + * @param value The value to set the metric to. + */ +- (void)setIntValue:(int64_t)value forMetric:(nonnull NSString *)metricName; + +/** + * Deletes the metric with the given name. Does nothing if that metric doesn't exist. + * + * @param metricName The name of the metric to delete. + */ +- (void)deleteMetric:(nonnull NSString *)metricName; + +@end diff --git a/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.m b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.m new file mode 100644 index 0000000..ec618dd --- /dev/null +++ b/Pods/FirebasePerformance/FirebasePerformance/Sources/Timer/FPRCounterList.m @@ -0,0 +1,122 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebasePerformance/Sources/Timer/FPRCounterList.h" + +@interface FPRCounterList () + +@property(nonatomic) NSMutableDictionary *counterDictionary; + +/** Serial queue to manage incrementing counters. */ +@property(nonatomic, readwrite) dispatch_queue_t counterSerialQueue; + +@end + +@implementation FPRCounterList + +- (instancetype)init { + self = [super init]; + if (self) { + _counterDictionary = [[NSMutableDictionary alloc] init]; + _counterSerialQueue = dispatch_queue_create("com.google.perf.counters", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (void)incrementCounterNamed:(NSString *)counterName by:(NSInteger)incrementValue { + dispatch_sync(self.counterSerialQueue, ^{ + if (counterName) { + NSNumber *number = self.counterDictionary[counterName]; + if (number != nil) { + int64_t value = [number longLongValue]; + value += incrementValue; + number = @(value); + } else { + number = @(incrementValue); + } + self.counterDictionary[counterName] = number; + } + }); +} + +- (NSDictionary *)counters { + __block NSDictionary *countersDictionary; + dispatch_sync(self.counterSerialQueue, ^{ + countersDictionary = [self.counterDictionary copy]; + }); + return countersDictionary; +} + +- (NSUInteger)numberOfCounters { + __block NSUInteger numberOfCounters; + dispatch_sync(self.counterSerialQueue, ^{ + numberOfCounters = self.counterDictionary.count; + }); + return numberOfCounters; +} + +#pragma mark - Methods related to metrics + +- (void)incrementMetric:(nonnull NSString *)metricName byInt:(int64_t)incrementValue { + dispatch_async(self.counterSerialQueue, ^{ + if (metricName) { + NSNumber *number = self.counterDictionary[metricName]; + if (number != nil) { + int64_t value = [number longLongValue]; + value += incrementValue; + number = @(value); + } else { + number = @(incrementValue); + } + self.counterDictionary[metricName] = number; + } + }); +} + +- (int64_t)valueForIntMetric:(nonnull NSString *)metricName { + __block int64_t metricValue = 0; + dispatch_sync(self.counterSerialQueue, ^{ + if (metricName) { + NSNumber *value = self.counterDictionary[metricName]; + if (value != nil) { + metricValue = [value longLongValue]; + } else { + metricValue = 0; + } + } + }); + return metricValue; +} + +- (void)deleteMetric:(nonnull NSString *)metricName { + if (metricName) { + dispatch_sync(self.counterSerialQueue, ^{ + [self.counterDictionary removeObjectForKey:metricName]; + }); + } +} + +- (void)setIntValue:(int64_t)value forMetric:(nonnull NSString *)metricName { + dispatch_async(self.counterSerialQueue, ^{ + NSNumber *newValue = @(value); + self.counterDictionary[metricName] = newValue; + }); +} + +- (BOOL)isValid { + // TODO(b/175054970): Rename this class to metrics list and see if this method makes sense. + return YES; +} + +@end diff --git a/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h new file mode 100644 index 0000000..4420dcb --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h @@ -0,0 +1,87 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "RCNConfigSettings.h" // This import is needed to expose settings for the Swift API tests. + +@class FIROptions; +@class RCNConfigContent; +@class RCNConfigDBManager; +@class RCNConfigFetch; +@class RCNConfigRealtime; +@protocol FIRAnalyticsInterop; +@protocol FIRRolloutsStateSubscriber; + +NS_ASSUME_NONNULL_BEGIN + +@class RCNConfigSettings; + +@interface FIRRemoteConfigUpdate () + +/// Designated initializer. +- (instancetype)initWithUpdatedKeys:(NSSet *)updatedKeys; +@end + +@interface FIRRemoteConfig () { + NSString *_FIRNamespace; +} + +/// Internal settings +@property(nonatomic, readonly, strong) RCNConfigSettings *settings; + +/// Config settings are custom settings. +@property(nonatomic, readwrite, strong, nonnull) RCNConfigFetch *configFetch; + +@property(nonatomic, readwrite, strong, nonnull) RCNConfigRealtime *configRealtime; + +/// Returns the FIRRemoteConfig instance for your namespace and for the default Firebase App. +/// This singleton object contains the complete set of Remote Config parameter values available to +/// the app, including the Active Config and Default Config.. This object also caches values fetched +/// from the Remote Config Server until they are copied to the Active Config by calling +/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase +/// namespace service, you should use this class method to create a shared instance of the +/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config +/// Server and the Firebase service. This API is used internally by 2P teams. ++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace + NS_SWIFT_NAME(remoteConfig(FIRNamespace:)); + +/// Returns the FIRRemoteConfig instance for your namespace and for the default 3P developer's app. +/// This singleton object contains the complete set of Remote Config parameter values available to +/// the app, including the Active Config and Default Config. This object also caches values fetched +/// from the Remote Config Server until they are copied to the Active Config by calling +/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase +/// namespace service, you should use this class method to create a shared instance of the +/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config +/// Server and the Firebase service. ++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace + app:(FIRApp *)app + NS_SWIFT_NAME(remoteConfig(FIRNamespace:app:)); + +/// Initialize a FIRRemoteConfig instance with all the required parameters directly. This exists so +/// tests can create FIRRemoteConfig objects without needing FIRApp. +- (instancetype)initWithAppName:(NSString *)appName + FIROptions:(FIROptions *)options + namespace:(NSString *)FIRNamespace + DBManager:(RCNConfigDBManager *)DBManager + configContent:(RCNConfigContent *)configContent + analytics:(nullable id)analytics; + +/// Register RolloutsStateSubcriber to FIRRemoteConfig instance +- (void)addRemoteConfigInteropSubscriber:(id _Nonnull)subscriber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h new file mode 100644 index 0000000..dbef87d --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +@class FIROptions; +@class RCNConfigContent; +@class RCNConfigSettings; +@class RCNConfigExperiment; +@class RCNConfigDBManager; + +NS_ASSUME_NONNULL_BEGIN + +/// Completion handler invoked by NSSessionFetcher. +typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response, NSError *error); + +/// Completion handler invoked after a fetch that contains the updated keys +typedef void (^RCNConfigFetchCompletion)(FIRRemoteConfigFetchStatus status, + FIRRemoteConfigUpdate *update, + NSError *error); + +@interface RCNConfigFetch : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer +- (instancetype)initWithContent:(RCNConfigContent *)content + DBManager:(RCNConfigDBManager *)DBManager + settings:(RCNConfigSettings *)settings + analytics:(nullable id)analytics + experiment:(nullable RCNConfigExperiment *)experiment + queue:(dispatch_queue_t)queue + namespace:(NSString *)firebaseNamespace + options:(FIROptions *)firebaseOptions NS_DESIGNATED_INITIALIZER; + +/// Fetches config data keyed by namespace. Completion block will be called on the main queue. +/// @param expirationDuration Expiration duration, in seconds. +/// @param completionHandler Callback handler. +- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler; + +/// Fetches config data immediately, keyed by namespace. Completion block will be called on the main +/// queue. +/// @param fetchAttemptNumber The number of the fetch attempt. +/// @param completionHandler Callback handler. +- (void)realtimeFetchConfigWithNoExpirationDuration:(NSInteger)fetchAttemptNumber + completionHandler:(RCNConfigFetchCompletion)completionHandler; + +/// Add the ability to update NSURLSession's timeout after a session has already been created. +- (void)recreateNetworkSession; + +/// Provide fetchSession for tests to override. +@property(nonatomic, readwrite, strong, nonnull) NSURLSession *fetchSession; + +/// Provide config template version number for Realtime config client. +@property(nonatomic, copy, nonnull) NSString *templateVersionNumber; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h new file mode 100644 index 0000000..034c50c --- /dev/null +++ b/Pods/FirebasePerformance/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h @@ -0,0 +1,152 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +@class RCNConfigDBManager; + +/// This internal class contains a set of variables that are unique among all the config instances. +/// It also handles all metadata and internal metadata. This class is not thread safe and does not +/// inherently allow for synchronized access. Callers are responsible for synchronization +/// (currently using serial dispatch queues). +@interface RCNConfigSettings : NSObject + +/// The time interval that config data stays fresh. +@property(nonatomic, readwrite, assign) NSTimeInterval minimumFetchInterval; + +/// The timeout to set for outgoing fetch requests. +@property(nonatomic, readwrite, assign) NSTimeInterval fetchTimeout; +// The Google App ID of the configured FIRApp. +@property(nonatomic, readwrite, copy) NSString *googleAppID; +#pragma mark - Data required by config request. +/// Device authentication ID required by config request. +@property(nonatomic, copy) NSString *deviceAuthID; +/// Secret Token required by config request. +@property(nonatomic, copy) NSString *secretToken; +/// Device data version of checkin information. +@property(nonatomic, copy) NSString *deviceDataVersion; +/// InstallationsID. +@property(nonatomic, copy) NSString *configInstallationsIdentifier; +/// Installations token. +@property(nonatomic, copy) NSString *configInstallationsToken; + +/// A list of successful fetch timestamps in milliseconds. +/// TODO Not used anymore. Safe to remove. +@property(nonatomic, readonly, copy) NSArray *successFetchTimes; +/// A list of failed fetch timestamps in milliseconds. +@property(nonatomic, readonly, copy) NSArray *failureFetchTimes; +/// Custom variable (aka App context digest). This is the pending custom variables request before +/// fetching. +@property(nonatomic, copy) NSDictionary *customVariables; +/// Cached internal metadata from internal metadata table. It contains customized information such +/// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time +/// interval. Client has the default value of each parameters, they are only saved in +/// internalMetadata if they have been customize by developers. +@property(nonatomic, readonly, copy) NSDictionary *internalMetadata; +/// Device conditions since last successful fetch from the backend. Device conditions including +/// app +/// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for +/// determing whether to throttle. +@property(nonatomic, readonly, copy) NSDictionary *deviceContext; +/// Bundle Identifier +@property(nonatomic, readonly, copy) NSString *bundleIdentifier; +/// The time of last successful config fetch. +@property(nonatomic, readonly, assign) NSTimeInterval lastFetchTimeInterval; +/// Last fetch status. +@property(nonatomic, readwrite, assign) FIRRemoteConfigFetchStatus lastFetchStatus; +/// The reason that last fetch failed. +@property(nonatomic, readwrite, assign) FIRRemoteConfigError lastFetchError; +/// The time of last apply timestamp. +@property(nonatomic, readwrite, assign) NSTimeInterval lastApplyTimeInterval; +/// The time of last setDefaults timestamp. +@property(nonatomic, readwrite, assign) NSTimeInterval lastSetDefaultsTimeInterval; +/// The latest eTag value stored from the last successful response. +@property(nonatomic, readwrite, assign) NSString *lastETag; +/// The timestamp of the last eTag update. +@property(nonatomic, readwrite, assign) NSTimeInterval lastETagUpdateTime; +/// Last fetched template version. +@property(nonatomic, readwrite, assign) NSString *lastFetchedTemplateVersion; +/// Last active template version. +@property(nonatomic, readwrite, assign) NSString *lastActiveTemplateVersion; + +#pragma mark Throttling properties + +/// Throttling intervals are based on https://cloud.google.com/storage/docs/exponential-backoff +/// Returns true if client has fetched config and has not got back from server. This is used to +/// determine whether there is another config task infight when fetching. +@property(atomic, readwrite, assign) BOOL isFetchInProgress; +/// Returns the current retry interval in seconds set for exponential backoff. +@property(nonatomic, readwrite, assign) double exponentialBackoffRetryInterval; +/// Returns the time in seconds until the next request is allowed while in exponential backoff mode. +@property(nonatomic, readonly, assign) NSTimeInterval exponentialBackoffThrottleEndTime; +/// Returns the current retry interval in seconds set for exponential backoff for the Realtime +/// service. +@property(nonatomic, readwrite, assign) double realtimeExponentialBackoffRetryInterval; +/// Returns the time in seconds until the next request is allowed while in exponential backoff mode +/// for the Realtime service. +@property(nonatomic, readonly, assign) NSTimeInterval realtimeExponentialBackoffThrottleEndTime; +/// Realtime connection attempts. +@property(nonatomic, readwrite, assign) int realtimeRetryCount; + +#pragma mark Throttling Methods + +/// Designated initializer. +- (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager + namespace:(NSString *)FIRNamespace + firebaseAppName:(NSString *)appName + googleAppID:(NSString *)googleAppID; + +/// Returns a fetch request with the latest device and config change. +/// Whenever user issues a fetch api call, collect the latest request. +/// @param userProperties User properties to set to config request. +/// @return Config fetch request string +- (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties; + +/// Returns metadata from metadata table. +- (NSDictionary *)loadConfigFromMetadataTable; + +/// Updates internal content with the latest successful config response. +- (void)updateInternalContentWithResponse:(NSDictionary *)response; + +/// Updates the metadata table with the current fetch status. +/// @param fetchSuccess True if fetch was successful. +- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess + templateVersion:(NSString *)templateVersion; + +/// Increases the throttling time. Should only be called if the fetch error indicates a server +/// issue. +- (void)updateExponentialBackoffTime; + +/// Increases the throttling time for Realtime. Should only be called if the Realtime error +/// indicates a server issue. +- (void)updateRealtimeExponentialBackoffTime; + +/// Update last active template version from last fetched template version. +- (void)updateLastActiveTemplateVersion; + +/// Returns the difference between the Realtime backoff end time and the current time in a +/// NSTimeInterval format. +- (NSTimeInterval)getRealtimeBackoffInterval; + +/// Returns true if we are in exponential backoff mode and it is not yet the next request time. +- (BOOL)shouldThrottle; + +/// Returns true if the last fetch is outside the minimum fetch interval supplied. +- (BOOL)hasMinimumFetchIntervalElapsed:(NSTimeInterval)minimumFetchInterval; + +@end diff --git a/Pods/FirebasePerformance/LICENSE b/Pods/FirebasePerformance/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebasePerformance/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebasePerformance/README.md b/Pods/FirebasePerformance/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebasePerformance/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h b/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h new file mode 100644 index 0000000..b2f2da0 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/ABTExperimentPayload.h @@ -0,0 +1,96 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Policy for handling the case where there's an overflow of experiments for an installation +/// instance. +typedef NS_ENUM(int32_t, ABTExperimentPayloadExperimentOverflowPolicy) { + ABTExperimentPayloadExperimentOverflowPolicyUnrecognizedValue = 999, + ABTExperimentPayloadExperimentOverflowPolicyUnspecified = 0, + ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest = 1, + ABTExperimentPayloadExperimentOverflowPolicyIgnoreNewest = 2, +}; + +@interface ABTExperimentLite : NSObject +@property(nonatomic, readonly, copy) NSString *experimentId; + +- (instancetype)initWithExperimentId:(NSString *)experimentId NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +@end + +@interface ABTExperimentPayload : NSObject + +/// Unique identifier for this experiment. +@property(nonatomic, readonly, copy) NSString *experimentId; + +/// Unique identifier for the variant to which an installation instance has been assigned. +@property(nonatomic, readonly, copy) NSString *variantId; + +/// Epoch time that represents when the experiment was started. +@property(nonatomic, readonly) int64_t experimentStartTimeMillis; + +/// The event that triggers this experiment into ON state. +@property(nonatomic, nullable, readonly, copy) NSString *triggerEvent; + +/// Duration in milliseconds for which the experiment can stay in STANDBY state (un-triggered). +@property(nonatomic, readonly) int64_t triggerTimeoutMillis; + +/// Duration in milliseconds for which the experiment can stay in ON state (triggered). +@property(nonatomic, readonly) int64_t timeToLiveMillis; + +/// The event logged when impact service sets the experiment. +@property(nonatomic, readonly, copy) NSString *setEventToLog; + +/// The event logged when an experiment goes to the ON state. +@property(nonatomic, readonly, copy) NSString *activateEventToLog; + +/// The event logged when an experiment is cleared. +@property(nonatomic, readonly, copy) NSString *clearEventToLog; + +/// The event logged when an experiment times out after `triggerTimeoutMillis` milliseconds. +@property(nonatomic, readonly, copy) NSString *timeoutEventToLog; + +/// The event logged when an experiment times out after `timeToLiveMillis` milliseconds. +@property(nonatomic, readonly, copy) NSString *ttlExpiryEventToLog; + +@property(nonatomic, readonly) ABTExperimentPayloadExperimentOverflowPolicy overflowPolicy; + +/// A list of all other ongoing (started, and not yet stopped) experiments at the time this +/// experiment was started. Does not include this experiment; only the others. +@property(nonatomic, readonly) NSArray *ongoingExperiments; + +/// Parses an ABTExperimentPayload directly from JSON data. +/// @param data JSON object as NSData. Must be reconstructible as an NSDictionary. ++ (nullable instancetype)parseFromData:(NSData *)data; + +/// Initializes an ABTExperimentPayload from a dictionary with experiment metadata. +- (instancetype)initWithDictionary:(NSDictionary *)dictionary + NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Clears the trigger event associated with this payload. +- (void)clearTriggerEvent; + +/// Checks if the overflow policy is a valid enum object. +- (BOOL)overflowPolicyIsValid; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h b/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h new file mode 100644 index 0000000..7259e08 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h @@ -0,0 +1,20 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase Public and Private +// headers. Any package manager complexity should be handled here. + +#import + +#import "FirebaseABTesting/Sources/Private/ABTExperimentPayload.h" diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRAppInternal.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRAppInternal.h new file mode 100644 index 0000000..b0b1511 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRAppInternal.h @@ -0,0 +1,156 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; +@class FIRHeartbeatLogger; +@protocol FIRLibrary; + +/** + * The internal interface to `FirebaseApp`. This is meant for first-party integrators, who need to + * receive `FirebaseApp` notifications, log info about the success or failure of their + * configuration, and access other internal functionality of `FirebaseApp`. + */ +NS_ASSUME_NONNULL_BEGIN + +typedef NS_ENUM(NSInteger, FIRConfigType) { + FIRConfigTypeCore = 1, + FIRConfigTypeSDK = 2, +}; + +extern NSString *const kFIRDefaultAppName; +extern NSString *const kFIRAppReadyToConfigureSDKNotification; +extern NSString *const kFIRAppDeleteNotification; +extern NSString *const kFIRAppIsDefaultAppKey; +extern NSString *const kFIRAppNameKey; +extern NSString *const kFIRGoogleAppIDKey; +extern NSString *const kFirebaseCoreErrorDomain; + +/** + * The format string for the `UserDefaults` key used for storing the data collection enabled flag. + * This includes formatting to append the `FirebaseApp`'s name. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledDefaultsKeyFormat; + +/** + * The plist key used for storing the data collection enabled flag. + */ +extern NSString *const kFIRGlobalAppDataCollectionEnabledPlistKey; + +/** @var FirebaseAuthStateDidChangeInternalNotification + @brief The name of the @c NotificationCenter notification which is posted when the auth state + changes (e.g. a new token has been produced, a user logs in or out). The object parameter of + the notification is a dictionary possibly containing the key: + @c FirebaseAuthStateDidChangeInternalNotificationTokenKey (the new access token.) If it does not + contain this key it indicates a sign-out event took place. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotification; + +/** @var FirebaseAuthStateDidChangeInternalNotificationTokenKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new access token. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationTokenKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationAppKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the FirebaseApp associated with the auth instance. + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationAppKey; + +/** @var FirebaseAuthStateDidChangeInternalNotificationUIDKey + @brief A key present in the dictionary object parameter of the + @c FirebaseAuthStateDidChangeInternalNotification notification. The value associated with this + key will contain the new user's UID (or nil if there is no longer a user signed in). + */ +extern NSString *const FIRAuthStateDidChangeInternalNotificationUIDKey; + +@interface FIRApp () + +/** + * A flag indicating if this is the default app (has the default app name). + */ +@property(nonatomic, readonly) BOOL isDefaultApp; + +/** + * The container of interop SDKs for this app. + */ +@property(nonatomic) FIRComponentContainer *container; + +/** + * The heartbeat logger associated with this app. + * + * Firebase apps have a 1:1 relationship with heartbeat loggers. + */ +@property(readonly) FIRHeartbeatLogger *heartbeatLogger; + +/** + * Checks if the default app is configured without trying to configure it. + */ ++ (BOOL)isDefaultAppConfigured; + +/** + * Registers a given third-party library with the given version number to be reported for + * analytics. + * + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerLibrary:(nonnull NSString *)name withVersion:(nonnull NSString *)version; + +/** + * Registers a given internal library to be reported for analytics. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name; + +/** + * Registers a given internal library with the given version number to be reported for + * analytics. This should only be used for non-Firebase libraries that have their own versioning + * scheme. + * + * @param library Optional parameter for component registration. + * @param name Name of the library. + * @param version Version of the library. + */ ++ (void)registerInternalLibrary:(nonnull Class)library + withName:(nonnull NSString *)name + withVersion:(nonnull NSString *)version; + +/** + * A concatenated string representing all the third-party libraries and version numbers. + */ ++ (NSString *)firebaseUserAgent; + +/** + * Can be used by the unit tests in each SDK to reset `FirebaseApp`. This method is thread unsafe. + */ ++ (void)resetApps; + +/** + * Can be used by the unit tests in each SDK to set customized options. + */ +- (instancetype)initInstanceWithName:(NSString *)name options:(FIROptions *)options; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponent.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponent.h new file mode 100644 index 0000000..c58a851 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponent.h @@ -0,0 +1,84 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides a system to clean up cached instances returned from the component system. +NS_SWIFT_NAME(ComponentLifecycleMaintainer) +@protocol FIRComponentLifecycleMaintainer +/// The associated app will be deleted, clean up any resources as they are about to be deallocated. +- (void)appWillBeDeleted:(FIRApp *)app; +@end + +typedef _Nullable id (^FIRComponentCreationBlock)(FIRComponentContainer *container, + BOOL *isCacheable) + NS_SWIFT_NAME(ComponentCreationBlock); + +/// Describes the timing of instantiation. Note: new components should default to lazy unless there +/// is a strong reason to be eager. +typedef NS_ENUM(NSInteger, FIRInstantiationTiming) { + FIRInstantiationTimingLazy, + FIRInstantiationTimingAlwaysEager, + FIRInstantiationTimingEagerInDefaultApp +} NS_SWIFT_NAME(InstantiationTiming); + +/// A component that can be used from other Firebase SDKs. +NS_SWIFT_NAME(Component) +@interface FIRComponent : NSObject + +/// The protocol describing functionality provided from the `Component`. +@property(nonatomic, strong, readonly) Protocol *protocol; + +/// The timing of instantiation. +@property(nonatomic, readonly) FIRInstantiationTiming instantiationTiming; + +/// A block to instantiate an instance of the component with the appropriate dependencies. +@property(nonatomic, copy, readonly) FIRComponentCreationBlock creationBlock; + +// There's an issue with long NS_SWIFT_NAMES that causes compilation to fail, disable clang-format +// for the next two methods. +// clang-format off + +/// Creates a component with no dependencies that will be lazily initialized. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:creationBlock:)); + +/// Creates a component to be registered with the component container. +/// +/// @param protocol - The protocol describing functionality provided by the component. +/// @param instantiationTiming - When the component should be initialized. Use .lazy unless there's +/// a good reason to be instantiated earlier. +/// @param creationBlock - A block to instantiate the component with a container, and if +/// @return A component that can be registered with the component container. ++ (instancetype)componentWithProtocol:(Protocol *)protocol + instantiationTiming:(FIRInstantiationTiming)instantiationTiming + creationBlock:(FIRComponentCreationBlock)creationBlock +NS_SWIFT_NAME(init(_:instantiationTiming:creationBlock:)); + +// clang-format on + +/// Unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentContainer.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentContainer.h new file mode 100644 index 0000000..6ec6147 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentContainer.h @@ -0,0 +1,45 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A type-safe macro to retrieve a component from a container. This should be used to retrieve +/// components instead of using the container directly. +#define FIR_COMPONENT(type, container) \ + [FIRComponentType> instanceForProtocol:@protocol(type) inContainer:container] + +@class FIRApp; + +/// A container that holds different components that are registered via the +/// `registerAsComponentRegistrant` call. These classes should conform to `ComponentRegistrant` +/// in order to properly register components for Core. +NS_SWIFT_NAME(FirebaseComponentContainer) +@interface FIRComponentContainer : NSObject + +/// A weak reference to the app that an instance of the container belongs to. +@property(nonatomic, weak, readonly) FIRApp *app; + +// TODO: See if we can get improved type safety here. +/// A Swift only API for fetching an instance since the top macro isn't available. +- (nullable id)__instanceForProtocol:(Protocol *)protocol NS_SWIFT_NAME(instance(for:)); + +/// Unavailable. Use the `container` property on `FirebaseApp`. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentType.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentType.h new file mode 100644 index 0000000..c69085d --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRComponentType.h @@ -0,0 +1,35 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRComponentContainer; + +NS_ASSUME_NONNULL_BEGIN + +/// Do not use directly. A placeholder type in order to provide a macro that will warn users of +/// mis-matched protocols. +NS_SWIFT_NAME(ComponentType) +@interface FIRComponentType<__covariant T> : NSObject + +/// Do not use directly. A factory method to retrieve an instance that provides a specific +/// functionality. ++ (nullable T)instanceForProtocol:(Protocol *)protocol + inContainer:(FIRComponentContainer *)container; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRHeartbeatLogger.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRHeartbeatLogger.h new file mode 100644 index 0000000..6314f50 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRHeartbeatLogger.h @@ -0,0 +1,90 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +#ifndef FIREBASE_BUILD_CMAKE +@class FIRHeartbeatsPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Enum representing different daily heartbeat codes. +/// This enum is only used by clients using platform logging V1. This is because +/// the V1 payload only supports a single daily heartbeat. +typedef NS_ENUM(NSInteger, FIRDailyHeartbeatCode) { + /// Represents the absence of a daily heartbeat. + FIRDailyHeartbeatCodeNone = 0, + /// Represents the presence of a daily heartbeat. + FIRDailyHeartbeatCodeSome = 2, +}; + +@protocol FIRHeartbeatLoggerProtocol + +/// Asynchronously logs a heartbeat. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Return the headerValue for the HeartbeatLogger. +- (NSString *_Nullable)headerValue; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets the heartbeat code for today. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +#ifndef FIREBASE_BUILD_CMAKE +/// Returns a nullable string header value from a given heartbeats payload. +/// +/// This API returns `nil` when the given heartbeats payload is considered empty. +/// +/// @param heartbeatsPayload The heartbeats payload. +NSString *_Nullable FIRHeaderValueFromHeartbeatsPayload(FIRHeartbeatsPayload *heartbeatsPayload); +#endif // FIREBASE_BUILD_CMAKE + +/// A thread safe, synchronized object that logs and flushes platform logging info. +@interface FIRHeartbeatLogger : NSObject + +/// Designated initializer. +/// +/// @param appID The app ID that this heartbeat logger corresponds to. +- (instancetype)initWithAppID:(NSString *)appID; + +/// Asynchronously logs a new heartbeat corresponding to the Firebase User Agent, if needed. +/// +/// @note This API is thread-safe. +- (void)log; + +#ifndef FIREBASE_BUILD_CMAKE +/// Flushes heartbeats from storage into a structured payload of heartbeats. +/// +/// This API is for clients using platform logging V2. +/// +/// @note This API is thread-safe. +/// @return A payload of heartbeats. +- (FIRHeartbeatsPayload *)flushHeartbeatsIntoPayload; +#endif // FIREBASE_BUILD_CMAKE + +/// Gets today's corresponding heartbeat code. +/// +/// This API is for clients using platform logging V1. +/// +/// @note This API is thread-safe. +/// @return Heartbeat code indicating whether or not there is an unsent global heartbeat. +- (FIRDailyHeartbeatCode)heartbeatCodeForToday; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLibrary.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLibrary.h new file mode 100644 index 0000000..17664ac --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLibrary.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FIRLibrary_h +#define FIRLibrary_h + +#import + +@class FIRApp; +@class FIRComponent; + +NS_ASSUME_NONNULL_BEGIN + +/// Provide an interface to register a library for userAgent logging and availability to others. +NS_SWIFT_NAME(Library) +@protocol FIRLibrary + +/// Returns one or more Components that will be registered in +/// FirebaseApp and participate in dependency resolution and injection. ++ (NSArray *)componentsToRegister; + +@end + +NS_ASSUME_NONNULL_END + +#endif /* FIRLibrary_h */ diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLogger.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLogger.h new file mode 100644 index 0000000..52ed75d --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIRLogger.h @@ -0,0 +1,148 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * The Firebase services used in Firebase logger. + */ +typedef NSString *const FIRLoggerService; + +extern NSString *const kFIRLoggerAnalytics; +extern NSString *const kFIRLoggerCrash; +extern NSString *const kFIRLoggerCore; +extern NSString *const kFIRLoggerRemoteConfig; + +/** + * The key used to store the logger's error count. + */ +extern NSString *const kFIRLoggerErrorCountKey; + +/** + * The key used to store the logger's warning count. + */ +extern NSString *const kFIRLoggerWarningCountKey; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/** + * Enables or disables Analytics debug mode. + * If set to true, the logging level for Analytics will be set to FirebaseLoggerLevelDebug. + * Enabling the debug mode has no effect if the app is running from App Store. + * (required) analytics debug mode flag. + */ +void FIRSetAnalyticsDebugMode(BOOL analyticsDebugMode); + +/** + * Gets the current FIRLoggerLevel. + */ +FIRLoggerLevel FIRGetLoggerLevel(void); + +/** + * Changes the default logging level of FirebaseLoggerLevelNotice to a user-specified level. + * The default level cannot be set above FirebaseLoggerLevelNotice if the app is running from App + * Store. (required) log level (one of the FirebaseLoggerLevel enum values). + */ +void FIRSetLoggerLevel(FIRLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) whether or not this function is called from the Analytics component. + */ +BOOL FIRIsLoggableLevel(FIRLoggerLevel loggerLevel, BOOL analyticsComponent); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than FirebaseLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the FirebaseLoggerLevel enum values). + * (required) service name of type FirebaseLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void FIRLogBasic(FIRLoggerLevel level, + NSString *category, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type FirebaseLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * FirebaseLogError(kFirebaseLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void FIRLogError(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogWarning(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogNotice(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogInfo(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); +extern void FIRLogDebug(NSString *category, NSString *messageCode, NSString *message, ...) + NS_FORMAT_FUNCTION(3, 4); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +NS_SWIFT_NAME(FirebaseLogger) +@interface FIRLoggerWrapper : NSObject + +/// Logs a given message at a given log level. +/// +/// - Parameters: +/// - level: The log level to use (defined by `FirebaseLoggerLevel` enum values). +/// - service: The service name of type `FirebaseLoggerService`. +/// - code: The message code. Starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: Formatted string to be used as the log's message. ++ (void)logWithLevel:(FIRLoggerLevel)level + service:(NSString *)category + code:(NSString *)code + message:(NSString *)message + __attribute__((__swift_name__("log(level:service:code:message:)"))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIROptionsInternal.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIROptionsInternal.h new file mode 100644 index 0000000..93a03d6 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FIROptionsInternal.h @@ -0,0 +1,106 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** + * Keys for the strings in the plist file. + */ +extern NSString *const kFIRAPIKey; +extern NSString *const kFIRTrackingID; +extern NSString *const kFIRGoogleAppID; +extern NSString *const kFIRClientID; +extern NSString *const kFIRGCMSenderID; +extern NSString *const kFIRAndroidClientID; +extern NSString *const kFIRDatabaseURL; +extern NSString *const kFIRStorageBucket; +extern NSString *const kFIRBundleID; +extern NSString *const kFIRProjectID; + +/** + * Keys for the plist file name + */ +extern NSString *const kServiceInfoFileName; + +extern NSString *const kServiceInfoFileType; + +/** + * This header file exposes the initialization of FirebaseOptions to internal use. + */ +@interface FIROptions () + +/** + * `resetDefaultOptions` and `initInternalWithOptionsDictionary` are exposed only for unit tests. + */ ++ (void)resetDefaultOptions; + +/** + * Initializes the options with dictionary. The above strings are the keys of the dictionary. + * This is the designated initializer. + */ +- (instancetype)initInternalWithOptionsDictionary:(NSDictionary *)serviceInfoDictionary + NS_DESIGNATED_INITIALIZER; + +/** + * `defaultOptions` and `defaultOptionsDictionary` are exposed in order to be used in FirebaseApp + * and other first party services. + */ ++ (FIROptions *)defaultOptions; + ++ (NSDictionary *)defaultOptionsDictionary; + +/** + * Indicates whether or not Analytics collection was explicitly enabled via a plist flag or at + * runtime. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionExplicitlySet; + +/** + * Whether or not Analytics Collection was enabled. Analytics Collection is enabled unless + * explicitly disabled in GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionEnabled; + +/** + * Whether or not Analytics Collection was completely disabled. If true, then + * isAnalyticsCollectionEnabled will be false. + */ +@property(nonatomic, readonly) BOOL isAnalyticsCollectionDeactivated; + +/** + * The version ID of the client library, e.g. @"1100000". + */ +@property(nonatomic, readonly, copy) NSString *libraryVersionID; + +/** + * The flag indicating whether this object was constructed with the values in the default plist + * file. + */ +@property(nonatomic) BOOL usingOptionsFromDefaultPlist; + +/** + * Whether or not Measurement was enabled. Measurement is enabled unless explicitly disabled in + * GoogleService-Info.plist. + */ +@property(nonatomic, readonly) BOOL isMeasurementEnabled; + +/** + * Whether or not editing is locked. This should occur after `FirebaseOptions` has been set on a + * `FirebaseApp`. + */ +@property(nonatomic, getter=isEditingLocked) BOOL editingLocked; + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FirebaseCoreInternal.h b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FirebaseCoreInternal.h new file mode 100644 index 0000000..0cb388b --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseCore/Extension/FirebaseCoreInternal.h @@ -0,0 +1,24 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import FirebaseCore; + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" diff --git a/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h b/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h new file mode 100644 index 0000000..0c850e9 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h @@ -0,0 +1,19 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// An umbrella header, for any other libraries in this repo to access Firebase +// Installations Public headers. Any package manager complexity should be +// handled here. + +#import diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m new file mode 100644 index 0000000..e68d9c1 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRConfigValue.m @@ -0,0 +1,91 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" + +@implementation FIRRemoteConfigValue { + /// Data backing the config value. + NSData *_data; + FIRRemoteConfigSource _source; +} + +/// Designated initializer +- (instancetype)initWithData:(NSData *)data source:(FIRRemoteConfigSource)source { + self = [super init]; + if (self) { + _data = [data copy]; + _source = source; + } + return self; +} + +/// Superclass's designated initializer +- (instancetype)init { + return [self initWithData:nil source:FIRRemoteConfigSourceStatic]; +} + +/// The string is a UTF-8 representation of NSData. +- (nonnull NSString *)stringValue { + return [[NSString alloc] initWithData:_data encoding:NSUTF8StringEncoding] ?: @""; +} + +/// Number representation of a UTF-8 string. +- (NSNumber *)numberValue { + return [NSNumber numberWithDouble:self.stringValue.doubleValue]; +} + +/// Internal representation of the FIRRemoteConfigValue as a NSData object. +- (NSData *)dataValue { + return _data; +} + +/// Boolean representation of a UTF-8 string. +- (BOOL)boolValue { + return self.stringValue.boolValue; +} + +/// Returns a foundation object (NSDictionary / NSArray) representation for JSON data. +- (id)JSONValue { + NSError *error; + if (!_data) { + return nil; + } + id JSONObject = [NSJSONSerialization JSONObjectWithData:_data options:kNilOptions error:&error]; + if (error) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000065", @"Error parsing data as JSON."); + return nil; + } + return JSONObject; +} + +/// Debug description showing the representations of all types. +- (NSString *)debugDescription { + NSString *content = [NSString + stringWithFormat:@"Boolean: %d, String: %@, Number: %@, JSON:%@, Data: %@, Source: %zd", + self.boolValue, self.stringValue, self.numberValue, self.JSONValue, _data, + (long)self.source]; + return [NSString stringWithFormat:@"<%@: %p, %@>", [self class], self, content]; +} + +/// Copy method. +- (id)copyWithZone:(NSZone *)zone { + FIRRemoteConfigValue *value = [[[self class] allocWithZone:zone] initWithData:_data]; + return value; +} +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m new file mode 100644 index 0000000..561ada5 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfig.m @@ -0,0 +1,698 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +#import "FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h" +#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigRealtime.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" +#import "FirebaseRemoteConfig/Sources/RCNDevice.h" +#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h" + +/// Remote Config Error Domain. +/// TODO: Rename according to obj-c style for constants. +NSString *const FIRRemoteConfigErrorDomain = @"com.google.remoteconfig.ErrorDomain"; +// Remote Config Realtime Error Domain +NSString *const FIRRemoteConfigUpdateErrorDomain = @"com.google.remoteconfig.update.ErrorDomain"; +/// Remote Config Error Info End Time Seconds; +NSString *const FIRRemoteConfigThrottledEndTimeInSecondsKey = @"error_throttled_end_time_seconds"; +/// Minimum required time interval between fetch requests made to the backend. +static NSString *const kRemoteConfigMinimumFetchIntervalKey = @"_rcn_minimum_fetch_interval"; +/// Timeout value for waiting on a fetch response. +static NSString *const kRemoteConfigFetchTimeoutKey = @"_rcn_fetch_timeout"; +/// Notification when config is successfully activated +const NSNotificationName FIRRemoteConfigActivateNotification = + @"FIRRemoteConfigActivateNotification"; +static NSNotificationName FIRRolloutsStateDidChangeNotificationName = + @"FIRRolloutsStateDidChangeNotification"; + +/// Listener for the get methods. +typedef void (^FIRRemoteConfigListener)(NSString *_Nonnull, NSDictionary *_Nonnull); + +@implementation FIRRemoteConfigSettings + +- (instancetype)init { + self = [super init]; + if (self) { + _minimumFetchInterval = RCNDefaultMinimumFetchInterval; + _fetchTimeout = RCNHTTPDefaultConnectionTimeout; + } + return self; +} + +@end + +@implementation FIRRemoteConfig { + /// All the config content. + RCNConfigContent *_configContent; + RCNConfigDBManager *_DBManager; + RCNConfigSettings *_settings; + RCNConfigFetch *_configFetch; + RCNConfigExperiment *_configExperiment; + RCNConfigRealtime *_configRealtime; + dispatch_queue_t _queue; + NSString *_appName; + NSMutableArray *_listeners; +} + +static NSMutableDictionary *> + *RCInstances; + ++ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(FIRApp *_Nonnull)firebaseApp { + return [FIRRemoteConfig + remoteConfigWithFIRNamespace:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform + app:firebaseApp]; +} + ++ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace { + if (![FIRApp isDefaultAppConfigured]) { + [NSException raise:@"FIRAppNotConfigured" + format:@"The default `FirebaseApp` instance must be configured before the " + @"default Remote Config instance can be initialized. One way to ensure this " + @"is to call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` or the `@main` struct's " + @"initializer in SwiftUI."]; + } + + return [FIRRemoteConfig remoteConfigWithFIRNamespace:firebaseNamespace app:[FIRApp defaultApp]]; +} + ++ (nonnull FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *_Nonnull)firebaseNamespace + app:(FIRApp *_Nonnull)firebaseApp { + // Use the provider to generate and return instances of FIRRemoteConfig for this specific app and + // namespace. This will ensure the app is configured before Remote Config can return an instance. + id provider = + FIR_COMPONENT(FIRRemoteConfigProvider, firebaseApp.container); + return [provider remoteConfigForNamespace:firebaseNamespace]; +} + ++ (FIRRemoteConfig *)remoteConfig { + // If the default app is not configured at this point, warn the developer. + if (![FIRApp isDefaultAppConfigured]) { + [NSException raise:@"FIRAppNotConfigured" + format:@"The default `FirebaseApp` instance must be configured before the " + @"default Remote Config instance can be initialized. One way to ensure this " + @"is to call `FirebaseApp.configure()` in the App Delegate's " + @"`application(_:didFinishLaunchingWithOptions:)` or the `@main` struct's " + @"initializer in SwiftUI."]; + } + + return [FIRRemoteConfig + remoteConfigWithFIRNamespace:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform + app:[FIRApp defaultApp]]; +} + +/// Singleton instance of serial queue for queuing all incoming RC calls. ++ (dispatch_queue_t)sharedRemoteConfigSerialQueue { + static dispatch_once_t onceToken; + static dispatch_queue_t sharedRemoteConfigQueue; + dispatch_once(&onceToken, ^{ + sharedRemoteConfigQueue = + dispatch_queue_create(RCNRemoteConfigQueueLabel, DISPATCH_QUEUE_SERIAL); + }); + return sharedRemoteConfigQueue; +} + +/// Designated initializer +- (instancetype)initWithAppName:(NSString *)appName + FIROptions:(FIROptions *)options + namespace:(NSString *)FIRNamespace + DBManager:(RCNConfigDBManager *)DBManager + configContent:(RCNConfigContent *)configContent + analytics:(nullable id)analytics { + self = [super init]; + if (self) { + _appName = appName; + _DBManager = DBManager; + // The fully qualified Firebase namespace is namespace:firappname. + _FIRNamespace = [NSString stringWithFormat:@"%@:%@", FIRNamespace, appName]; + + // Initialize RCConfigContent if not already. + _configContent = configContent; + _settings = [[RCNConfigSettings alloc] initWithDatabaseManager:_DBManager + namespace:_FIRNamespace + firebaseAppName:appName + googleAppID:options.googleAppID]; + + FIRExperimentController *experimentController = [FIRExperimentController sharedInstance]; + _configExperiment = [[RCNConfigExperiment alloc] initWithDBManager:_DBManager + experimentController:experimentController]; + /// Serial queue for read and write lock. + _queue = [FIRRemoteConfig sharedRemoteConfigSerialQueue]; + + // Initialize with default config settings. + [self setDefaultConfigSettings]; + _configFetch = [[RCNConfigFetch alloc] initWithContent:_configContent + DBManager:_DBManager + settings:_settings + analytics:analytics + experiment:_configExperiment + queue:_queue + namespace:_FIRNamespace + options:options]; + + _configRealtime = [[RCNConfigRealtime alloc] init:_configFetch + settings:_settings + namespace:_FIRNamespace + options:options]; + + [_settings loadConfigFromMetadataTable]; + + if (analytics) { + _listeners = [[NSMutableArray alloc] init]; + RCNPersonalization *personalization = + [[RCNPersonalization alloc] initWithAnalytics:analytics]; + [self addListener:^(NSString *key, NSDictionary *config) { + [personalization logArmActive:key config:config]; + }]; + } + } + return self; +} + +// Initialize with default config settings. +- (void)setDefaultConfigSettings { + // Set the default config settings. + self->_settings.fetchTimeout = RCNHTTPDefaultConnectionTimeout; + self->_settings.minimumFetchInterval = RCNDefaultMinimumFetchInterval; +} + +- (void)ensureInitializedWithCompletionHandler: + (nonnull FIRRemoteConfigInitializationCompletion)completionHandler { + __weak FIRRemoteConfig *weakSelf = self; + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ + FIRRemoteConfig *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + BOOL initializationSuccess = [self->_configContent initializationSuccessful]; + NSError *error = nil; + if (!initializationSuccess) { + error = [[NSError alloc] + initWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{NSLocalizedDescriptionKey : @"Timed out waiting for database load."}]; + } + completionHandler(error); + }); +} + +/// Adds a listener that will be called whenever one of the get methods is called. +/// @param listener Function that takes in the parameter key and the config. +- (void)addListener:(nonnull FIRRemoteConfigListener)listener { + @synchronized(_listeners) { + [_listeners addObject:listener]; + } +} + +- (void)callListeners:(NSString *)key config:(NSDictionary *)config { + @synchronized(_listeners) { + for (FIRRemoteConfigListener listener in _listeners) { + dispatch_async(_queue, ^{ + listener(key, config); + }); + } + } +} + +#pragma mark - fetch + +- (void)fetchWithCompletionHandler:(FIRRemoteConfigFetchCompletion)completionHandler { + dispatch_async(_queue, ^{ + [self fetchWithExpirationDuration:self->_settings.minimumFetchInterval + completionHandler:completionHandler]; + }); +} + +- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler { + FIRRemoteConfigFetchCompletion completionHandlerCopy = nil; + if (completionHandler) { + completionHandlerCopy = [completionHandler copy]; + } + [_configFetch fetchConfigWithExpirationDuration:expirationDuration + completionHandler:completionHandlerCopy]; +} + +#pragma mark - fetchAndActivate + +- (void)fetchAndActivateWithCompletionHandler: + (FIRRemoteConfigFetchAndActivateCompletion)completionHandler { + __weak FIRRemoteConfig *weakSelf = self; + FIRRemoteConfigFetchCompletion fetchCompletion = + ^(FIRRemoteConfigFetchStatus fetchStatus, NSError *fetchError) { + FIRRemoteConfig *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + // Fetch completed. We are being called on the main queue. + // If fetch is successful, try to activate the fetched config + if (fetchStatus == FIRRemoteConfigFetchStatusSuccess && !fetchError) { + [strongSelf activateWithCompletion:^(BOOL changed, NSError *_Nullable activateError) { + if (completionHandler) { + FIRRemoteConfigFetchAndActivateStatus status = + activateError ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData + : FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote; + dispatch_async(dispatch_get_main_queue(), ^{ + completionHandler(status, nil); + }); + } + }]; + } else if (completionHandler) { + FIRRemoteConfigFetchAndActivateStatus status = + fetchStatus == FIRRemoteConfigFetchStatusSuccess + ? FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData + : FIRRemoteConfigFetchAndActivateStatusError; + dispatch_async(dispatch_get_main_queue(), ^{ + completionHandler(status, fetchError); + }); + } + }; + [self fetchWithCompletionHandler:fetchCompletion]; +} + +#pragma mark - activate + +typedef void (^FIRRemoteConfigActivateChangeCompletion)(BOOL changed, NSError *_Nullable error); + +- (void)activateWithCompletion:(FIRRemoteConfigActivateChangeCompletion)completion { + __weak FIRRemoteConfig *weakSelf = self; + void (^applyBlock)(void) = ^(void) { + FIRRemoteConfig *strongSelf = weakSelf; + if (!strongSelf) { + NSError *error = [NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{@"ActivationFailureReason" : @"Internal Error."}]; + if (completion) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completion(NO, error); + }); + } + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000068", @"Internal error activating config."); + return; + } + // Check if the last fetched config has already been activated. Fetches with no data change are + // ignored. + if (strongSelf->_settings.lastETagUpdateTime == 0 || + strongSelf->_settings.lastETagUpdateTime <= strongSelf->_settings.lastApplyTimeInterval) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069", + @"Most recently fetched config is already activated."); + if (completion) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completion(NO, nil); + }); + } + return; + } + [strongSelf->_configContent copyFromDictionary:self->_configContent.fetchedConfig + toSource:RCNDBSourceActive + forNamespace:self->_FIRNamespace]; + strongSelf->_settings.lastApplyTimeInterval = [[NSDate date] timeIntervalSince1970]; + // New config has been activated at this point + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069", @"Config activated."); + [strongSelf->_configContent activatePersonalization]; + // Update last active template version number in setting and userDefaults. + [strongSelf->_settings updateLastActiveTemplateVersion]; + // Update activeRolloutMetadata + [strongSelf->_configContent activateRolloutMetadata:^(BOOL success) { + if (success) { + [self notifyRolloutsStateChange:strongSelf->_configContent.activeRolloutMetadata + versionNumber:strongSelf->_settings.lastActiveTemplateVersion]; + } + }]; + + // Update experiments only for 3p namespace + NSString *namespace = [strongSelf->_FIRNamespace + substringToIndex:[strongSelf->_FIRNamespace rangeOfString:@":"].location]; + if ([namespace isEqualToString:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform]) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self notifyConfigHasActivated]; + }); + [strongSelf->_configExperiment updateExperimentsWithHandler:^(NSError *_Nullable error) { + if (completion) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completion(YES, nil); + }); + } + }]; + } else { + if (completion) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + completion(YES, nil); + }); + } + } + }; + dispatch_async(_queue, applyBlock); +} + +- (void)notifyConfigHasActivated { + // Need a valid google app name. + if (!_appName) { + return; + } + // The Remote Config Swift SDK will be listening for this notification so it can tell SwiftUI to + // update the UI. + NSDictionary *appInfoDict = @{kFIRAppNameKey : _appName}; + [[NSNotificationCenter defaultCenter] postNotificationName:FIRRemoteConfigActivateNotification + object:self + userInfo:appInfoDict]; +} + +#pragma mark - helpers +- (NSString *)fullyQualifiedNamespace:(NSString *)namespace { + // If this is already a fully qualified namespace, return. + if ([namespace rangeOfString:@":"].location != NSNotFound) { + return namespace; + } + NSString *fullyQualifiedNamespace = [NSString stringWithFormat:@"%@:%@", namespace, _appName]; + return fullyQualifiedNamespace; +} + +- (FIRRemoteConfigValue *)defaultValueForFullyQualifiedNamespace:(NSString *)namespace + key:(NSString *)key { + FIRRemoteConfigValue *value = self->_configContent.defaultConfig[namespace][key]; + if (!value) { + value = [[FIRRemoteConfigValue alloc] + initWithData:[NSData data] + source:(FIRRemoteConfigSource)FIRRemoteConfigSourceStatic]; + } + return value; +} + +#pragma mark - Get Config Result + +- (FIRRemoteConfigValue *)objectForKeyedSubscript:(NSString *)key { + return [self configValueForKey:key]; +} + +- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key { + if (!key) { + return [[FIRRemoteConfigValue alloc] initWithData:[NSData data] + source:FIRRemoteConfigSourceStatic]; + } + NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + __block FIRRemoteConfigValue *value; + dispatch_sync(_queue, ^{ + value = self->_configContent.activeConfig[FQNamespace][key]; + if (value) { + if (value.source != FIRRemoteConfigSourceRemote) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000001", + @"Key %@ should come from source:%zd instead coming from source: %zd.", key, + (long)FIRRemoteConfigSourceRemote, (long)value.source); + } + [self callListeners:key + config:[self->_configContent getConfigAndMetadataForNamespace:FQNamespace]]; + return; + } + value = [self defaultValueForFullyQualifiedNamespace:FQNamespace key:key]; + }); + return value; +} + +- (FIRRemoteConfigValue *)configValueForKey:(NSString *)key source:(FIRRemoteConfigSource)source { + if (!key) { + return [[FIRRemoteConfigValue alloc] initWithData:[NSData data] + source:FIRRemoteConfigSourceStatic]; + } + NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + + __block FIRRemoteConfigValue *value; + dispatch_sync(_queue, ^{ + if (source == FIRRemoteConfigSourceRemote) { + value = self->_configContent.activeConfig[FQNamespace][key]; + } else if (source == FIRRemoteConfigSourceDefault) { + value = self->_configContent.defaultConfig[FQNamespace][key]; + } else { + value = [[FIRRemoteConfigValue alloc] initWithData:[NSData data] + source:FIRRemoteConfigSourceStatic]; + } + }); + return value; +} + +- (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state + objects:(id __unsafe_unretained[])stackbuf + count:(NSUInteger)len { + __block NSUInteger localValue; + dispatch_sync(_queue, ^{ + localValue = + [self->_configContent.activeConfig[self->_FIRNamespace] countByEnumeratingWithState:state + objects:stackbuf + count:len]; + }); + return localValue; +} + +#pragma mark - Properties + +/// Last fetch completion time. +- (NSDate *)lastFetchTime { + __block NSDate *fetchTime; + dispatch_sync(_queue, ^{ + NSTimeInterval lastFetchTime = self->_settings.lastFetchTimeInterval; + fetchTime = [NSDate dateWithTimeIntervalSince1970:lastFetchTime]; + }); + return fetchTime; +} + +- (FIRRemoteConfigFetchStatus)lastFetchStatus { + __block FIRRemoteConfigFetchStatus currentStatus; + dispatch_sync(_queue, ^{ + currentStatus = self->_settings.lastFetchStatus; + }); + return currentStatus; +} + +- (NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source { + __block NSArray *keys = [[NSArray alloc] init]; + dispatch_sync(_queue, ^{ + NSString *FQNamespace = [self fullyQualifiedNamespace:self->_FIRNamespace]; + switch (source) { + case FIRRemoteConfigSourceDefault: + if (self->_configContent.defaultConfig[FQNamespace]) { + keys = [[self->_configContent.defaultConfig[FQNamespace] allKeys] copy]; + } + break; + case FIRRemoteConfigSourceRemote: + if (self->_configContent.activeConfig[FQNamespace]) { + keys = [[self->_configContent.activeConfig[FQNamespace] allKeys] copy]; + } + break; + default: + break; + } + }); + return keys; +} + +- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix { + __block NSMutableSet *keys = [[NSMutableSet alloc] init]; + dispatch_sync(_queue, ^{ + NSString *FQNamespace = [self fullyQualifiedNamespace:self->_FIRNamespace]; + if (self->_configContent.activeConfig[FQNamespace]) { + NSArray *allKeys = [self->_configContent.activeConfig[FQNamespace] allKeys]; + if (!prefix.length) { + keys = [NSMutableSet setWithArray:allKeys]; + } else { + for (NSString *key in allKeys) { + if ([key hasPrefix:prefix]) { + [keys addObject:key]; + } + } + } + } + }); + return [keys copy]; +} + +#pragma mark - Defaults + +- (void)setDefaults:(NSDictionary *)defaultConfig { + NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + NSDictionary *defaultConfigCopy = [[NSDictionary alloc] init]; + if (defaultConfig) { + defaultConfigCopy = [defaultConfig copy]; + } + void (^setDefaultsBlock)(void) = ^(void) { + NSDictionary *namespaceToDefaults = @{FQNamespace : defaultConfigCopy}; + [self->_configContent copyFromDictionary:namespaceToDefaults + toSource:RCNDBSourceDefault + forNamespace:FQNamespace]; + self->_settings.lastSetDefaultsTimeInterval = [[NSDate date] timeIntervalSince1970]; + }; + dispatch_async(_queue, setDefaultsBlock); +} + +- (FIRRemoteConfigValue *)defaultValueForKey:(NSString *)key { + NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + __block FIRRemoteConfigValue *value; + dispatch_sync(_queue, ^{ + NSDictionary *defaultConfig = self->_configContent.defaultConfig; + value = defaultConfig[FQNamespace][key]; + if (value) { + if (value.source != FIRRemoteConfigSourceDefault) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000002", + @"Key %@ should come from source:%zd instead coming from source: %zd", key, + (long)FIRRemoteConfigSourceDefault, (long)value.source); + } + } + }); + return value; +} + +- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName { + if (!fileName || fileName.length == 0) { + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037", + @"The plist file '%@' could not be found by Remote Config.", fileName); + return; + } + NSArray *bundles = @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ]; + + for (NSBundle *bundle in bundles) { + NSString *plistFile = [bundle pathForResource:fileName ofType:@"plist"]; + // Use the first one we find. + if (plistFile) { + NSDictionary *defaultConfig = [[NSDictionary alloc] initWithContentsOfFile:plistFile]; + if (defaultConfig) { + [self setDefaults:defaultConfig]; + } + return; + } + } + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000037", + @"The plist file '%@' could not be found by Remote Config.", fileName); +} + +#pragma mark - custom variables + +- (FIRRemoteConfigSettings *)configSettings { + __block NSTimeInterval minimumFetchInterval = RCNDefaultMinimumFetchInterval; + __block NSTimeInterval fetchTimeout = RCNHTTPDefaultConnectionTimeout; + dispatch_sync(_queue, ^{ + minimumFetchInterval = self->_settings.minimumFetchInterval; + fetchTimeout = self->_settings.fetchTimeout; + }); + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000066", + @"Successfully read configSettings. Minimum Fetch Interval:%f, " + @"Fetch timeout: %f", + minimumFetchInterval, fetchTimeout); + FIRRemoteConfigSettings *settings = [[FIRRemoteConfigSettings alloc] init]; + settings.minimumFetchInterval = minimumFetchInterval; + settings.fetchTimeout = fetchTimeout; + /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated. + [_configFetch recreateNetworkSession]; + return settings; +} + +- (void)setConfigSettings:(FIRRemoteConfigSettings *)configSettings { + void (^setConfigSettingsBlock)(void) = ^(void) { + if (!configSettings) { + return; + } + + self->_settings.minimumFetchInterval = configSettings.minimumFetchInterval; + self->_settings.fetchTimeout = configSettings.fetchTimeout; + /// The NSURLSession needs to be recreated whenever the fetch timeout may be updated. + [self->_configFetch recreateNetworkSession]; + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000067", + @"Successfully set configSettings. Minimum Fetch Interval:%f, " + @"Fetch timeout:%f", + configSettings.minimumFetchInterval, configSettings.fetchTimeout); + }; + dispatch_async(_queue, setConfigSettingsBlock); +} + +#pragma mark - Realtime + +- (FIRConfigUpdateListenerRegistration *)addOnConfigUpdateListener: + (void (^_Nonnull)(FIRRemoteConfigUpdate *update, NSError *_Nullable error))listener { + return [self->_configRealtime addConfigUpdateListener:listener]; +} + +#pragma mark - Rollout + +- (void)addRemoteConfigInteropSubscriber:(id)subscriber { + [[NSNotificationCenter defaultCenter] + addObserverForName:FIRRolloutsStateDidChangeNotificationName + object:self + queue:nil + usingBlock:^(NSNotification *_Nonnull notification) { + FIRRolloutsState *rolloutsState = + notification.userInfo[FIRRolloutsStateDidChangeNotificationName]; + [subscriber rolloutsStateDidChange:rolloutsState]; + }]; + // Send active rollout metadata stored in persistence while app launched if there is activeConfig + NSString *fullyQualifiedNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + NSDictionary *activeConfig = self->_configContent.activeConfig; + if (activeConfig[fullyQualifiedNamespace] && activeConfig[fullyQualifiedNamespace].count > 0) { + [self notifyRolloutsStateChange:self->_configContent.activeRolloutMetadata + versionNumber:self->_settings.lastActiveTemplateVersion]; + } +} + +- (void)notifyRolloutsStateChange:(NSArray *)rolloutMetadata + versionNumber:(NSString *)versionNumber { + NSArray *rolloutsAssignments = + [self rolloutsAssignmentsWith:rolloutMetadata versionNumber:versionNumber]; + FIRRolloutsState *rolloutsState = + [[FIRRolloutsState alloc] initWithAssignmentList:rolloutsAssignments]; + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000069", + @"Send rollouts state notification with name %@ to RemoteConfigInterop.", + FIRRolloutsStateDidChangeNotificationName); + [[NSNotificationCenter defaultCenter] + postNotificationName:FIRRolloutsStateDidChangeNotificationName + object:self + userInfo:@{FIRRolloutsStateDidChangeNotificationName : rolloutsState}]; +} + +- (NSArray *)rolloutsAssignmentsWith: + (NSArray *)rolloutMetadata + versionNumber:(NSString *)versionNumber { + NSMutableArray *rolloutsAssignments = [[NSMutableArray alloc] init]; + NSString *FQNamespace = [self fullyQualifiedNamespace:_FIRNamespace]; + for (NSDictionary *metadata in rolloutMetadata) { + NSString *rolloutId = metadata[RCNFetchResponseKeyRolloutID]; + NSString *variantID = metadata[RCNFetchResponseKeyVariantID]; + NSArray *affectedParameterKeys = metadata[RCNFetchResponseKeyAffectedParameterKeys]; + if (rolloutId && variantID && affectedParameterKeys) { + for (NSString *key in affectedParameterKeys) { + FIRRemoteConfigValue *value = self->_configContent.activeConfig[FQNamespace][key]; + if (!value) { + value = [self defaultValueForFullyQualifiedNamespace:FQNamespace key:key]; + } + FIRRolloutAssignment *assignment = + [[FIRRolloutAssignment alloc] initWithRolloutId:rolloutId + variantId:variantID + templateVersion:[versionNumber longLongValue] + parameterKey:key + parameterValue:value.stringValue]; + [rolloutsAssignments addObject:assignment]; + } + } + } + return rolloutsAssignments; +} +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h new file mode 100644 index 0000000..e8dda53 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +@import FirebaseRemoteConfigInterop; + +@class FIRApp; +@class FIRRemoteConfig; + +NS_ASSUME_NONNULL_BEGIN + +/// Provides and creates instances of Remote Config based on the namespace provided. Used in the +/// interop registration process to keep track of RC instances for each `FIRApp` instance. +@protocol FIRRemoteConfigProvider + +/// Cached instances of Remote Config objects. +@property(nonatomic, strong) NSMutableDictionary *instances; + +/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist. +- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace; + +@end + +/// A concrete implementation for FIRRemoteConfigInterop to create Remote Config instances and +/// register with Core's component system. +@interface FIRRemoteConfigComponent + : NSObject + +/// The FIRApp that instances will be set up with. +@property(nonatomic, weak, readonly) FIRApp *app; + +/// Cached instances of Remote Config objects. +@property(nonatomic, strong) NSMutableDictionary *instances; + +/// Clear all the component instances from the singleton which created previously, this is for +/// testing only ++ (void)clearAllComponentInstances; + +/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist. +- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace; + +/// Default initializer. +- (instancetype)initWithApp:(FIRApp *)app NS_DESIGNATED_INITIALIZER; + +- (instancetype)init __attribute__((unavailable("Use `initWithApp:`."))); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m new file mode 100644 index 0000000..84a4a50 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.m @@ -0,0 +1,151 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/FIRRemoteConfigComponent.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +@implementation FIRRemoteConfigComponent + +// Because Component now need to register two protocols (provider and interop), we need a way to +// return the same component instance for both registered protocol, this singleton pattern allow us +// to return the same component object for both registration callback. +static NSMutableDictionary *_componentInstances = nil; + ++ (FIRRemoteConfigComponent *)getComponentForApp:(FIRApp *)app { + @synchronized(_componentInstances) { + // need to init the dictionary first + if (!_componentInstances) { + _componentInstances = [[NSMutableDictionary alloc] init]; + } + if (![_componentInstances objectForKey:app.name]) { + _componentInstances[app.name] = [[self alloc] initWithApp:app]; + } + return _componentInstances[app.name]; + } + return nil; +} + ++ (void)clearAllComponentInstances { + @synchronized(_componentInstances) { + [_componentInstances removeAllObjects]; + } +} + +/// Default method for retrieving a Remote Config instance, or creating one if it doesn't exist. +- (FIRRemoteConfig *)remoteConfigForNamespace:(NSString *)remoteConfigNamespace { + if (!remoteConfigNamespace) { + // TODO: Throw an error? Return nil? What do we want to do? + return nil; + } + + // Validate the required information is available. + FIROptions *options = self.app.options; + NSString *errorPropertyName; + if (options.googleAppID.length == 0) { + errorPropertyName = @"googleAppID"; + } else if (options.GCMSenderID.length == 0) { + errorPropertyName = @"GCMSenderID"; + } else if (options.projectID.length == 0) { + errorPropertyName = @"projectID"; + } + + if (errorPropertyName) { + NSString *const kFirebaseConfigErrorDomain = @"com.firebase.config"; + [NSException + raise:kFirebaseConfigErrorDomain + format:@"%@", + [NSString + stringWithFormat: + @"Firebase Remote Config is missing the required %@ property from the " + @"configured FirebaseApp and will not be able to function properly. Please " + @"fix this issue to ensure that Firebase is correctly configured.", + errorPropertyName]]; + } + + FIRRemoteConfig *instance = self.instances[remoteConfigNamespace]; + if (!instance) { + FIRApp *app = self.app; + id analytics = + app.isDefaultApp ? FIR_COMPONENT(FIRAnalyticsInterop, app.container) : nil; + instance = [[FIRRemoteConfig alloc] initWithAppName:app.name + FIROptions:app.options + namespace:remoteConfigNamespace + DBManager:[RCNConfigDBManager sharedInstance] + configContent:[RCNConfigContent sharedInstance] + analytics:analytics]; + self.instances[remoteConfigNamespace] = instance; + } + + return instance; +} + +/// Default initializer. +- (instancetype)initWithApp:(FIRApp *)app { + self = [super init]; + if (self) { + _app = app; + _instances = [[NSMutableDictionary alloc] initWithCapacity:1]; + } + return self; +} + +#pragma mark - Lifecycle + ++ (void)load { + // Register as an internal library to be part of the initialization process. The name comes from + // go/firebase-sdk-platform-info. + [FIRApp registerInternalLibrary:self withName:@"fire-rc"]; +} + +#pragma mark - Interoperability + ++ (NSArray *)componentsToRegister { + FIRComponent *rcProvider = [FIRComponent + componentWithProtocol:@protocol(FIRRemoteConfigProvider) + instantiationTiming:FIRInstantiationTimingAlwaysEager + creationBlock:^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + // Cache the component so instances of Remote Config are cached. + *isCacheable = YES; + return [FIRRemoteConfigComponent getComponentForApp:container.app]; + }]; + + // Unlike provider needs to setup a hard dependency on remote config, interop allows an optional + // dependency on RC + FIRComponent *rcInterop = [FIRComponent + componentWithProtocol:@protocol(FIRRemoteConfigInterop) + instantiationTiming:FIRInstantiationTimingAlwaysEager + creationBlock:^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) { + // Cache the component so instances of Remote Config are cached. + *isCacheable = YES; + return [FIRRemoteConfigComponent getComponentForApp:container.app]; + }]; + return @[ rcProvider, rcInterop ]; +} + +#pragma mark - Remote Config Interop Protocol + +- (void)registerRolloutsStateSubscriber:(id)subscriber + for:(NSString * _Nonnull)namespace { + FIRRemoteConfig *instance = [self remoteConfigForNamespace:namespace]; + [instance addRemoteConfigInteropSubscriber:subscriber]; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigUpdate.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigUpdate.m new file mode 100644 index 0000000..47a8c89 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/FIRRemoteConfigUpdate.m @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +@implementation FIRRemoteConfigUpdate { + NSSet *_updatedKeys; +} + +- (instancetype)initWithUpdatedKeys:(NSSet *)updatedKeys { + self = [super init]; + if (self) { + _updatedKeys = [updatedKeys copy]; + } + return self; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h new file mode 100644 index 0000000..4420dcb --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h @@ -0,0 +1,87 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "RCNConfigSettings.h" // This import is needed to expose settings for the Swift API tests. + +@class FIROptions; +@class RCNConfigContent; +@class RCNConfigDBManager; +@class RCNConfigFetch; +@class RCNConfigRealtime; +@protocol FIRAnalyticsInterop; +@protocol FIRRolloutsStateSubscriber; + +NS_ASSUME_NONNULL_BEGIN + +@class RCNConfigSettings; + +@interface FIRRemoteConfigUpdate () + +/// Designated initializer. +- (instancetype)initWithUpdatedKeys:(NSSet *)updatedKeys; +@end + +@interface FIRRemoteConfig () { + NSString *_FIRNamespace; +} + +/// Internal settings +@property(nonatomic, readonly, strong) RCNConfigSettings *settings; + +/// Config settings are custom settings. +@property(nonatomic, readwrite, strong, nonnull) RCNConfigFetch *configFetch; + +@property(nonatomic, readwrite, strong, nonnull) RCNConfigRealtime *configRealtime; + +/// Returns the FIRRemoteConfig instance for your namespace and for the default Firebase App. +/// This singleton object contains the complete set of Remote Config parameter values available to +/// the app, including the Active Config and Default Config.. This object also caches values fetched +/// from the Remote Config Server until they are copied to the Active Config by calling +/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase +/// namespace service, you should use this class method to create a shared instance of the +/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config +/// Server and the Firebase service. This API is used internally by 2P teams. ++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace + NS_SWIFT_NAME(remoteConfig(FIRNamespace:)); + +/// Returns the FIRRemoteConfig instance for your namespace and for the default 3P developer's app. +/// This singleton object contains the complete set of Remote Config parameter values available to +/// the app, including the Active Config and Default Config. This object also caches values fetched +/// from the Remote Config Server until they are copied to the Active Config by calling +/// activateFetched. When you fetch values from the Remote Config Server using the default Firebase +/// namespace service, you should use this class method to create a shared instance of the +/// FIRRemoteConfig object to ensure that your app will function properly with the Remote Config +/// Server and the Firebase service. ++ (FIRRemoteConfig *)remoteConfigWithFIRNamespace:(NSString *)remoteConfigNamespace + app:(FIRApp *)app + NS_SWIFT_NAME(remoteConfig(FIRNamespace:app:)); + +/// Initialize a FIRRemoteConfig instance with all the required parameters directly. This exists so +/// tests can create FIRRemoteConfig objects without needing FIRApp. +- (instancetype)initWithAppName:(NSString *)appName + FIROptions:(FIROptions *)options + namespace:(NSString *)FIRNamespace + DBManager:(RCNConfigDBManager *)DBManager + configContent:(RCNConfigContent *)configContent + analytics:(nullable id)analytics; + +/// Register RolloutsStateSubcriber to FIRRemoteConfig instance +- (void)addRemoteConfigInteropSubscriber:(id _Nonnull)subscriber; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h new file mode 100644 index 0000000..dbef87d --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +@class FIROptions; +@class RCNConfigContent; +@class RCNConfigSettings; +@class RCNConfigExperiment; +@class RCNConfigDBManager; + +NS_ASSUME_NONNULL_BEGIN + +/// Completion handler invoked by NSSessionFetcher. +typedef void (^RCNConfigFetcherCompletion)(NSData *data, NSURLResponse *response, NSError *error); + +/// Completion handler invoked after a fetch that contains the updated keys +typedef void (^RCNConfigFetchCompletion)(FIRRemoteConfigFetchStatus status, + FIRRemoteConfigUpdate *update, + NSError *error); + +@interface RCNConfigFetch : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer +- (instancetype)initWithContent:(RCNConfigContent *)content + DBManager:(RCNConfigDBManager *)DBManager + settings:(RCNConfigSettings *)settings + analytics:(nullable id)analytics + experiment:(nullable RCNConfigExperiment *)experiment + queue:(dispatch_queue_t)queue + namespace:(NSString *)firebaseNamespace + options:(FIROptions *)firebaseOptions NS_DESIGNATED_INITIALIZER; + +/// Fetches config data keyed by namespace. Completion block will be called on the main queue. +/// @param expirationDuration Expiration duration, in seconds. +/// @param completionHandler Callback handler. +- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler; + +/// Fetches config data immediately, keyed by namespace. Completion block will be called on the main +/// queue. +/// @param fetchAttemptNumber The number of the fetch attempt. +/// @param completionHandler Callback handler. +- (void)realtimeFetchConfigWithNoExpirationDuration:(NSInteger)fetchAttemptNumber + completionHandler:(RCNConfigFetchCompletion)completionHandler; + +/// Add the ability to update NSURLSession's timeout after a session has already been created. +- (void)recreateNetworkSession; + +/// Provide fetchSession for tests to override. +@property(nonatomic, readwrite, strong, nonnull) NSURLSession *fetchSession; + +/// Provide config template version number for Realtime config client. +@property(nonatomic, copy, nonnull) NSString *templateVersionNumber; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h new file mode 100644 index 0000000..034c50c --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h @@ -0,0 +1,152 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import + +@class RCNConfigDBManager; + +/// This internal class contains a set of variables that are unique among all the config instances. +/// It also handles all metadata and internal metadata. This class is not thread safe and does not +/// inherently allow for synchronized access. Callers are responsible for synchronization +/// (currently using serial dispatch queues). +@interface RCNConfigSettings : NSObject + +/// The time interval that config data stays fresh. +@property(nonatomic, readwrite, assign) NSTimeInterval minimumFetchInterval; + +/// The timeout to set for outgoing fetch requests. +@property(nonatomic, readwrite, assign) NSTimeInterval fetchTimeout; +// The Google App ID of the configured FIRApp. +@property(nonatomic, readwrite, copy) NSString *googleAppID; +#pragma mark - Data required by config request. +/// Device authentication ID required by config request. +@property(nonatomic, copy) NSString *deviceAuthID; +/// Secret Token required by config request. +@property(nonatomic, copy) NSString *secretToken; +/// Device data version of checkin information. +@property(nonatomic, copy) NSString *deviceDataVersion; +/// InstallationsID. +@property(nonatomic, copy) NSString *configInstallationsIdentifier; +/// Installations token. +@property(nonatomic, copy) NSString *configInstallationsToken; + +/// A list of successful fetch timestamps in milliseconds. +/// TODO Not used anymore. Safe to remove. +@property(nonatomic, readonly, copy) NSArray *successFetchTimes; +/// A list of failed fetch timestamps in milliseconds. +@property(nonatomic, readonly, copy) NSArray *failureFetchTimes; +/// Custom variable (aka App context digest). This is the pending custom variables request before +/// fetching. +@property(nonatomic, copy) NSDictionary *customVariables; +/// Cached internal metadata from internal metadata table. It contains customized information such +/// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time +/// interval. Client has the default value of each parameters, they are only saved in +/// internalMetadata if they have been customize by developers. +@property(nonatomic, readonly, copy) NSDictionary *internalMetadata; +/// Device conditions since last successful fetch from the backend. Device conditions including +/// app +/// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for +/// determing whether to throttle. +@property(nonatomic, readonly, copy) NSDictionary *deviceContext; +/// Bundle Identifier +@property(nonatomic, readonly, copy) NSString *bundleIdentifier; +/// The time of last successful config fetch. +@property(nonatomic, readonly, assign) NSTimeInterval lastFetchTimeInterval; +/// Last fetch status. +@property(nonatomic, readwrite, assign) FIRRemoteConfigFetchStatus lastFetchStatus; +/// The reason that last fetch failed. +@property(nonatomic, readwrite, assign) FIRRemoteConfigError lastFetchError; +/// The time of last apply timestamp. +@property(nonatomic, readwrite, assign) NSTimeInterval lastApplyTimeInterval; +/// The time of last setDefaults timestamp. +@property(nonatomic, readwrite, assign) NSTimeInterval lastSetDefaultsTimeInterval; +/// The latest eTag value stored from the last successful response. +@property(nonatomic, readwrite, assign) NSString *lastETag; +/// The timestamp of the last eTag update. +@property(nonatomic, readwrite, assign) NSTimeInterval lastETagUpdateTime; +/// Last fetched template version. +@property(nonatomic, readwrite, assign) NSString *lastFetchedTemplateVersion; +/// Last active template version. +@property(nonatomic, readwrite, assign) NSString *lastActiveTemplateVersion; + +#pragma mark Throttling properties + +/// Throttling intervals are based on https://cloud.google.com/storage/docs/exponential-backoff +/// Returns true if client has fetched config and has not got back from server. This is used to +/// determine whether there is another config task infight when fetching. +@property(atomic, readwrite, assign) BOOL isFetchInProgress; +/// Returns the current retry interval in seconds set for exponential backoff. +@property(nonatomic, readwrite, assign) double exponentialBackoffRetryInterval; +/// Returns the time in seconds until the next request is allowed while in exponential backoff mode. +@property(nonatomic, readonly, assign) NSTimeInterval exponentialBackoffThrottleEndTime; +/// Returns the current retry interval in seconds set for exponential backoff for the Realtime +/// service. +@property(nonatomic, readwrite, assign) double realtimeExponentialBackoffRetryInterval; +/// Returns the time in seconds until the next request is allowed while in exponential backoff mode +/// for the Realtime service. +@property(nonatomic, readonly, assign) NSTimeInterval realtimeExponentialBackoffThrottleEndTime; +/// Realtime connection attempts. +@property(nonatomic, readwrite, assign) int realtimeRetryCount; + +#pragma mark Throttling Methods + +/// Designated initializer. +- (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager + namespace:(NSString *)FIRNamespace + firebaseAppName:(NSString *)appName + googleAppID:(NSString *)googleAppID; + +/// Returns a fetch request with the latest device and config change. +/// Whenever user issues a fetch api call, collect the latest request. +/// @param userProperties User properties to set to config request. +/// @return Config fetch request string +- (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties; + +/// Returns metadata from metadata table. +- (NSDictionary *)loadConfigFromMetadataTable; + +/// Updates internal content with the latest successful config response. +- (void)updateInternalContentWithResponse:(NSDictionary *)response; + +/// Updates the metadata table with the current fetch status. +/// @param fetchSuccess True if fetch was successful. +- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess + templateVersion:(NSString *)templateVersion; + +/// Increases the throttling time. Should only be called if the fetch error indicates a server +/// issue. +- (void)updateExponentialBackoffTime; + +/// Increases the throttling time for Realtime. Should only be called if the Realtime error +/// indicates a server issue. +- (void)updateRealtimeExponentialBackoffTime; + +/// Update last active template version from last fetched template version. +- (void)updateLastActiveTemplateVersion; + +/// Returns the difference between the Realtime backoff end time and the current time in a +/// NSTimeInterval format. +- (NSTimeInterval)getRealtimeBackoffInterval; + +/// Returns true if we are in exponential backoff mode and it is not yet the next request time. +- (BOOL)shouldThrottle; + +/// Returns true if the last fetch is outside the minimum fetch interval supplied. +- (BOOL)hasMinimumFetchIntervalElapsed:(NSTimeInterval)minimumFetchInterval; + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h new file mode 100644 index 0000000..0a45617 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h @@ -0,0 +1,360 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRApp; + +/// The Firebase Remote Config service default namespace, to be used if the API method does not +/// specify a different namespace. Use the default namespace if configuring from the Google Firebase +/// service. +extern NSString *const _Nonnull FIRNamespaceGoogleMobilePlatform NS_SWIFT_NAME( + NamespaceGoogleMobilePlatform); + +/// Key used to manage throttling in NSError user info when the refreshing of Remote Config +/// parameter values (data) is throttled. The value of this key is the elapsed time since 1970, +/// measured in seconds. +extern NSString *const _Nonnull FIRRemoteConfigThrottledEndTimeInSecondsKey NS_SWIFT_NAME( + RemoteConfigThrottledEndTimeInSecondsKey); + +/** + * Listener registration returned by `addOnConfigUpdateListener`. Calling its method `remove` stops + * the associated listener from receiving config updates and unregisters itself. + * + * If remove is called and no other listener registrations remain, the connection to the real-time + * RC backend is closed. Subsequently calling `addOnConfigUpdateListener` will re-open the + * connection. + */ +NS_SWIFT_NAME(ConfigUpdateListenerRegistration) +@interface FIRConfigUpdateListenerRegistration : NSObject +/** + * Removes the listener associated with this `ConfigUpdateListenerRegistration`. After the + * initial call, subsequent calls have no effect. + */ +- (void)remove; +@end + +/// Indicates whether updated data was successfully fetched. +typedef NS_ENUM(NSInteger, FIRRemoteConfigFetchStatus) { + /// Config has never been fetched. + FIRRemoteConfigFetchStatusNoFetchYet, + /// Config fetch succeeded. + FIRRemoteConfigFetchStatusSuccess, + /// Config fetch failed. + FIRRemoteConfigFetchStatusFailure, + /// Config fetch was throttled. + FIRRemoteConfigFetchStatusThrottled, +} NS_SWIFT_NAME(RemoteConfigFetchStatus); + +/// Indicates whether updated data was successfully fetched and activated. +typedef NS_ENUM(NSInteger, FIRRemoteConfigFetchAndActivateStatus) { + /// The remote fetch succeeded and fetched data was activated. + FIRRemoteConfigFetchAndActivateStatusSuccessFetchedFromRemote, + /// The fetch and activate succeeded from already fetched but yet unexpired config data. You can + /// control this using minimumFetchInterval property in FIRRemoteConfigSettings. + FIRRemoteConfigFetchAndActivateStatusSuccessUsingPreFetchedData, + /// The fetch and activate failed. + FIRRemoteConfigFetchAndActivateStatusError +} NS_SWIFT_NAME(RemoteConfigFetchAndActivateStatus); + +/// Remote Config error domain that handles errors when fetching data from the service. +extern NSString *const _Nonnull FIRRemoteConfigErrorDomain NS_SWIFT_NAME(RemoteConfigErrorDomain); +/// Firebase Remote Config service fetch error. +typedef NS_ERROR_ENUM(FIRRemoteConfigErrorDomain, FIRRemoteConfigError){ + /// Unknown or no error. + FIRRemoteConfigErrorUnknown = 8001, + /// Frequency of fetch requests exceeds throttled limit. + FIRRemoteConfigErrorThrottled = 8002, + /// Internal error that covers all internal HTTP errors. + FIRRemoteConfigErrorInternalError = 8003, +} NS_SWIFT_NAME(RemoteConfigError); + +/// Remote Config error domain that handles errors for the real-time config update service. +extern NSString *const _Nonnull FIRRemoteConfigUpdateErrorDomain NS_SWIFT_NAME(RemoteConfigUpdateErrorDomain); +/// Firebase Remote Config real-time config update service error. +typedef NS_ERROR_ENUM(FIRRemoteConfigUpdateErrorDomain, FIRRemoteConfigUpdateError){ + /// Unable to make a connection to the Remote Config backend. + FIRRemoteConfigUpdateErrorStreamError = 8001, + /// Unable to fetch the latest version of the config. + FIRRemoteConfigUpdateErrorNotFetched = 8002, + /// The ConfigUpdate message was unparsable. + FIRRemoteConfigUpdateErrorMessageInvalid = 8003, + /// The Remote Config real-time config update service is unavailable. + FIRRemoteConfigUpdateErrorUnavailable = 8004, +} NS_SWIFT_NAME(RemoteConfigUpdateError); + +/// Enumerated value that indicates the source of Remote Config data. Data can come from +/// the Remote Config service, the DefaultConfig that is available when the app is first installed, +/// or a static initialized value if data is not available from the service or DefaultConfig. +typedef NS_ENUM(NSInteger, FIRRemoteConfigSource) { + FIRRemoteConfigSourceRemote, ///< The data source is the Remote Config service. + FIRRemoteConfigSourceDefault, ///< The data source is the DefaultConfig defined for this app. + FIRRemoteConfigSourceStatic, ///< The data doesn't exist, return a static initialized value. +} NS_SWIFT_NAME(RemoteConfigSource); + +/// Completion handler invoked by fetch methods when they get a response from the server. +/// +/// @param status Config fetching status. +/// @param error Error message on failure. +typedef void (^FIRRemoteConfigFetchCompletion)(FIRRemoteConfigFetchStatus status, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Completion handler invoked by activate method upon completion. +/// @param error Error message on failure. Nil if activation was successful. +typedef void (^FIRRemoteConfigActivateCompletion)(NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Completion handler invoked upon completion of Remote Config initialization. +/// +/// @param initializationError nil if initialization succeeded. +typedef void (^FIRRemoteConfigInitializationCompletion)(NSError *_Nullable initializationError) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Completion handler invoked by the fetchAndActivate method. Used to convey status of fetch and, +/// if successful, resultant activate call +/// @param status Config fetching status. +/// @param error Error message on failure of config fetch +typedef void (^FIRRemoteConfigFetchAndActivateCompletion)( + FIRRemoteConfigFetchAndActivateStatus status, NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +#pragma mark - FIRRemoteConfigValue +/// This class provides a wrapper for Remote Config parameter values, with methods to get parameter +/// values as different data types. +NS_SWIFT_NAME(RemoteConfigValue) +@interface FIRRemoteConfigValue : NSObject +/// Gets the value as a string. +@property(nonatomic, readonly, nonnull) NSString *stringValue; +/// Gets the value as a number value. +@property(nonatomic, readonly, nonnull) NSNumber *numberValue; +/// Gets the value as a NSData object. +@property(nonatomic, readonly, nonnull) NSData *dataValue; +/// Gets the value as a boolean. +@property(nonatomic, readonly) BOOL boolValue; +/// Gets a foundation object (NSDictionary / NSArray) by parsing the value as JSON. This method uses +/// NSJSONSerialization's JSONObjectWithData method with an options value of 0. +@property(nonatomic, readonly, nullable) id JSONValue NS_SWIFT_NAME(jsonValue); +/// Identifies the source of the fetched value. +@property(nonatomic, readonly) FIRRemoteConfigSource source; +@end + +#pragma mark - FIRRemoteConfigSettings +/// Firebase Remote Config settings. +NS_SWIFT_NAME(RemoteConfigSettings) +@interface FIRRemoteConfigSettings : NSObject +/// Indicates the default value in seconds to set for the minimum interval that needs to elapse +/// before a fetch request can again be made to the Remote Config backend. After a fetch request to +/// the backend has succeeded, no additional fetch requests to the backend will be allowed until the +/// minimum fetch interval expires. Note that you can override this default on a per-fetch request +/// basis using `RemoteConfig.fetch(withExpirationDuration:)`. For example, setting +/// the expiration duration to 0 in the fetch request will override the `minimumFetchInterval` and +/// allow the request to proceed. +@property(nonatomic, assign) NSTimeInterval minimumFetchInterval; +/// Indicates the default value in seconds to abandon a pending fetch request made to the backend. +/// This value is set for outgoing requests as the `timeoutIntervalForRequest` as well as the +/// `timeoutIntervalForResource` on the `NSURLSession`'s configuration. +@property(nonatomic, assign) NSTimeInterval fetchTimeout; +@end + +#pragma mark - FIRRemoteConfigUpdate +/// Used by Remote Config real-time config update service, this class represents changes between the +/// newly fetched config and the current one. An instance of this class is passed to +/// `FIRRemoteConfigUpdateCompletion` when a new config version has been automatically fetched. +NS_SWIFT_NAME(RemoteConfigUpdate) +@interface FIRRemoteConfigUpdate : NSObject + +/// Parameter keys whose values have been updated from the currently activated values. Includes +/// keys that are added, deleted, and whose value, value source, or metadata has changed. +@property(nonatomic, readonly, nonnull) NSSet *updatedKeys; + +@end + +#pragma mark - FIRRemoteConfig +/// Firebase Remote Config class. The class method `remoteConfig()` can be used +/// to fetch, activate and read config results and set default config results on the default +/// Remote Config instance. +NS_SWIFT_NAME(RemoteConfig) +@interface FIRRemoteConfig : NSObject +/// Last successful fetch completion time. +@property(nonatomic, readonly, strong, nullable) NSDate *lastFetchTime; +/// Last fetch status. The status can be any enumerated value from `RemoteConfigFetchStatus`. +@property(nonatomic, readonly, assign) FIRRemoteConfigFetchStatus lastFetchStatus; +/// Config settings are custom settings. +@property(nonatomic, readwrite, strong, nonnull) FIRRemoteConfigSettings *configSettings; + +/// Returns the `RemoteConfig` instance configured for the default Firebase app. This singleton +/// object contains the complete set of Remote Config parameter values available to the app, +/// including the Active Config and Default Config. This object also caches values fetched from the +/// Remote Config server until they are copied to the Active Config by calling `activate()`. When +/// you fetch values from the Remote Config server using the default Firebase app, you should use +/// this class method to create and reuse a shared instance of `RemoteConfig`. ++ (nonnull FIRRemoteConfig *)remoteConfig NS_SWIFT_NAME(remoteConfig()); + +/// Returns the `RemoteConfig` instance for your (non-default) Firebase appID. Note that Firebase +/// analytics does not work for non-default app instances. This singleton object contains the +/// complete set of Remote Config parameter values available to the app, including the Active Config +/// and Default Config. This object also caches values fetched from the Remote Config Server until +/// they are copied to the Active Config by calling `activate())`. When you fetch values +/// from the Remote Config Server using the non-default Firebase app, you should use this +/// class method to create and reuse shared instance of `RemoteConfig`. ++ (nonnull FIRRemoteConfig *)remoteConfigWithApp:(nonnull FIRApp *)app + NS_SWIFT_NAME(remoteConfig(app:)); + +/// Unavailable. Use +remoteConfig instead. +- (nonnull instancetype)init __attribute__((unavailable("Use +remoteConfig instead."))); + +/// Ensures initialization is complete and clients can begin querying for Remote Config values. +/// @param completionHandler Initialization complete callback with error parameter. +- (void)ensureInitializedWithCompletionHandler: + (void (^_Nonnull)(NSError *_Nullable initializationError))completionHandler; +#pragma mark - Fetch +/// Fetches Remote Config data with a callback. Call `activate()` to make fetched data +/// available to your app. +/// +/// Note: This method uses a Firebase Installations token to identify the app instance, and once +/// it's called, it periodically sends data to the Firebase backend. (see +/// `Installations.authToken(completion:)`). +/// To stop the periodic sync, call `Installations.delete(completion:)` +/// and avoid calling this method again. +/// +/// @param completionHandler Fetch operation callback with status and error parameters. +- (void)fetchWithCompletionHandler:(void (^_Nullable)(FIRRemoteConfigFetchStatus status, + NSError *_Nullable error))completionHandler; + +/// Fetches Remote Config data and sets a duration that specifies how long config data lasts. +/// Call `activateWithCompletion:` to make fetched data available to your app. +/// +/// Note: This method uses a Firebase Installations token to identify the app instance, and once +/// it's called, it periodically sends data to the Firebase backend. (see +/// `Installations.authToken(completion:)`). +/// To stop the periodic sync, call `Installations.delete(completion:)` +/// and avoid calling this method again. +/// +/// @param expirationDuration Override the (default or optionally set `minimumFetchInterval` +/// property in RemoteConfigSettings) `minimumFetchInterval` for only the current request, in +/// seconds. Setting a value of 0 seconds will force a fetch to the backend. +/// @param completionHandler Fetch operation callback with status and error parameters. +- (void)fetchWithExpirationDuration:(NSTimeInterval)expirationDuration + completionHandler:(void (^_Nullable)(FIRRemoteConfigFetchStatus status, + NSError *_Nullable error))completionHandler; + +/// Fetches Remote Config data and if successful, activates fetched data. Optional completion +/// handler callback is invoked after the attempted activation of data, if the fetch call succeeded. +/// +/// Note: This method uses a Firebase Installations token to identify the app instance, and once +/// it's called, it periodically sends data to the Firebase backend. (see +/// `Installations.authToken(completion:)`). +/// To stop the periodic sync, call `Installations.delete(completion:)` +/// and avoid calling this method again. +/// +/// @param completionHandler Fetch operation callback with status and error parameters. +- (void)fetchAndActivateWithCompletionHandler: + (void (^_Nullable)(FIRRemoteConfigFetchAndActivateStatus status, + NSError *_Nullable error))completionHandler; + +#pragma mark - Apply + +/// Applies Fetched Config data to the Active Config, causing updates to the behavior and appearance +/// of the app to take effect (depending on how config data is used in the app). +/// @param completion Activate operation callback with changed and error parameters. +- (void)activateWithCompletion:(void (^_Nullable)(BOOL changed, + NSError *_Nullable error))completion; + +#pragma mark - Get Config +/// Enables access to configuration values by using object subscripting syntax. +/// For example: +/// let config = RemoteConfig.remoteConfig() +/// let value = config["yourKey"] +/// let boolValue = value.boolValue +/// let number = config["yourKey"].numberValue +- (nonnull FIRRemoteConfigValue *)objectForKeyedSubscript:(nonnull NSString *)key; + +/// Gets the config value. +/// @param key Config key. +- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key; + +/// Gets the config value of a given source from the default namespace. +/// @param key Config key. +/// @param source Config value source. +- (nonnull FIRRemoteConfigValue *)configValueForKey:(nullable NSString *)key + source:(FIRRemoteConfigSource)source; + +/// Gets all the parameter keys of a given source from the default namespace. +/// +/// @param source The config data source. +/// @return An array of keys under the given source. +- (nonnull NSArray *)allKeysFromSource:(FIRRemoteConfigSource)source; + +/// Returns the set of parameter keys that start with the given prefix, from the default namespace +/// in the active config. +/// +/// @param prefix The key prefix to look for. If prefix is nil or empty, returns all the +/// keys. +/// @return The set of parameter keys that start with the specified prefix. +- (nonnull NSSet *)keysWithPrefix:(nullable NSString *)prefix; + +#pragma mark - Defaults +/// Sets config defaults for parameter keys and values in the default namespace config. +/// @param defaults A dictionary mapping a NSString * key to a NSObject * value. +- (void)setDefaults:(nullable NSDictionary *)defaults; + +/// Sets default configs from plist for default namespace. +/// +/// @param fileName The plist file name, with no file name extension. For example, if the plist file +/// is named `defaultSamples.plist`: +/// `RemoteConfig.remoteConfig().setDefaults(fromPlist: "defaultSamples")` +- (void)setDefaultsFromPlistFileName:(nullable NSString *)fileName + NS_SWIFT_NAME(setDefaults(fromPlist:)); + +/// Returns the default value of a given key from the default config. +/// +/// @param key The parameter key of default config. +/// @return Returns the default value of the specified key. Returns +/// nil if the key doesn't exist in the default config. +- (nullable FIRRemoteConfigValue *)defaultValueForKey:(nullable NSString *)key; + +#pragma mark - Real-time Config Updates + +/// Completion handler invoked by `addOnConfigUpdateListener` when there is an update to +/// the config from the backend. +/// +/// @param configUpdate An instance of `FIRRemoteConfigUpdate` that contains information on which +/// key's values have changed. +/// @param error Error message on failure. +typedef void (^FIRRemoteConfigUpdateCompletion)(FIRRemoteConfigUpdate *_Nullable configUpdate, + NSError *_Nullable error) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Start listening for real-time config updates from the Remote Config backend and automatically +/// fetch updates when they're available. +/// +/// If a connection to the Remote Config backend is not already open, calling this method will +/// open it. Multiple listeners can be added by calling this method again, but subsequent calls +/// re-use the same connection to the backend. +/// +/// Note: Real-time Remote Config requires the Firebase Remote Config Realtime API. See Get started +/// with Firebase Remote Config at https://firebase.google.com/docs/remote-config/get-started for +/// more information. +/// +/// @param listener The configured listener that is called for every config update. +/// @return Returns a registration representing the listener. The registration contains +/// a remove method, which can be used to stop receiving updates for the provided listener. +- (FIRConfigUpdateListenerRegistration *_Nonnull)addOnConfigUpdateListener: + (FIRRemoteConfigUpdateCompletion _Nonnull)listener + NS_SWIFT_NAME(addOnConfigUpdateListener(remoteConfigUpdateCompletion:)); + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FirebaseRemoteConfig.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FirebaseRemoteConfig.h new file mode 100644 index 0000000..9ae8cea --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FirebaseRemoteConfig.h @@ -0,0 +1,17 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FIRRemoteConfig.h" diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h new file mode 100644 index 0000000..51d248c --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigConstants.h @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#define RCN_SEC_PER_MIN 60 +#define RCN_MSEC_PER_SEC 1000 + +/// Key prefix applied to all the packages (bundle IDs) in internal metadata. +static NSString *const RCNInternalMetadataAllPackagesPrefix = @"all_packages"; + +/// HTTP connection default timeout in seconds. +static const NSTimeInterval RCNHTTPDefaultConnectionTimeout = 60; +/// Default duration of how long config data lasts to stay fresh. +static const NSTimeInterval RCNDefaultMinimumFetchInterval = 43200; + +/// Label for serial queue for read/write lock on ivars. +static const char *RCNRemoteConfigQueueLabel = "com.google.GoogleConfigService.FIRRemoteConfig"; + +/// Constants for key names in the fetch response. +/// Key that includes an array of template entries. +static NSString *const RCNFetchResponseKeyEntries = @"entries"; +/// Key that includes data for experiment descriptions in ABT. +static NSString *const RCNFetchResponseKeyExperimentDescriptions = @"experimentDescriptions"; +/// Key that includes data for Personalization metadata. +static NSString *const RCNFetchResponseKeyPersonalizationMetadata = @"personalizationMetadata"; +/// Key that includes data for Rollout metadata. +static NSString *const RCNFetchResponseKeyRolloutMetadata = @"rolloutMetadata"; +/// Key that indicates rollout id in Rollout metadata. +static NSString *const RCNFetchResponseKeyRolloutID = @"rolloutId"; +/// Key that indicates variant id in Rollout metadata. +static NSString *const RCNFetchResponseKeyVariantID = @"variantId"; +/// Key that indicates affected parameter keys in Rollout Metadata. +static NSString *const RCNFetchResponseKeyAffectedParameterKeys = @"affectedParameterKeys"; +/// Error key. +static NSString *const RCNFetchResponseKeyError = @"error"; +/// Error code. +static NSString *const RCNFetchResponseKeyErrorCode = @"code"; +/// Error status. +static NSString *const RCNFetchResponseKeyErrorStatus = @"status"; +/// Error message. +static NSString *const RCNFetchResponseKeyErrorMessage = @"message"; +/// The current state of the backend template. +static NSString *const RCNFetchResponseKeyState = @"state"; +/// Default state (when not set). +static NSString *const RCNFetchResponseKeyStateUnspecified = @"INSTANCE_STATE_UNSPECIFIED"; +/// Config key/value map and/or ABT experiment list differs from last fetch. +/// TODO: Migrate to the new HTTP error codes once available in the backend. b/117182055 +static NSString *const RCNFetchResponseKeyStateUpdate = @"UPDATE"; +/// No template fetched. +static NSString *const RCNFetchResponseKeyStateNoTemplate = @"NO_TEMPLATE"; +/// Config key/value map and ABT experiment list both match last fetch. +static NSString *const RCNFetchResponseKeyStateNoChange = @"NO_CHANGE"; +/// Template found, but evaluates to empty (e.g. all keys omitted). +static NSString *const RCNFetchResponseKeyStateEmptyConfig = @"EMPTY_CONFIG"; +/// Fetched Template Version key +static NSString *const RCNFetchResponseKeyTemplateVersion = @"templateVersion"; +/// Active Template Version key +static NSString *const RCNActiveKeyTemplateVersion = @"activeTemplateVersion"; diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h new file mode 100644 index 0000000..e841007 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +typedef NS_ENUM(NSInteger, RCNDBSource) { + RCNDBSourceActive, + RCNDBSourceDefault, + RCNDBSourceFetched, +}; + +@class RCNConfigDBManager; + +/// This class handles all the config content that is fetched from the server, cached in local +/// config or persisted in database. +@interface RCNConfigContent : NSObject +/// Shared Singleton Instance ++ (instancetype)sharedInstance; + +/// Fetched config (aka pending config) data that is latest data from server that might or might +/// not be applied. +@property(nonatomic, readonly, copy) NSDictionary *fetchedConfig; +/// Active config that is available to external users; +@property(nonatomic, readonly, copy) NSDictionary *activeConfig; +/// Local default config that is provided by external users; +@property(nonatomic, readonly, copy) NSDictionary *defaultConfig; +/// Active Rollout metadata that is currently used. +@property(nonatomic, readonly, copy) NSArray *activeRolloutMetadata; + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer; +- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager NS_DESIGNATED_INITIALIZER; + +/// Returns true if initialization succeeded. +- (BOOL)initializationSuccessful; + +/// Update config content from fetch response in JSON format. +- (void)updateConfigContentWithResponse:(NSDictionary *)response + forNamespace:(NSString *)FIRNamespace; + +/// Copy from a given dictionary to one of the data source. +/// @param fromDictionary The data to copy from. +/// @param source The data source to copy to(pending/active/default). +- (void)copyFromDictionary:(NSDictionary *)fromDictionary + toSource:(RCNDBSource)source + forNamespace:(NSString *)FIRNamespace; + +/// Sets the fetched Personalization metadata to active. +- (void)activatePersonalization; + +/// Gets the active config and Personalization metadata. +- (NSDictionary *)getConfigAndMetadataForNamespace:(NSString *)FIRNamespace; + +/// Sets the fetched rollout metadata to active with a success completion handler. +- (void)activateRolloutMetadata:(void (^)(BOOL success))completionHandler; + +/// Returns the updated parameters between fetched and active config. +- (FIRRemoteConfigUpdate *)getConfigUpdateForNamespace:(NSString *)FIRNamespace; + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m new file mode 100644 index 0000000..bbc572d --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigContent.m @@ -0,0 +1,526 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h" + +#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h" +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +@implementation RCNConfigContent { + /// Active config data that is currently used. + NSMutableDictionary *_activeConfig; + /// Pending config (aka Fetched config) data that is latest data from server that might or might + /// not be applied. + NSMutableDictionary *_fetchedConfig; + /// Default config provided by user. + NSMutableDictionary *_defaultConfig; + /// Active Personalization metadata that is currently used. + NSDictionary *_activePersonalization; + /// Pending Personalization metadata that is latest data from server that might or might not be + /// applied. + NSDictionary *_fetchedPersonalization; + /// Active Rollout metadata that is currently used. + NSArray *_activeRolloutMetadata; + /// Pending Rollout metadata that is latest data from server that might or might not be applied. + NSArray *_fetchedRolloutMetadata; + /// DBManager + RCNConfigDBManager *_DBManager; + /// Current bundle identifier; + NSString *_bundleIdentifier; + /// Blocks all config reads until we have read from the database. This only + /// potentially blocks on the first read. Should be a no-wait for all subsequent reads once we + /// have data read into memory from the database. + dispatch_group_t _dispatch_group; + /// Boolean indicating if initial DB load of fetched,active and default config has succeeded. + BOOL _isConfigLoadFromDBCompleted; + /// Boolean indicating that the load from database has initiated at least once. + BOOL _isDatabaseLoadAlreadyInitiated; +} + +/// Default timeout when waiting to read data from database. +const NSTimeInterval kDatabaseLoadTimeoutSecs = 30.0; + +/// Singleton instance of RCNConfigContent. ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static RCNConfigContent *sharedInstance; + dispatch_once(&onceToken, ^{ + sharedInstance = + [[RCNConfigContent alloc] initWithDBManager:[RCNConfigDBManager sharedInstance]]; + }); + return sharedInstance; +} + +- (instancetype)init { + NSAssert(NO, @"Invalid initializer."); + return nil; +} + +/// Designated initializer +- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager { + self = [super init]; + if (self) { + _activeConfig = [[NSMutableDictionary alloc] init]; + _fetchedConfig = [[NSMutableDictionary alloc] init]; + _defaultConfig = [[NSMutableDictionary alloc] init]; + _activePersonalization = [[NSDictionary alloc] init]; + _fetchedPersonalization = [[NSDictionary alloc] init]; + _activeRolloutMetadata = [[NSArray alloc] init]; + _fetchedRolloutMetadata = [[NSArray alloc] init]; + _bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + if (!_bundleIdentifier) { + FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000038", + @"Main bundle identifier is missing. Remote Config might not work properly."); + _bundleIdentifier = @""; + } + _DBManager = DBManager; + // Waits for both config and Personalization data to load. + _dispatch_group = dispatch_group_create(); + [self loadConfigFromMainTable]; + } + return self; +} + +// Blocking call that returns true/false once database load completes / times out. +// @return Initialization status. +- (BOOL)initializationSuccessful { + RCN_MUST_NOT_BE_MAIN_THREAD(); + BOOL isDatabaseLoadSuccessful = [self checkAndWaitForInitialDatabaseLoad]; + return isDatabaseLoadSuccessful; +} + +#pragma mark - database + +/// This method is only meant to be called at init time. The underlying logic will need to be +/// reevaluated if the assumption changes at a later time. +- (void)loadConfigFromMainTable { + if (!_DBManager) { + return; + } + + NSAssert(!_isDatabaseLoadAlreadyInitiated, @"Database load has already been initiated"); + _isDatabaseLoadAlreadyInitiated = true; + + dispatch_group_enter(_dispatch_group); + [_DBManager loadMainWithBundleIdentifier:_bundleIdentifier + completionHandler:^( + BOOL success, NSDictionary *fetchedConfig, NSDictionary *activeConfig, + NSDictionary *defaultConfig, NSDictionary *rolloutMetadata) { + self->_fetchedConfig = [fetchedConfig mutableCopy]; + self->_activeConfig = [activeConfig mutableCopy]; + self->_defaultConfig = [defaultConfig mutableCopy]; + self->_fetchedRolloutMetadata = + [rolloutMetadata[@RCNRolloutTableKeyFetchedMetadata] copy]; + self->_activeRolloutMetadata = + [rolloutMetadata[@RCNRolloutTableKeyActiveMetadata] copy]; + dispatch_group_leave(self->_dispatch_group); + }]; + + // TODO(karenzeng): Refactor personalization to be returned in loadMainWithBundleIdentifier above + dispatch_group_enter(_dispatch_group); + [_DBManager + loadPersonalizationWithCompletionHandler:^( + BOOL success, NSDictionary *fetchedPersonalization, NSDictionary *activePersonalization, + NSDictionary *defaultConfig, NSDictionary *rolloutMetadata) { + self->_fetchedPersonalization = [fetchedPersonalization copy]; + self->_activePersonalization = [activePersonalization copy]; + dispatch_group_leave(self->_dispatch_group); + }]; +} + +/// Update the current config result to main table. +/// @param values Values in a row to write to the table. +/// @param source The source the config data is coming from. It determines which table to write to. +- (void)updateMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)source { + [_DBManager insertMainTableWithValues:values fromSource:source completionHandler:nil]; +} + +#pragma mark - update +/// This function is for copying dictionary when user set up a default config or when user clicks +/// activate. For now the DBSource can only be Active or Default. +- (void)copyFromDictionary:(NSDictionary *)fromDict + toSource:(RCNDBSource)DBSource + forNamespace:(NSString *)FIRNamespace { + // Make sure database load has completed. + [self checkAndWaitForInitialDatabaseLoad]; + NSMutableDictionary *toDict; + if (!fromDict) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000007", + @"The source dictionary to copy from does not exist."); + return; + } + FIRRemoteConfigSource source = FIRRemoteConfigSourceRemote; + switch (DBSource) { + case RCNDBSourceDefault: + toDict = _defaultConfig; + source = FIRRemoteConfigSourceDefault; + break; + case RCNDBSourceFetched: + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000008", + @"This shouldn't happen. Destination dictionary should never be pending type."); + return; + case RCNDBSourceActive: + toDict = _activeConfig; + source = FIRRemoteConfigSourceRemote; + [toDict removeObjectForKey:FIRNamespace]; + break; + default: + toDict = _activeConfig; + source = FIRRemoteConfigSourceRemote; + [toDict removeObjectForKey:FIRNamespace]; + break; + } + + // Completely wipe out DB first. + [_DBManager deleteRecordFromMainTableWithNamespace:FIRNamespace + bundleIdentifier:_bundleIdentifier + fromSource:DBSource]; + + toDict[FIRNamespace] = [[NSMutableDictionary alloc] init]; + NSDictionary *config = fromDict[FIRNamespace]; + for (NSString *key in config) { + if (DBSource == FIRRemoteConfigSourceDefault) { + NSObject *value = config[key]; + NSData *valueData; + if ([value isKindOfClass:[NSData class]]) { + valueData = (NSData *)value; + } else if ([value isKindOfClass:[NSString class]]) { + valueData = [(NSString *)value dataUsingEncoding:NSUTF8StringEncoding]; + } else if ([value isKindOfClass:[NSNumber class]]) { + NSString *strValue = [(NSNumber *)value stringValue]; + valueData = [(NSString *)strValue dataUsingEncoding:NSUTF8StringEncoding]; + } else if ([value isKindOfClass:[NSDate class]]) { + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; + NSString *strValue = [dateFormatter stringFromDate:(NSDate *)value]; + valueData = [(NSString *)strValue dataUsingEncoding:NSUTF8StringEncoding]; + } else if ([value isKindOfClass:[NSArray class]]) { + NSError *error; + valueData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error]; + if (error) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000076", @"Invalid array value for key '%@'", + key); + } + } else if ([value isKindOfClass:[NSDictionary class]]) { + NSError *error; + valueData = [NSJSONSerialization dataWithJSONObject:value options:0 error:&error]; + if (error) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000077", + @"Invalid dictionary value for key '%@'", key); + } + } else { + continue; + } + toDict[FIRNamespace][key] = [[FIRRemoteConfigValue alloc] initWithData:valueData + source:source]; + NSArray *values = @[ _bundleIdentifier, FIRNamespace, key, valueData ]; + [self updateMainTableWithValues:values fromSource:DBSource]; + } else { + FIRRemoteConfigValue *value = config[key]; + toDict[FIRNamespace][key] = [[FIRRemoteConfigValue alloc] initWithData:value.dataValue + source:source]; + NSArray *values = @[ _bundleIdentifier, FIRNamespace, key, value.dataValue ]; + [self updateMainTableWithValues:values fromSource:DBSource]; + } + } +} + +- (void)updateConfigContentWithResponse:(NSDictionary *)response + forNamespace:(NSString *)currentNamespace { + // Make sure database load has completed. + [self checkAndWaitForInitialDatabaseLoad]; + NSString *state = response[RCNFetchResponseKeyState]; + + if (!state) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000049", @"State field in fetch response is nil."); + return; + } + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000059", + @"Updating config content from Response for namespace:%@ with state: %@", + currentNamespace, response[RCNFetchResponseKeyState]); + + if ([state isEqualToString:RCNFetchResponseKeyStateNoChange]) { + [self handleNoChangeStateForConfigNamespace:currentNamespace]; + return; + } + + /// Handle empty config state + if ([state isEqualToString:RCNFetchResponseKeyStateEmptyConfig]) { + [self handleEmptyConfigStateForConfigNamespace:currentNamespace]; + return; + } + + /// Handle no template state. + if ([state isEqualToString:RCNFetchResponseKeyStateNoTemplate]) { + [self handleNoTemplateStateForConfigNamespace:currentNamespace]; + return; + } + + /// Handle update state + if ([state isEqualToString:RCNFetchResponseKeyStateUpdate]) { + [self handleUpdateStateForConfigNamespace:currentNamespace + withEntries:response[RCNFetchResponseKeyEntries]]; + [self handleUpdatePersonalization:response[RCNFetchResponseKeyPersonalizationMetadata]]; + [self handleUpdateRolloutFetchedMetadata:response[RCNFetchResponseKeyRolloutMetadata]]; + return; + } +} + +- (void)activatePersonalization { + _activePersonalization = _fetchedPersonalization; + [_DBManager insertOrUpdatePersonalizationConfig:_activePersonalization + fromSource:RCNDBSourceActive]; +} + +- (void)activateRolloutMetadata:(void (^)(BOOL success))completionHandler { + _activeRolloutMetadata = _fetchedRolloutMetadata; + [_DBManager insertOrUpdateRolloutTableWithKey:@RCNRolloutTableKeyActiveMetadata + value:_activeRolloutMetadata + completionHandler:^(BOOL success, NSDictionary *result) { + completionHandler(success); + }]; +} + +#pragma mark State handling +- (void)handleNoChangeStateForConfigNamespace:(NSString *)currentNamespace { + if (!_fetchedConfig[currentNamespace]) { + _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init]; + } +} + +- (void)handleEmptyConfigStateForConfigNamespace:(NSString *)currentNamespace { + if (_fetchedConfig[currentNamespace]) { + [_fetchedConfig[currentNamespace] removeAllObjects]; + } else { + // If namespace has empty status and it doesn't exist in _fetchedConfig, we will + // still add an entry for that namespace. Even if it will not be persisted in database. + // TODO: Add generics for all collection types. + _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init]; + } + [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace + bundleIdentifier:_bundleIdentifier + fromSource:RCNDBSourceFetched]; +} + +- (void)handleNoTemplateStateForConfigNamespace:(NSString *)currentNamespace { + // Remove the namespace. + [_fetchedConfig removeObjectForKey:currentNamespace]; + [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace + bundleIdentifier:_bundleIdentifier + fromSource:RCNDBSourceFetched]; +} +- (void)handleUpdateStateForConfigNamespace:(NSString *)currentNamespace + withEntries:(NSDictionary *)entries { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000058", @"Update config in DB for namespace:%@", + currentNamespace); + // Clear before updating + [_DBManager deleteRecordFromMainTableWithNamespace:currentNamespace + bundleIdentifier:_bundleIdentifier + fromSource:RCNDBSourceFetched]; + if ([_fetchedConfig objectForKey:currentNamespace]) { + [_fetchedConfig[currentNamespace] removeAllObjects]; + } else { + _fetchedConfig[currentNamespace] = [[NSMutableDictionary alloc] init]; + } + + // Store the fetched config values. + for (NSString *key in entries) { + NSData *valueData = [entries[key] dataUsingEncoding:NSUTF8StringEncoding]; + if (!valueData) { + continue; + } + _fetchedConfig[currentNamespace][key] = + [[FIRRemoteConfigValue alloc] initWithData:valueData source:FIRRemoteConfigSourceRemote]; + NSArray *values = @[ _bundleIdentifier, currentNamespace, key, valueData ]; + [self updateMainTableWithValues:values fromSource:RCNDBSourceFetched]; + } +} + +- (void)handleUpdatePersonalization:(NSDictionary *)metadata { + if (!metadata) { + return; + } + _fetchedPersonalization = metadata; + [_DBManager insertOrUpdatePersonalizationConfig:metadata fromSource:RCNDBSourceFetched]; +} + +- (void)handleUpdateRolloutFetchedMetadata:(NSArray *)metadata { + if (!metadata) { + metadata = [[NSArray alloc] init]; + } + _fetchedRolloutMetadata = metadata; + [_DBManager insertOrUpdateRolloutTableWithKey:@RCNRolloutTableKeyFetchedMetadata + value:metadata + completionHandler:nil]; +} + +#pragma mark - getter/setter +- (NSDictionary *)fetchedConfig { + /// If this is the first time reading the fetchedConfig, we might still be reading it from the + /// database. + [self checkAndWaitForInitialDatabaseLoad]; + return _fetchedConfig; +} + +- (NSDictionary *)activeConfig { + /// If this is the first time reading the activeConfig, we might still be reading it from the + /// database. + [self checkAndWaitForInitialDatabaseLoad]; + return _activeConfig; +} + +- (NSDictionary *)defaultConfig { + /// If this is the first time reading the fetchedConfig, we might still be reading it from the + /// database. + [self checkAndWaitForInitialDatabaseLoad]; + return _defaultConfig; +} + +- (NSDictionary *)activePersonalization { + [self checkAndWaitForInitialDatabaseLoad]; + return _activePersonalization; +} + +- (NSArray *)activeRolloutMetadata { + [self checkAndWaitForInitialDatabaseLoad]; + return _activeRolloutMetadata; +} + +- (NSDictionary *)getConfigAndMetadataForNamespace:(NSString *)FIRNamespace { + /// If this is the first time reading the active metadata, we might still be reading it from the + /// database. + [self checkAndWaitForInitialDatabaseLoad]; + return @{ + RCNFetchResponseKeyEntries : _activeConfig[FIRNamespace], + RCNFetchResponseKeyPersonalizationMetadata : _activePersonalization + }; +} + +/// We load the database async at init time. Block all further calls to active/fetched/default +/// configs until load is done. +/// @return Database load completion status. +- (BOOL)checkAndWaitForInitialDatabaseLoad { + /// Wait until load is done. This should be a no-op for subsequent calls. + if (!_isConfigLoadFromDBCompleted) { + intptr_t isErrorOrTimeout = dispatch_group_wait( + _dispatch_group, + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(kDatabaseLoadTimeoutSecs * NSEC_PER_SEC))); + if (isErrorOrTimeout) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000048", + @"Timed out waiting for fetched config to be loaded from DB"); + return false; + } + _isConfigLoadFromDBCompleted = true; + } + return true; +} + +// Compare fetched config with active config and output what has changed +- (FIRRemoteConfigUpdate *)getConfigUpdateForNamespace:(NSString *)FIRNamespace { + // TODO: handle diff in experiment metadata + + FIRRemoteConfigUpdate *configUpdate; + NSMutableSet *updatedKeys = [[NSMutableSet alloc] init]; + + NSDictionary *fetchedConfig = + _fetchedConfig[FIRNamespace] ? _fetchedConfig[FIRNamespace] : [[NSDictionary alloc] init]; + NSDictionary *activeConfig = + _activeConfig[FIRNamespace] ? _activeConfig[FIRNamespace] : [[NSDictionary alloc] init]; + NSDictionary *fetchedP13n = _fetchedPersonalization; + NSDictionary *activeP13n = _activePersonalization; + NSArray *fetchedRolloutMetadata = _fetchedRolloutMetadata; + NSArray *activeRolloutMetadata = _activeRolloutMetadata; + + // add new/updated params + for (NSString *key in [fetchedConfig allKeys]) { + if (activeConfig[key] == nil || + ![[activeConfig[key] stringValue] isEqualToString:[fetchedConfig[key] stringValue]]) { + [updatedKeys addObject:key]; + } + } + // add deleted params + for (NSString *key in [activeConfig allKeys]) { + if (fetchedConfig[key] == nil) { + [updatedKeys addObject:key]; + } + } + + // add params with new/updated p13n metadata + for (NSString *key in [fetchedP13n allKeys]) { + if (activeP13n[key] == nil || ![activeP13n[key] isEqualToDictionary:fetchedP13n[key]]) { + [updatedKeys addObject:key]; + } + } + // add params with deleted p13n metadata + for (NSString *key in [activeP13n allKeys]) { + if (fetchedP13n[key] == nil) { + [updatedKeys addObject:key]; + } + } + + NSDictionary *fetchedRollouts = + [self getParameterKeyToRolloutMetadata:fetchedRolloutMetadata]; + NSDictionary *activeRollouts = + [self getParameterKeyToRolloutMetadata:activeRolloutMetadata]; + + // add params with new/updated rollout metadata + for (NSString *key in [fetchedRollouts allKeys]) { + if (activeRollouts[key] == nil || + ![activeRollouts[key] isEqualToDictionary:fetchedRollouts[key]]) { + [updatedKeys addObject:key]; + } + } + // add params with deleted rollout metadata + for (NSString *key in [activeRollouts allKeys]) { + if (fetchedRollouts[key] == nil) { + [updatedKeys addObject:key]; + } + } + + configUpdate = [[FIRRemoteConfigUpdate alloc] initWithUpdatedKeys:updatedKeys]; + return configUpdate; +} + +- (NSDictionary *)getParameterKeyToRolloutMetadata: + (NSArray *)rolloutMetadata { + NSMutableDictionary *result = + [[NSMutableDictionary alloc] init]; + for (NSDictionary *metadata in rolloutMetadata) { + NSString *rolloutId = metadata[RCNFetchResponseKeyRolloutID]; + NSString *variantId = metadata[RCNFetchResponseKeyVariantID]; + NSArray *affectedKeys = metadata[RCNFetchResponseKeyAffectedParameterKeys]; + if (rolloutId && variantId && affectedKeys) { + for (NSString *key in affectedKeys) { + if (result[key]) { + NSMutableDictionary *rolloutIdToVariantId = result[key]; + [rolloutIdToVariantId setValue:variantId forKey:rolloutId]; + } else { + NSMutableDictionary *rolloutIdToVariantId = [@{rolloutId : variantId} mutableCopy]; + [result setValue:rolloutIdToVariantId forKey:key]; + } + } + } + } + return [result copy]; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h new file mode 100644 index 0000000..97ca03a --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.h @@ -0,0 +1,142 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h" + +typedef NS_ENUM(NSInteger, RCNUpdateOption) { + RCNUpdateOptionApplyTime, + RCNUpdateOptionDefaultTime, + RCNUpdateOptionFetchStatus, +}; + +/// Column names in metadata table +static NSString *const RCNKeyBundleIdentifier = @"bundle_identifier"; +static NSString *const RCNKeyNamespace = @"namespace"; +static NSString *const RCNKeyFetchTime = @"fetch_time"; +static NSString *const RCNKeyDigestPerNamespace = @"digest_per_ns"; +static NSString *const RCNKeyDeviceContext = @"device_context"; +static NSString *const RCNKeyAppContext = @"app_context"; +static NSString *const RCNKeySuccessFetchTime = @"success_fetch_time"; +static NSString *const RCNKeyFailureFetchTime = @"failure_fetch_time"; +static NSString *const RCNKeyLastFetchStatus = @"last_fetch_status"; +static NSString *const RCNKeyLastFetchError = @"last_fetch_error"; +static NSString *const RCNKeyLastApplyTime = @"last_apply_time"; +static NSString *const RCNKeyLastSetDefaultsTime = @"last_set_defaults_time"; + +/// Persist config data in sqlite database on device. Managing data read/write from/to database. +@interface RCNConfigDBManager : NSObject +/// Shared Singleton Instance ++ (instancetype)sharedInstance; + +/// Database Operation Completion callback. +/// @param success Decide whether the DB operation succeeds. +/// @param result Return operation result data. +typedef void (^RCNDBCompletion)(BOOL success, NSDictionary *result); + +/// Database Load Operation Completion callback. +/// @param success Decide whether the DB operation succeeds. +/// @param fetchedConfig Return fetchedConfig loaded from DB +/// @param activeConfig Return activeConfig loaded from DB +/// @param defaultConfig Return defaultConfig loaded from DB +/// @param rolloutMetadata Return fetched and active RolloutMetadata loaded from DB +typedef void (^RCNDBLoadCompletion)(BOOL success, + NSDictionary *fetchedConfig, + NSDictionary *activeConfig, + NSDictionary *defaultConfig, + NSDictionary *rolloutMetadata); + +/// Returns the current version of the Remote Config database. ++ (NSString *)remoteConfigPathForDatabase; + +/// Load config content from main table to cached memory during app start. +- (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier + completionHandler:(RCNDBLoadCompletion)handler; +/// Load config settings for a given namespace from metadata table to cached memory during app +/// start. Config settings include success/failure fetch times, device contenxt, app context, etc. +- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier + namespace:(NSString *)namespace; +/// Load internal metadata from internal metadata table, such as customized HTTP connection/read +/// timeout, throttling time interval and number limit of throttling, etc. +/// This call needs to be blocking to ensure throttling works during apps starts. +- (NSDictionary *)loadInternalMetadataTable; +/// Load experiment from experiment table. +/// @param handler The callback when reading from DB is complete. +- (void)loadExperimentWithCompletionHandler:(RCNDBCompletion)handler; +/// Load Personalization from table. +/// @param handler The callback when reading from DB is complete. +- (void)loadPersonalizationWithCompletionHandler:(RCNDBLoadCompletion)handler; +/// Insert a record in metadata table. +/// @param columnNameToValue The column name and its value to be inserted in metadata table. +/// @param handler The callback. +- (void)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue + completionHandler:(RCNDBCompletion)handler; +/// Insert a record in main table. +/// @param values Values to be inserted. +- (void)insertMainTableWithValues:(NSArray *)values + fromSource:(RCNDBSource)source + completionHandler:(RCNDBCompletion)handler; +/// Insert a record in internal metadata table. +/// @param values Values to be inserted. +- (void)insertInternalMetadataTableWithValues:(NSArray *)values + completionHandler:(RCNDBCompletion)handler; +/// Insert experiment data in experiment table. +/// @param key The key of experiment data belongs to, which are defined in +/// RCNConfigDefines.h. +/// @param value The value that experiment. +/// @param handler The callback. +- (void)insertExperimentTableWithKey:(NSString *)key + value:(NSData *)value + completionHandler:(RCNDBCompletion)handler; + +- (void)updateMetadataWithOption:(RCNUpdateOption)option + namespace:(NSString *)namespace + values:(NSArray *)values + completionHandler:(RCNDBCompletion)handler; + +/// Insert or update the data in Personalization config. +- (BOOL)insertOrUpdatePersonalizationConfig:(NSDictionary *)metadata fromSource:(RCNDBSource)source; + +/// Insert rollout metadata in rollout table. +/// @param key Key indicating whether rollout metadata is fetched or active and defined in +/// RCNConfigDefines.h. +/// @param metadataList The metadata info for each rollout entry . +/// @param handler The callback. +- (void)insertOrUpdateRolloutTableWithKey:(NSString *)key + value:(NSArray *)metadataList + completionHandler:(RCNDBCompletion)handler; + +/// Clear the record of given namespace and package name +/// before updating the table. +- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p + bundleIdentifier:(NSString *)bundleIdentifier + fromSource:(RCNDBSource)source; +/// Remove all the records of given package name and namespace from metadata/internal metadata DB +/// before updating new values from response. +- (void)deleteRecordWithBundleIdentifier:(NSString *)bundlerIdentifier + namespace:(NSString *)namespace + isInternalDB:(BOOL)isInternalDB; +/// Remove all the records from a config content table. +- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source; + +/// Remove all the records from experiment table with given key. +/// @param key The key of experiment data belongs to, which are defined in RCNConfigDefines.h. +- (void)deleteExperimentTableForKey:(NSString *)key; + +/// Returns true if this a new install of the Config database. +- (BOOL)isNewDatabase; +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m new file mode 100644 index 0000000..57ee025 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDBManager.m @@ -0,0 +1,1305 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" + +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +/// Using macro for securely preprocessing string concatenation in query before runtime. +#define RCNTableNameMain "main" +#define RCNTableNameMainActive "main_active" +#define RCNTableNameMainDefault "main_default" +#define RCNTableNameMetadataDeprecated "fetch_metadata" +#define RCNTableNameMetadata "fetch_metadata_v2" +#define RCNTableNameInternalMetadata "internal_metadata" +#define RCNTableNameExperiment "experiment" +#define RCNTableNamePersonalization "personalization" +#define RCNTableNameRollout "rollout" + +static BOOL gIsNewDatabase; +/// SQLite file name in versions 0, 1 and 2. +static NSString *const RCNDatabaseName = @"RemoteConfig.sqlite3"; +/// The storage sub-directory that the Remote Config database resides in. +static NSString *const RCNRemoteConfigStorageSubDirectory = @"Google/RemoteConfig"; + +/// Remote Config database path for deprecated V0 version. +static NSString *RemoteConfigPathForOldDatabaseV0(void) { + NSArray *dirPaths = + NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); + NSString *docPath = dirPaths.firstObject; + return [docPath stringByAppendingPathComponent:RCNDatabaseName]; +} + +/// Remote Config database path for current database. +static NSString *RemoteConfigPathForDatabase(void) { +#if TARGET_OS_TV + NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + NSArray *dirPaths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif + NSString *storageDirPath = dirPaths.firstObject; + NSArray *components = @[ storageDirPath, RCNRemoteConfigStorageSubDirectory, RCNDatabaseName ]; + return [NSString pathWithComponents:components]; +} + +static BOOL RemoteConfigAddSkipBackupAttributeToItemAtPath(NSString *filePathString) { + NSURL *URL = [NSURL fileURLWithPath:filePathString]; + assert([[NSFileManager defaultManager] fileExistsAtPath:[URL path]]); + + NSError *error = nil; + BOOL success = [URL setResourceValue:[NSNumber numberWithBool:YES] + forKey:NSURLIsExcludedFromBackupKey + error:&error]; + if (!success) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000017", @"Error excluding %@ from backup %@.", + [URL lastPathComponent], error); + } + return success; +} + +static BOOL RemoteConfigCreateFilePathIfNotExist(NSString *filePath) { + if (!filePath || !filePath.length) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000018", + @"Failed to create subdirectory for an empty file path."); + return NO; + } + NSFileManager *fileManager = [NSFileManager defaultManager]; + if (![fileManager fileExistsAtPath:filePath]) { + gIsNewDatabase = YES; + NSError *error; + [fileManager createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:&error]; + if (error) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000019", + @"Failed to create subdirectory for database file: %@.", error); + return NO; + } + } + return YES; +} + +static NSArray *RemoteConfigMetadataTableColumnsInOrder(void) { + return @[ + RCNKeyBundleIdentifier, RCNKeyNamespace, RCNKeyFetchTime, RCNKeyDigestPerNamespace, + RCNKeyDeviceContext, RCNKeyAppContext, RCNKeySuccessFetchTime, RCNKeyFailureFetchTime, + RCNKeyLastFetchStatus, RCNKeyLastFetchError, RCNKeyLastApplyTime, RCNKeyLastSetDefaultsTime + ]; +} + +@interface RCNConfigDBManager () { + /// Database storing all the config information. + sqlite3 *_database; + /// Serial queue for database read/write operations. + dispatch_queue_t _databaseOperationQueue; +} +@end + +@implementation RCNConfigDBManager + ++ (instancetype)sharedInstance { + static dispatch_once_t onceToken; + static RCNConfigDBManager *sharedInstance; + dispatch_once(&onceToken, ^{ + sharedInstance = [[RCNConfigDBManager alloc] init]; + }); + return sharedInstance; +} + +/// Returns the current version of the Remote Config database. ++ (NSString *)remoteConfigPathForDatabase { + return RemoteConfigPathForDatabase(); +} + +- (instancetype)init { + self = [super init]; + if (self) { + _databaseOperationQueue = + dispatch_queue_create("com.google.GoogleConfigService.database", DISPATCH_QUEUE_SERIAL); + [self createOrOpenDatabase]; + } + return self; +} + +#pragma mark - database +- (void)migrateV1NamespaceToV2Namespace { + for (int table = 0; table < 3; table++) { + NSString *tableName = @"" RCNTableNameMain; + switch (table) { + case 1: + tableName = @"" RCNTableNameMainActive; + break; + case 2: + tableName = @"" RCNTableNameMainDefault; + break; + default: + break; + } + NSString *SQLString = [NSString + stringWithFormat:@"SELECT namespace FROM %@ WHERE namespace NOT LIKE '%%:%%'", tableName]; + const char *SQL = [SQLString UTF8String]; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return; + } + NSMutableArray *namespaceArray = [[NSMutableArray alloc] init]; + while (sqlite3_step(statement) == SQLITE_ROW) { + NSString *configNamespace = + [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)]; + [namespaceArray addObject:configNamespace]; + } + sqlite3_finalize(statement); + + // Update. + for (NSString *namespaceToUpdate in namespaceArray) { + NSString *newNamespace = + [NSString stringWithFormat:@"%@:%@", namespaceToUpdate, kFIRDefaultAppName]; + NSString *updateSQLString = + [NSString stringWithFormat:@"UPDATE %@ SET namespace = ? WHERE namespace = ?", tableName]; + const char *updateSQL = [updateSQLString UTF8String]; + sqlite3_stmt *updateStatement = [self prepareSQL:updateSQL]; + if (!updateStatement) { + return; + } + NSArray *updateParams = @[ newNamespace, namespaceToUpdate ]; + [self bindStringsToStatement:updateStatement stringArray:updateParams]; + + int result = sqlite3_step(updateStatement); + if (result != SQLITE_DONE) { + [self logErrorWithSQL:SQL finalizeStatement:updateStatement returnValue:NO]; + return; + } + sqlite3_finalize(updateStatement); + } + } +} + +- (void)createOrOpenDatabase { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSString *oldV0DBPath = RemoteConfigPathForOldDatabaseV0(); + // Backward Compatibility + if ([[NSFileManager defaultManager] fileExistsAtPath:oldV0DBPath]) { + FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000009", + @"Old database V0 exists, removed it and replace with the new one."); + [strongSelf removeDatabase:oldV0DBPath]; + } + NSString *dbPath = [RCNConfigDBManager remoteConfigPathForDatabase]; + FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000062", @"Loading database at path %@", dbPath); + const char *databasePath = dbPath.UTF8String; + + // Create or open database path. + if (!RemoteConfigCreateFilePathIfNotExist(dbPath)) { + return; + } + + int flags = SQLITE_OPEN_CREATE | SQLITE_OPEN_READWRITE | SQLITE_OPEN_FULLMUTEX; +#ifdef SQLITE_OPEN_FILEPROTECTION_COMPLETEUNTILFIRSTUSERAUTHENTICATION + flags |= SQLITE_OPEN_FILEPROTECTION_COMPLETEUNTILFIRSTUSERAUTHENTICATION; +#endif + + if (sqlite3_open_v2(databasePath, &strongSelf->_database, flags, NULL) == SQLITE_OK) { + // Always try to create table if not exists for backward compatibility. + if (![strongSelf createTableSchema]) { + // Remove database before fail. + [strongSelf removeDatabase:dbPath]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000010", @"Failed to create table."); + // Create a new database if existing database file is corrupted. + if (!RemoteConfigCreateFilePathIfNotExist(dbPath)) { + return; + } + if (sqlite3_open_v2(databasePath, &strongSelf->_database, flags, NULL) == SQLITE_OK) { + if (![strongSelf createTableSchema]) { + // Remove database before fail. + [strongSelf removeDatabase:dbPath]; + // If it failed again, there's nothing we can do here. + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000010", @"Failed to create table."); + } else { + // Exclude the app data used from iCloud backup. + RemoteConfigAddSkipBackupAttributeToItemAtPath(dbPath); + } + } else { + [strongSelf logDatabaseError]; + } + } else { + // DB file already exists. Migrate any V1 namespace column entries to V2 fully qualified + // 'namespace:FIRApp' entries. + [self migrateV1NamespaceToV2Namespace]; + // Exclude the app data used from iCloud backup. + RemoteConfigAddSkipBackupAttributeToItemAtPath(dbPath); + } + } else { + [strongSelf logDatabaseError]; + } + }); +} + +- (BOOL)createTableSchema { + RCN_MUST_NOT_BE_MAIN_THREAD(); + static const char *createTableMain = + "create TABLE IF NOT EXISTS " RCNTableNameMain + " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)"; + + static const char *createTableMainActive = + "create TABLE IF NOT EXISTS " RCNTableNameMainActive + " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)"; + + static const char *createTableMainDefault = + "create TABLE IF NOT EXISTS " RCNTableNameMainDefault + " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT, key TEXT, value BLOB)"; + + static const char *createTableMetadata = + "create TABLE IF NOT EXISTS " RCNTableNameMetadata + " (_id INTEGER PRIMARY KEY, bundle_identifier TEXT, namespace TEXT," + " fetch_time INTEGER, digest_per_ns BLOB, device_context BLOB, app_context BLOB, " + "success_fetch_time BLOB, failure_fetch_time BLOB, last_fetch_status INTEGER, " + "last_fetch_error INTEGER, last_apply_time INTEGER, last_set_defaults_time INTEGER)"; + + static const char *createTableInternalMetadata = + "create TABLE IF NOT EXISTS " RCNTableNameInternalMetadata + " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)"; + + static const char *createTableExperiment = "create TABLE IF NOT EXISTS " RCNTableNameExperiment + " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)"; + static const char *createTablePersonalization = + "create TABLE IF NOT EXISTS " RCNTableNamePersonalization + " (_id INTEGER PRIMARY KEY, key INTEGER, value BLOB)"; + + static const char *createTableRollout = "create TABLE IF NOT EXISTS " RCNTableNameRollout + " (_id INTEGER PRIMARY KEY, key TEXT, value BLOB)"; + + return [self executeQuery:createTableMain] && [self executeQuery:createTableMainActive] && + [self executeQuery:createTableMainDefault] && [self executeQuery:createTableMetadata] && + [self executeQuery:createTableInternalMetadata] && + [self executeQuery:createTableExperiment] && + [self executeQuery:createTablePersonalization] && [self executeQuery:createTableRollout]; +} + +- (void)removeDatabaseOnDatabaseQueueAtPath:(NSString *)path { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_sync(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + if (sqlite3_close(strongSelf->_database) != SQLITE_OK) { + [self logDatabaseError]; + } + strongSelf->_database = nil; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + if (![fileManager removeItemAtPath:path error:&error]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011", + @"Failed to remove database at path %@ for error %@.", path, error); + } + }); +} + +- (void)removeDatabase:(NSString *)path { + if (sqlite3_close(_database) != SQLITE_OK) { + [self logDatabaseError]; + } + _database = nil; + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + if (![fileManager removeItemAtPath:path error:&error]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011", + @"Failed to remove database at path %@ for error %@.", path, error); + } +} + +#pragma mark - execute +- (BOOL)executeQuery:(const char *)SQL { + RCN_MUST_NOT_BE_MAIN_THREAD(); + char *error; + if (sqlite3_exec(_database, SQL, nil, nil, &error) != SQLITE_OK) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000012", @"Failed to execute query with error %s.", + error); + return NO; + } + return YES; +} + +#pragma mark - insert +- (void)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue + completionHandler:(RCNDBCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [weakSelf insertMetadataTableWithValues:columnNameToValue]; + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)insertMetadataTableWithValues:(NSDictionary *)columnNameToValue { + RCN_MUST_NOT_BE_MAIN_THREAD(); + static const char *SQL = + "INSERT INTO " RCNTableNameMetadata + " (bundle_identifier, namespace, fetch_time, digest_per_ns, device_context, " + "app_context, success_fetch_time, failure_fetch_time, last_fetch_status, " + "last_fetch_error, last_apply_time, last_set_defaults_time) values (?, ?, ?, ?, ?, ?, " + "?, ?, ?, ?, ?, ?)"; + + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + [self logErrorWithSQL:SQL finalizeStatement:nil returnValue:NO]; + return NO; + } + + NSArray *columns = RemoteConfigMetadataTableColumnsInOrder(); + int index = 0; + for (NSString *columnName in columns) { + if ([columnName isEqualToString:RCNKeyBundleIdentifier] || + [columnName isEqualToString:RCNKeyNamespace]) { + NSString *value = columnNameToValue[columnName]; + if (![self bindStringToStatement:statement index:++index string:value]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } else if ([columnName isEqualToString:RCNKeyFetchTime] || + [columnName isEqualToString:RCNKeyLastApplyTime] || + [columnName isEqualToString:RCNKeyLastSetDefaultsTime]) { + double value = [columnNameToValue[columnName] doubleValue]; + if (sqlite3_bind_double(statement, ++index, value) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } else if ([columnName isEqualToString:RCNKeyLastFetchStatus] || + [columnName isEqualToString:RCNKeyLastFetchError]) { + int value = [columnNameToValue[columnName] intValue]; + if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } else { + NSData *data = columnNameToValue[columnName]; + if (sqlite3_bind_blob(statement, ++index, data.bytes, (int)data.length, NULL) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } + } + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +- (void)insertMainTableWithValues:(NSArray *)values + fromSource:(RCNDBSource)source + completionHandler:(RCNDBCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [weakSelf insertMainTableWithValues:values fromSource:source]; + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)insertMainTableWithValues:(NSArray *)values fromSource:(RCNDBSource)source { + RCN_MUST_NOT_BE_MAIN_THREAD(); + if (values.count != 4) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000013", + @"Failed to insert config record. Wrong number of give parameters, current " + @"number is %ld, correct number is 4.", + (long)values.count); + return NO; + } + const char *SQL = "INSERT INTO " RCNTableNameMain + " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)"; + if (source == RCNDBSourceDefault) { + SQL = "INSERT INTO " RCNTableNameMainDefault + " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)"; + } else if (source == RCNDBSourceActive) { + SQL = "INSERT INTO " RCNTableNameMainActive + " (bundle_identifier, namespace, key, value) values (?, ?, ?, ?)"; + } + + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + NSString *aString = values[0]; + if (![self bindStringToStatement:statement index:1 string:aString]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + aString = values[1]; + if (![self bindStringToStatement:statement index:2 string:aString]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + aString = values[2]; + if (![self bindStringToStatement:statement index:3 string:aString]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + NSData *blobData = values[3]; + if (sqlite3_bind_blob(statement, 4, blobData.bytes, (int)blobData.length, NULL) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +- (void)insertInternalMetadataTableWithValues:(NSArray *)values + completionHandler:(RCNDBCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [weakSelf insertInternalMetadataWithValues:values]; + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)insertInternalMetadataWithValues:(NSArray *)values { + RCN_MUST_NOT_BE_MAIN_THREAD(); + if (values.count != 2) { + return NO; + } + const char *SQL = + "INSERT OR REPLACE INTO " RCNTableNameInternalMetadata " (key, value) values (?, ?)"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + NSString *aString = values[0]; + if (![self bindStringToStatement:statement index:1 string:aString]) { + [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + return NO; + } + NSData *blobData = values[1]; + if (sqlite3_bind_blob(statement, 2, blobData.bytes, (int)blobData.length, NULL) != SQLITE_OK) { + [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + return NO; + } + if (sqlite3_step(statement) != SQLITE_DONE) { + [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + return NO; + } + sqlite3_finalize(statement); + return YES; +} + +- (void)insertExperimentTableWithKey:(NSString *)key + value:(NSData *)serializedValue + completionHandler:(RCNDBCompletion)handler { + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [self insertExperimentTableWithKey:key value:serializedValue]; + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)insertExperimentTableWithKey:(NSString *)key value:(NSData *)dataValue { + if ([key isEqualToString:@RCNExperimentTableKeyMetadata]) { + return [self updateExperimentMetadata:dataValue]; + } + + RCN_MUST_NOT_BE_MAIN_THREAD(); + const char *SQL = "INSERT INTO " RCNTableNameExperiment " (key, value) values (?, ?)"; + + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + if (![self bindStringToStatement:statement index:1 string:key]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_bind_blob(statement, 2, dataValue.bytes, (int)dataValue.length, NULL) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +- (BOOL)updateExperimentMetadata:(NSData *)dataValue { + RCN_MUST_NOT_BE_MAIN_THREAD(); + const char *SQL = "INSERT OR REPLACE INTO " RCNTableNameExperiment + " (_id, key, value) values ((SELECT _id from " RCNTableNameExperiment + " WHERE key = ?), ?, ?)"; + + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + if (![self bindStringToStatement:statement index:1 string:@RCNExperimentTableKeyMetadata]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (![self bindStringToStatement:statement index:2 string:@RCNExperimentTableKeyMetadata]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + if (sqlite3_bind_blob(statement, 3, dataValue.bytes, (int)dataValue.length, NULL) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +- (BOOL)insertOrUpdatePersonalizationConfig:(NSDictionary *)dataValue + fromSource:(RCNDBSource)source { + RCN_MUST_NOT_BE_MAIN_THREAD(); + + NSError *error; + NSData *JSONPayload = [NSJSONSerialization dataWithJSONObject:dataValue + options:NSJSONWritingPrettyPrinted + error:&error]; + + if (!JSONPayload || error) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000075", + @"Invalid Personalization payload to be serialized."); + } + + const char *SQL = "INSERT OR REPLACE INTO " RCNTableNamePersonalization + " (_id, key, value) values ((SELECT _id from " RCNTableNamePersonalization + " WHERE key = ?), ?, ?)"; + + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + if (sqlite3_bind_int(statement, 1, (int)source) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_bind_int(statement, 2, (int)source) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + if (sqlite3_bind_blob(statement, 3, JSONPayload.bytes, (int)JSONPayload.length, NULL) != + SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +- (void)insertOrUpdateRolloutTableWithKey:(NSString *)key + value:(NSArray *)metadataList + completionHandler:(RCNDBCompletion)handler { + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [self insertOrUpdateRolloutTableWithKey:key value:metadataList]; + if (handler) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)insertOrUpdateRolloutTableWithKey:(NSString *)key + value:(NSArray *)arrayValue { + RCN_MUST_NOT_BE_MAIN_THREAD(); + NSError *error; + NSData *dataValue = [NSJSONSerialization dataWithJSONObject:arrayValue + options:NSJSONWritingPrettyPrinted + error:&error]; + const char *SQL = + "INSERT OR REPLACE INTO " RCNTableNameRollout + " (_id, key, value) values ((SELECT _id from " RCNTableNameRollout " WHERE key = ?), ?, ?)"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + if (![self bindStringToStatement:statement index:1 string:key]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (![self bindStringToStatement:statement index:2 string:key]) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_bind_blob(statement, 3, dataValue.bytes, (int)dataValue.length, NULL) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +#pragma mark - update + +- (void)updateMetadataWithOption:(RCNUpdateOption)option + namespace:(NSString *)namespace + values:(NSArray *)values + completionHandler:(RCNDBCompletion)handler { + dispatch_async(_databaseOperationQueue, ^{ + BOOL success = [self updateMetadataTableWithOption:option namespace:namespace andValues:values]; + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(success, nil); + }); + } + }); +} + +- (BOOL)updateMetadataTableWithOption:(RCNUpdateOption)option + namespace:(NSString *)namespace + andValues:(NSArray *)values { + RCN_MUST_NOT_BE_MAIN_THREAD(); + static const char *SQL = + "UPDATE " RCNTableNameMetadata " (last_fetch_status, last_fetch_error, last_apply_time, " + "last_set_defaults_time) values (?, ?, ?, ?) WHERE namespace = ?"; + if (option == RCNUpdateOptionFetchStatus) { + SQL = "UPDATE " RCNTableNameMetadata + " SET last_fetch_status = ?, last_fetch_error = ? WHERE namespace = ?"; + } else if (option == RCNUpdateOptionApplyTime) { + SQL = "UPDATE " RCNTableNameMetadata " SET last_apply_time = ? WHERE namespace = ?"; + } else if (option == RCNUpdateOptionDefaultTime) { + SQL = "UPDATE " RCNTableNameMetadata " SET last_set_defaults_time = ? WHERE namespace = ?"; + } else { + return NO; + } + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + int index = 0; + if ((option == RCNUpdateOptionApplyTime || option == RCNUpdateOptionDefaultTime) && + values.count == 1) { + double value = [values[0] doubleValue]; + if (sqlite3_bind_double(statement, ++index, value) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } else if (option == RCNUpdateOptionFetchStatus && values.count == 2) { + int value = [values[0] intValue]; + if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + value = [values[1] intValue]; + if (sqlite3_bind_int(statement, ++index, value) != SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + } + // bind namespace to query + if (sqlite3_bind_text(statement, ++index, [namespace UTF8String], -1, SQLITE_TRANSIENT) != + SQLITE_OK) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} +#pragma mark - read from DB + +- (NSDictionary *)loadMetadataWithBundleIdentifier:(NSString *)bundleIdentifier + namespace:(NSString *)namespace { + __block NSDictionary *metadataTableResult; + __weak RCNConfigDBManager *weakSelf = self; + dispatch_sync(_databaseOperationQueue, ^{ + metadataTableResult = [weakSelf loadMetadataTableWithBundleIdentifier:bundleIdentifier + namespace:namespace]; + }); + if (metadataTableResult) { + return metadataTableResult; + } + return [[NSDictionary alloc] init]; +} + +- (NSMutableDictionary *)loadMetadataTableWithBundleIdentifier:(NSString *)bundleIdentifier + namespace:(NSString *)namespace { + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + const char *SQL = + "SELECT bundle_identifier, fetch_time, digest_per_ns, device_context, app_context, " + "success_fetch_time, failure_fetch_time , last_fetch_status, " + "last_fetch_error, last_apply_time, last_set_defaults_time FROM " RCNTableNameMetadata + " WHERE bundle_identifier = ? and namespace = ?"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + + NSArray *params = @[ bundleIdentifier, namespace ]; + [self bindStringsToStatement:statement stringArray:params]; + + while (sqlite3_step(statement) == SQLITE_ROW) { + NSString *dbBundleIdentifier = + [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)]; + + if (dbBundleIdentifier && ![dbBundleIdentifier isEqualToString:bundleIdentifier]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000014", + @"Load Metadata from table error: Wrong package name %@, should be %@.", + dbBundleIdentifier, bundleIdentifier); + return nil; + } + + double fetchTime = sqlite3_column_double(statement, 1); + NSData *digestPerNamespace = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 2) + length:sqlite3_column_bytes(statement, 2)]; + NSData *deviceContext = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 3) + length:sqlite3_column_bytes(statement, 3)]; + NSData *appContext = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 4) + length:sqlite3_column_bytes(statement, 4)]; + NSData *successTimeDigest = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 5) + length:sqlite3_column_bytes(statement, 5)]; + NSData *failureTimeDigest = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 6) + length:sqlite3_column_bytes(statement, 6)]; + + int lastFetchStatus = sqlite3_column_int(statement, 7); + int lastFetchFailReason = sqlite3_column_int(statement, 8); + double lastApplyTimestamp = sqlite3_column_double(statement, 9); + double lastSetDefaultsTimestamp = sqlite3_column_double(statement, 10); + + NSError *error; + NSMutableDictionary *deviceContextDict = nil; + if (deviceContext) { + deviceContextDict = [NSJSONSerialization JSONObjectWithData:deviceContext + options:NSJSONReadingMutableContainers + error:&error]; + } + + NSMutableDictionary *appContextDict = nil; + if (appContext) { + appContextDict = [NSJSONSerialization JSONObjectWithData:appContext + options:NSJSONReadingMutableContainers + error:&error]; + } + + NSMutableDictionary *digestPerNamespaceDictionary = nil; + if (digestPerNamespace) { + digestPerNamespaceDictionary = + [NSJSONSerialization JSONObjectWithData:digestPerNamespace + options:NSJSONReadingMutableContainers + error:&error]; + } + + NSMutableArray *successTimes = nil; + if (successTimeDigest) { + successTimes = [NSJSONSerialization JSONObjectWithData:successTimeDigest + options:NSJSONReadingMutableContainers + error:&error]; + } + + NSMutableArray *failureTimes = nil; + if (failureTimeDigest) { + failureTimes = [NSJSONSerialization JSONObjectWithData:failureTimeDigest + options:NSJSONReadingMutableContainers + error:&error]; + } + + dict[RCNKeyBundleIdentifier] = bundleIdentifier; + dict[RCNKeyFetchTime] = @(fetchTime); + dict[RCNKeyDigestPerNamespace] = digestPerNamespaceDictionary; + dict[RCNKeyDeviceContext] = deviceContextDict; + dict[RCNKeyAppContext] = appContextDict; + dict[RCNKeySuccessFetchTime] = successTimes; + dict[RCNKeyFailureFetchTime] = failureTimes; + dict[RCNKeyLastFetchStatus] = @(lastFetchStatus); + dict[RCNKeyLastFetchError] = @(lastFetchFailReason); + dict[RCNKeyLastApplyTime] = @(lastApplyTimestamp); + dict[RCNKeyLastSetDefaultsTime] = @(lastSetDefaultsTimestamp); + + break; + } + sqlite3_finalize(statement); + return dict; +} + +- (void)loadExperimentWithCompletionHandler:(RCNDBCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSMutableArray *experimentPayloads = + [strongSelf loadExperimentTableFromKey:@RCNExperimentTableKeyPayload]; + if (!experimentPayloads) { + experimentPayloads = [[NSMutableArray alloc] init]; + } + + NSMutableDictionary *experimentMetadata; + NSMutableArray *experiments = + [strongSelf loadExperimentTableFromKey:@RCNExperimentTableKeyMetadata]; + // There should be only one entry for experiment metadata. + if (experiments.count > 0) { + NSError *error; + experimentMetadata = [NSJSONSerialization JSONObjectWithData:experiments[0] + options:NSJSONReadingMutableContainers + error:&error]; + } + if (!experimentMetadata) { + experimentMetadata = [[NSMutableDictionary alloc] init]; + } + + /// Load activated experiments payload. + NSMutableArray *activeExperimentPayloads = + [strongSelf loadExperimentTableFromKey:@RCNExperimentTableKeyActivePayload]; + if (!activeExperimentPayloads) { + activeExperimentPayloads = [[NSMutableArray alloc] init]; + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler( + YES, @{ + @RCNExperimentTableKeyPayload : [experimentPayloads copy], + @RCNExperimentTableKeyMetadata : [experimentMetadata copy], + /// Activated experiments only need ExperimentsDescriptions data, which + /// experimentPayloads contains. + @RCNExperimentTableKeyActivePayload : [activeExperimentPayloads copy] + }); + }); + } + }); +} + +- (NSMutableArray *)loadExperimentTableFromKey:(NSString *)key { + RCN_MUST_NOT_BE_MAIN_THREAD(); + + const char *SQL = "SELECT value FROM " RCNTableNameExperiment " WHERE key = ?"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + + NSArray *params = @[ key ]; + [self bindStringsToStatement:statement stringArray:params]; + NSMutableArray *results = [self loadValuesFromStatement:statement]; + return results; +} + +- (NSArray *)loadRolloutTableFromKey:(NSString *)key { + RCN_MUST_NOT_BE_MAIN_THREAD(); + const char *SQL = "SELECT value FROM " RCNTableNameRollout " WHERE key = ?"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + NSArray *params = @[ key ]; + [self bindStringsToStatement:statement stringArray:params]; + NSMutableArray *results = [self loadValuesFromStatement:statement]; + // There should be only one entry in this table. + if (results.count != 1) { + return nil; + } + NSArray *rollout; + // Convert from NSData to NSArray + if (results[0]) { + NSError *error; + rollout = [NSJSONSerialization JSONObjectWithData:results[0] options:0 error:&error]; + if (!rollout) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011", + @"Failed to convert NSData to NSAarry for Rollout Metadata with error %@.", + error); + } + } + if (!rollout) { + rollout = [[NSArray alloc] init]; + } + return rollout; +} + +- (NSMutableArray *)loadValuesFromStatement:(sqlite3_stmt *)statement { + NSMutableArray *results = [[NSMutableArray alloc] init]; + NSData *value; + while (sqlite3_step(statement) == SQLITE_ROW) { + value = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 0) + length:sqlite3_column_bytes(statement, 0)]; + if (value) { + [results addObject:value]; + } + } + + sqlite3_finalize(statement); + return results; +} + +- (void)loadPersonalizationWithCompletionHandler:(RCNDBLoadCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + handler(NO, [NSMutableDictionary new], [NSMutableDictionary new], nil, nil); + }); + return; + } + + NSDictionary *activePersonalization; + NSData *personalizationResult = [strongSelf loadPersonalizationTableFromKey:RCNDBSourceActive]; + // There should be only one entry for Personalization metadata. + if (personalizationResult) { + NSError *error; + activePersonalization = [NSJSONSerialization JSONObjectWithData:personalizationResult + options:0 + error:&error]; + } + if (!activePersonalization) { + activePersonalization = [[NSMutableDictionary alloc] init]; + } + + NSDictionary *fetchedPersonalization; + personalizationResult = [strongSelf loadPersonalizationTableFromKey:RCNDBSourceFetched]; + // There should be only one entry for Personalization metadata. + if (personalizationResult) { + NSError *error; + fetchedPersonalization = [NSJSONSerialization JSONObjectWithData:personalizationResult + options:0 + error:&error]; + } + if (!fetchedPersonalization) { + fetchedPersonalization = [[NSMutableDictionary alloc] init]; + } + + if (handler) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + handler(YES, fetchedPersonalization, activePersonalization, nil, nil); + }); + } + }); +} + +- (NSData *)loadPersonalizationTableFromKey:(int)key { + RCN_MUST_NOT_BE_MAIN_THREAD(); + + NSMutableArray *results = [[NSMutableArray alloc] init]; + const char *SQL = "SELECT value FROM " RCNTableNamePersonalization " WHERE key = ?"; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + + if (sqlite3_bind_int(statement, 1, key) != SQLITE_OK) { + [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + return nil; + } + NSData *personalizationData; + while (sqlite3_step(statement) == SQLITE_ROW) { + personalizationData = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 0) + length:sqlite3_column_bytes(statement, 0)]; + if (personalizationData) { + [results addObject:personalizationData]; + } + } + + sqlite3_finalize(statement); + // There should be only one entry in this table. + if (results.count != 1) { + return nil; + } + return results[0]; +} + +- (NSDictionary *)loadInternalMetadataTable { + __block NSMutableDictionary *internalMetadataTableResult; + __weak RCNConfigDBManager *weakSelf = self; + dispatch_sync(_databaseOperationQueue, ^{ + internalMetadataTableResult = [weakSelf loadInternalMetadataTableInternal]; + }); + return internalMetadataTableResult; +} + +- (NSMutableDictionary *)loadInternalMetadataTableInternal { + NSMutableDictionary *internalMetadata = [[NSMutableDictionary alloc] init]; + const char *SQL = "SELECT key, value FROM " RCNTableNameInternalMetadata; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + + while (sqlite3_step(statement) == SQLITE_ROW) { + NSString *key = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 0)]; + + NSData *dataValue = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 1) + length:sqlite3_column_bytes(statement, 1)]; + internalMetadata[key] = dataValue; + } + sqlite3_finalize(statement); + return internalMetadata; +} + +/// This method is only meant to be called at init time. The underlying logic will need to be +/// reevaluated if the assumption changes at a later time. +- (void)loadMainWithBundleIdentifier:(NSString *)bundleIdentifier + completionHandler:(RCNDBLoadCompletion)handler { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + handler(NO, [NSDictionary new], [NSDictionary new], [NSDictionary new], [NSDictionary new]); + }); + return; + } + __block NSDictionary *fetchedConfig = + [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier + fromSource:RCNDBSourceFetched]; + __block NSDictionary *activeConfig = + [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier + fromSource:RCNDBSourceActive]; + __block NSDictionary *defaultConfig = + [strongSelf loadMainTableWithBundleIdentifier:bundleIdentifier + fromSource:RCNDBSourceDefault]; + + __block NSArray *fetchedRolloutMetadata = + [strongSelf loadRolloutTableFromKey:@RCNRolloutTableKeyFetchedMetadata]; + __block NSArray *activeRolloutMetadata = + [strongSelf loadRolloutTableFromKey:@RCNRolloutTableKeyActiveMetadata]; + + if (handler) { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + fetchedConfig = fetchedConfig ? fetchedConfig : [[NSDictionary alloc] init]; + activeConfig = activeConfig ? activeConfig : [[NSDictionary alloc] init]; + defaultConfig = defaultConfig ? defaultConfig : [[NSDictionary alloc] init]; + fetchedRolloutMetadata = + fetchedRolloutMetadata ? fetchedRolloutMetadata : [[NSArray alloc] init]; + activeRolloutMetadata = + activeRolloutMetadata ? activeRolloutMetadata : [[NSArray alloc] init]; + NSDictionary *rolloutMetadata = @{ + @RCNRolloutTableKeyActiveMetadata : [activeRolloutMetadata copy], + @RCNRolloutTableKeyFetchedMetadata : [fetchedRolloutMetadata copy] + }; + handler(YES, fetchedConfig, activeConfig, defaultConfig, rolloutMetadata); + }); + } + }); +} + +- (NSMutableDictionary *)loadMainTableWithBundleIdentifier:(NSString *)bundleIdentifier + fromSource:(RCNDBSource)source { + NSMutableDictionary *namespaceToConfig = [[NSMutableDictionary alloc] init]; + const char *SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMain + " WHERE bundle_identifier = ?"; + if (source == RCNDBSourceDefault) { + SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMainDefault + " WHERE bundle_identifier = ?"; + } else if (source == RCNDBSourceActive) { + SQL = "SELECT bundle_identifier, namespace, key, value FROM " RCNTableNameMainActive + " WHERE bundle_identifier = ?"; + } + NSArray *params = @[ bundleIdentifier ]; + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return nil; + } + [self bindStringsToStatement:statement stringArray:params]; + + while (sqlite3_step(statement) == SQLITE_ROW) { + NSString *configNamespace = + [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 1)]; + NSString *key = [[NSString alloc] initWithUTF8String:(char *)sqlite3_column_text(statement, 2)]; + NSData *value = [NSData dataWithBytes:(char *)sqlite3_column_blob(statement, 3) + length:sqlite3_column_bytes(statement, 3)]; + if (!namespaceToConfig[configNamespace]) { + namespaceToConfig[configNamespace] = [[NSMutableDictionary alloc] init]; + } + + if (source == RCNDBSourceDefault) { + namespaceToConfig[configNamespace][key] = + [[FIRRemoteConfigValue alloc] initWithData:value source:FIRRemoteConfigSourceDefault]; + } else { + namespaceToConfig[configNamespace][key] = + [[FIRRemoteConfigValue alloc] initWithData:value source:FIRRemoteConfigSourceRemote]; + } + } + sqlite3_finalize(statement); + return namespaceToConfig; +} + +#pragma mark - delete +- (void)deleteRecordFromMainTableWithNamespace:(NSString *)namespace_p + bundleIdentifier:(NSString *)bundleIdentifier + fromSource:(RCNDBSource)source { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSArray *params = @[ bundleIdentifier, namespace_p ]; + const char *SQL = + "DELETE FROM " RCNTableNameMain " WHERE bundle_identifier = ? and namespace = ?"; + if (source == RCNDBSourceDefault) { + SQL = "DELETE FROM " RCNTableNameMainDefault " WHERE bundle_identifier = ? and namespace = ?"; + } else if (source == RCNDBSourceActive) { + SQL = "DELETE FROM " RCNTableNameMainActive " WHERE bundle_identifier = ? and namespace = ?"; + } + [strongSelf executeQuery:SQL withParams:params]; + }); +} + +- (void)deleteRecordWithBundleIdentifier:(NSString *)bundleIdentifier + namespace:(NSString *)namespace + isInternalDB:(BOOL)isInternalDB { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + const char *SQL = "DELETE FROM " RCNTableNameInternalMetadata " WHERE key LIKE ?"; + NSArray *params = @[ bundleIdentifier ]; + if (!isInternalDB) { + SQL = "DELETE FROM " RCNTableNameMetadata " WHERE bundle_identifier = ? and namespace = ?"; + params = @[ bundleIdentifier, namespace ]; + } + [strongSelf executeQuery:SQL withParams:params]; + }); +} + +- (void)deleteAllRecordsFromTableWithSource:(RCNDBSource)source { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + const char *SQL = "DELETE FROM " RCNTableNameMain; + if (source == RCNDBSourceDefault) { + SQL = "DELETE FROM " RCNTableNameMainDefault; + } else if (source == RCNDBSourceActive) { + SQL = "DELETE FROM " RCNTableNameMainActive; + } + [strongSelf executeQuery:SQL]; + }); +} + +- (void)deleteExperimentTableForKey:(NSString *)key { + __weak RCNConfigDBManager *weakSelf = self; + dispatch_async(_databaseOperationQueue, ^{ + RCNConfigDBManager *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + NSArray *params = @[ key ]; + const char *SQL = "DELETE FROM " RCNTableNameExperiment " WHERE key = ?"; + [strongSelf executeQuery:SQL withParams:params]; + }); +} + +#pragma mark - helper +- (BOOL)executeQuery:(const char *)SQL withParams:(NSArray *)params { + RCN_MUST_NOT_BE_MAIN_THREAD(); + sqlite3_stmt *statement = [self prepareSQL:SQL]; + if (!statement) { + return NO; + } + + [self bindStringsToStatement:statement stringArray:params]; + if (sqlite3_step(statement) != SQLITE_DONE) { + return [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + } + sqlite3_finalize(statement); + return YES; +} + +/// Params only accept TEXT format string. +- (BOOL)bindStringsToStatement:(sqlite3_stmt *)statement stringArray:(NSArray *)array { + int index = 1; + for (NSString *param in array) { + if (![self bindStringToStatement:statement index:index string:param]) { + return [self logErrorWithSQL:nil finalizeStatement:statement returnValue:NO]; + } + index++; + } + return YES; +} + +- (BOOL)bindStringToStatement:(sqlite3_stmt *)statement index:(int)index string:(NSString *)value { + if (sqlite3_bind_text(statement, index, [value UTF8String], -1, SQLITE_TRANSIENT) != SQLITE_OK) { + return [self logErrorWithSQL:nil finalizeStatement:statement returnValue:NO]; + } + return YES; +} + +- (sqlite3_stmt *)prepareSQL:(const char *)SQL { + sqlite3_stmt *statement = nil; + if (sqlite3_prepare_v2(_database, SQL, -1, &statement, NULL) != SQLITE_OK) { + [self logErrorWithSQL:SQL finalizeStatement:statement returnValue:NO]; + return nil; + } + return statement; +} + +- (NSString *)errorMessage { + return [NSString stringWithFormat:@"%s", sqlite3_errmsg(_database)]; +} + +- (int)errorCode { + return sqlite3_errcode(_database); +} + +- (void)logDatabaseError { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000015", @"Error message: %@. Error code: %d.", + [self errorMessage], [self errorCode]); +} + +- (BOOL)logErrorWithSQL:(const char *)SQL + finalizeStatement:(sqlite3_stmt *)statement + returnValue:(BOOL)returnValue { + if (SQL) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000016", @"Failed with SQL: %s.", SQL); + } + [self logDatabaseError]; + + if (statement) { + sqlite3_finalize(statement); + } + + return returnValue; +} + +- (BOOL)isNewDatabase { + return gIsNewDatabase; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h new file mode 100644 index 0000000..1e95373 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigDefines.h @@ -0,0 +1,37 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef RCNConfigDefines_h +#define RCNConfigDefines_h + +#if defined(DEBUG) +#define RCN_MUST_NOT_BE_MAIN_THREAD() \ + do { \ + NSAssert(![NSThread isMainThread], @"Must not be executing on the main thread."); \ + } while (0); +#else +#define RCN_MUST_NOT_BE_MAIN_THREAD() \ + do { \ + } while (0); +#endif + +#define RCNExperimentTableKeyPayload "experiment_payload" +#define RCNExperimentTableKeyMetadata "experiment_metadata" +#define RCNExperimentTableKeyActivePayload "experiment_active_payload" +#define RCNRolloutTableKeyActiveMetadata "active_rollout_metadata" +#define RCNRolloutTableKeyFetchedMetadata "fetched_rollout_metadata" + +#endif diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h new file mode 100644 index 0000000..79051fa --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.h @@ -0,0 +1,38 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class FIRExperimentController; +@class RCNConfigDBManager; + +/// Handles experiment information update and persistence. +@interface RCNConfigExperiment : NSObject + +/// Designated initializer; +- (nonnull instancetype)initWithDBManager:(RCNConfigDBManager *_Nullable)DBManager + experimentController:(FIRExperimentController *_Nullable)controller + NS_DESIGNATED_INITIALIZER; + +/// Use `initWithDBManager:` instead. +- (nonnull instancetype)init NS_UNAVAILABLE; + +/// Update/Persist experiment information from config fetch response. +- (void)updateExperimentsWithResponse:(NSArray *> *_Nullable)response; + +/// Update experiments to Firebase Analytics when `activateWithCompletion:` happens. +- (void)updateExperimentsWithHandler:(nullable void (^)(NSError *_Nullable error))handler; +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m new file mode 100644 index 0000000..f5d09ea --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigExperiment.m @@ -0,0 +1,200 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h" + +#import "FirebaseABTesting/Sources/Private/FirebaseABTestingInternal.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDefines.h" + +static NSString *const kExperimentMetadataKeyLastStartTime = @"last_experiment_start_time"; + +static NSString *const kServiceOrigin = @"frc"; +static NSString *const kMethodNameLatestStartTime = + @"latestExperimentStartTimestampBetweenTimestamp:andPayloads:"; + +@interface RCNConfigExperiment () +@property(nonatomic, strong) + NSMutableArray *experimentPayloads; ///< Experiment payloads. +@property(nonatomic, strong) + NSMutableDictionary *experimentMetadata; ///< Experiment metadata +@property(nonatomic, strong) + NSMutableArray *activeExperimentPayloads; ///< Activated experiment payloads. +@property(nonatomic, strong) RCNConfigDBManager *DBManager; ///< Database Manager. +@property(nonatomic, strong) FIRExperimentController *experimentController; +@property(nonatomic, strong) NSDateFormatter *experimentStartTimeDateFormatter; +@end + +@implementation RCNConfigExperiment +/// Designated initializer +- (instancetype)initWithDBManager:(RCNConfigDBManager *)DBManager + experimentController:(FIRExperimentController *)controller { + self = [super init]; + if (self) { + _experimentPayloads = [[NSMutableArray alloc] init]; + _experimentMetadata = [[NSMutableDictionary alloc] init]; + _activeExperimentPayloads = [[NSMutableArray alloc] init]; + _experimentStartTimeDateFormatter = [[NSDateFormatter alloc] init]; + [_experimentStartTimeDateFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"]; + [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]]; + // Locale needs to be hardcoded. See + // https://developer.apple.com/library/ios/#qa/qa1480/_index.html for more details. + [_experimentStartTimeDateFormatter + setLocale:[[NSLocale alloc] initWithLocaleIdentifier:@"en_US_POSIX"]]; + [_experimentStartTimeDateFormatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]]; + + _DBManager = DBManager; + _experimentController = controller; + [self loadExperimentFromTable]; + } + return self; +} + +- (void)loadExperimentFromTable { + if (!_DBManager) { + return; + } + __weak RCNConfigExperiment *weakSelf = self; + RCNDBCompletion completionHandler = ^(BOOL success, NSDictionary *result) { + RCNConfigExperiment *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + if (result[@RCNExperimentTableKeyPayload]) { + [strongSelf->_experimentPayloads removeAllObjects]; + for (NSData *experiment in result[@RCNExperimentTableKeyPayload]) { + NSError *error; + id experimentPayloadJSON = [NSJSONSerialization JSONObjectWithData:experiment + options:kNilOptions + error:&error]; + if (!experimentPayloadJSON || error) { + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000031", + @"Experiment payload could not be parsed as JSON."); + } else { + [strongSelf->_experimentPayloads addObject:experiment]; + } + } + } + if (result[@RCNExperimentTableKeyMetadata]) { + strongSelf->_experimentMetadata = [result[@RCNExperimentTableKeyMetadata] mutableCopy]; + } + + /// Load activated experiments payload and metadata. + if (result[@RCNExperimentTableKeyActivePayload]) { + [strongSelf->_activeExperimentPayloads removeAllObjects]; + for (NSData *experiment in result[@RCNExperimentTableKeyActivePayload]) { + NSError *error; + id experimentPayloadJSON = [NSJSONSerialization JSONObjectWithData:experiment + options:kNilOptions + error:&error]; + if (!experimentPayloadJSON || error) { + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000031", + @"Activated experiment payload could not be parsed as JSON."); + } else { + [strongSelf->_activeExperimentPayloads addObject:experiment]; + } + } + } + }; + [_DBManager loadExperimentWithCompletionHandler:completionHandler]; +} + +- (void)updateExperimentsWithResponse:(NSArray *> *)response { + // cache fetched experiment payloads. + [_experimentPayloads removeAllObjects]; + [_DBManager deleteExperimentTableForKey:@RCNExperimentTableKeyPayload]; + + for (NSDictionary *experiment in response) { + NSError *error; + NSData *JSONPayload = [NSJSONSerialization dataWithJSONObject:experiment + options:kNilOptions + error:&error]; + if (!JSONPayload || error) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000030", + @"Invalid experiment payload to be serialized."); + } else { + [_experimentPayloads addObject:JSONPayload]; + [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyPayload + value:JSONPayload + completionHandler:nil]; + } + } +} + +- (void)updateExperimentsWithHandler:(void (^)(NSError *_Nullable))handler { + FIRLifecycleEvents *lifecycleEvent = [[FIRLifecycleEvents alloc] init]; + + // Get the last experiment start time prior to the latest payload. + NSTimeInterval lastStartTime = + [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue]; + + // Update the last experiment start time with the latest payload. + [self updateExperimentStartTime]; + [self.experimentController + updateExperimentsWithServiceOrigin:kServiceOrigin + events:lifecycleEvent + policy:ABTExperimentPayloadExperimentOverflowPolicyDiscardOldest + lastStartTime:lastStartTime + payloads:_experimentPayloads + completionHandler:handler]; + + /// Update activated experiments payload and metadata in DB. + [self updateActiveExperimentsInDB]; +} + +- (void)updateExperimentStartTime { + NSTimeInterval existingLastStartTime = + [_experimentMetadata[kExperimentMetadataKeyLastStartTime] doubleValue]; + + NSTimeInterval latestStartTime = + [self latestStartTimeWithExistingLastStartTime:existingLastStartTime]; + + _experimentMetadata[kExperimentMetadataKeyLastStartTime] = @(latestStartTime); + + if (![NSJSONSerialization isValidJSONObject:_experimentMetadata]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000028", + @"Invalid fetched experiment metadata to be serialized."); + return; + } + NSError *error; + NSData *serializedExperimentMetadata = + [NSJSONSerialization dataWithJSONObject:_experimentMetadata + options:NSJSONWritingPrettyPrinted + error:&error]; + [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyMetadata + value:serializedExperimentMetadata + completionHandler:nil]; +} + +- (void)updateActiveExperimentsInDB { + /// Put current fetched experiment payloads into activated experiment DB. + [_activeExperimentPayloads removeAllObjects]; + [_DBManager deleteExperimentTableForKey:@RCNExperimentTableKeyActivePayload]; + for (NSData *experiment in _experimentPayloads) { + [_activeExperimentPayloads addObject:experiment]; + [_DBManager insertExperimentTableWithKey:@RCNExperimentTableKeyActivePayload + value:experiment + completionHandler:nil]; + } +} + +- (NSTimeInterval)latestStartTimeWithExistingLastStartTime:(NSTimeInterval)existingLastStartTime { + return [self.experimentController + latestExperimentStartTimestampBetweenTimestamp:existingLastStartTime + andPayloads:_experimentPayloads]; +} +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigFetch.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigFetch.m new file mode 100644 index 0000000..dbc4b9b --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigFetch.m @@ -0,0 +1,691 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h" +#import "FirebaseRemoteConfig/Sources/Private/FIRRemoteConfig_Private.h" + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigContent.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigExperiment.h" +#import "FirebaseRemoteConfig/Sources/RCNDevice.h" +@import FirebaseRemoteConfigInterop; + +#ifdef RCN_STAGING_SERVER +static NSString *const kServerURLDomain = + @"https://staging-firebaseremoteconfig.sandbox.googleapis.com"; +#else +static NSString *const kServerURLDomain = @"https://firebaseremoteconfig.googleapis.com"; +#endif + +static NSString *const kServerURLVersion = @"/v1"; +static NSString *const kServerURLProjects = @"/projects/"; +static NSString *const kServerURLNamespaces = @"/namespaces/"; +static NSString *const kServerURLQuery = @":fetch?"; +static NSString *const kServerURLKey = @"key="; +static NSString *const kRequestJSONKeyAppID = @"app_id"; + +static NSString *const kHTTPMethodPost = @"POST"; ///< HTTP request method config fetch using +static NSString *const kContentTypeHeaderName = @"Content-Type"; ///< HTTP Header Field Name +static NSString *const kContentEncodingHeaderName = + @"Content-Encoding"; ///< HTTP Header Field Name +static NSString *const kAcceptEncodingHeaderName = @"Accept-Encoding"; ///< HTTP Header Field Name +static NSString *const kETagHeaderName = @"etag"; ///< HTTP Header Field Name +static NSString *const kIfNoneMatchETagHeaderName = @"if-none-match"; ///< HTTP Header Field Name +static NSString *const kInstallationsAuthTokenHeaderName = @"x-goog-firebase-installations-auth"; +// Sends the bundle ID. Refer to b/130301479 for details. +static NSString *const kiOSBundleIdentifierHeaderName = + @"X-Ios-Bundle-Identifier"; ///< HTTP Header Field Name + +static NSString *const kFetchTypeHeaderName = + @"X-Firebase-RC-Fetch-Type"; ///< Custom Http header key to identify the fetch type +static NSString *const kBaseFetchType = @"BASE"; ///< Fetch identifier for Base Fetch +static NSString *const kRealtimeFetchType = @"REALTIME"; ///< Fetch identifier for Realtime Fetch + +/// Config HTTP request content type proto buffer +static NSString *const kContentTypeValueJSON = @"application/json"; + +/// HTTP status codes. Ref: https://cloud.google.com/apis/design/errors#error_retries +static NSInteger const kRCNFetchResponseHTTPStatusCodeOK = 200; +static NSInteger const kRCNFetchResponseHTTPStatusTooManyRequests = 429; +static NSInteger const kRCNFetchResponseHTTPStatusCodeInternalError = 500; +static NSInteger const kRCNFetchResponseHTTPStatusCodeServiceUnavailable = 503; +static NSInteger const kRCNFetchResponseHTTPStatusCodeGatewayTimeout = 504; + +#pragma mark - RCNConfig + +@implementation RCNConfigFetch { + RCNConfigContent *_content; + RCNConfigSettings *_settings; + id _analytics; + RCNConfigExperiment *_experiment; + dispatch_queue_t _lockQueue; /// Guard the read/write operation. + NSURLSession *_fetchSession; /// Managed internally by the fetch instance. + NSString *_FIRNamespace; + FIROptions *_options; + NSString *_templateVersionNumber; +} + +- (instancetype)init { + NSAssert(NO, @"Invalid initializer."); + return nil; +} + +/// Designated initializer +- (instancetype)initWithContent:(RCNConfigContent *)content + DBManager:(RCNConfigDBManager *)DBManager + settings:(RCNConfigSettings *)settings + analytics:(nullable id)analytics + experiment:(RCNConfigExperiment *)experiment + queue:(dispatch_queue_t)queue + namespace:(NSString *)FIRNamespace + options:(FIROptions *)options { + self = [super init]; + if (self) { + _FIRNamespace = FIRNamespace; + _settings = settings; + _analytics = analytics; + _experiment = experiment; + _lockQueue = queue; + _content = content; + _fetchSession = [self newFetchSession]; + _options = options; + _templateVersionNumber = [self->_settings lastFetchedTemplateVersion]; + } + return self; +} + +/// Force a new NSURLSession creation for updated config. +- (void)recreateNetworkSession { + if (_fetchSession) { + [_fetchSession invalidateAndCancel]; + } + _fetchSession = [self newFetchSession]; +} + +/// Return the current session. (Tests). +- (NSURLSession *)currentNetworkSession { + return _fetchSession; +} + +- (void)dealloc { + [_fetchSession invalidateAndCancel]; +} + +#pragma mark - Fetch Config API + +- (void)fetchConfigWithExpirationDuration:(NSTimeInterval)expirationDuration + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler { + // Note: We expect the googleAppID to always be available. + BOOL hasDeviceContextChanged = + FIRRemoteConfigHasDeviceContextChanged(_settings.deviceContext, _options.googleAppID); + + __weak RCNConfigFetch *weakSelf = self; + dispatch_async(_lockQueue, ^{ + RCNConfigFetch *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + // Check whether we are outside of the minimum fetch interval. + if (![strongSelf->_settings hasMinimumFetchIntervalElapsed:expirationDuration] && + !hasDeviceContextChanged) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000051", @"Returning cached data."); + return [strongSelf reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusSuccess + withError:nil]; + } + + // Check if a fetch is already in progress. + if (strongSelf->_settings.isFetchInProgress) { + // Check if we have some fetched data. + if (strongSelf->_settings.lastFetchTimeInterval > 0) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000052", + @"A fetch is already in progress. Using previous fetch results."); + return [strongSelf reportCompletionOnHandler:completionHandler + withStatus:strongSelf->_settings.lastFetchStatus + withError:nil]; + } else { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000053", + @"A fetch is already in progress. Ignoring duplicate request."); + return [strongSelf reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:nil]; + } + } + + // Check whether cache data is within throttle limit. + if ([strongSelf->_settings shouldThrottle] && !hasDeviceContextChanged) { + // Must set lastFetchStatus before FailReason. + strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusThrottled; + strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorThrottled; + NSTimeInterval throttledEndTime = strongSelf->_settings.exponentialBackoffThrottleEndTime; + + NSError *error = + [NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorThrottled + userInfo:@{ + FIRRemoteConfigThrottledEndTimeInSecondsKey : @(throttledEndTime) + }]; + return [strongSelf reportCompletionOnHandler:completionHandler + withStatus:strongSelf->_settings.lastFetchStatus + withError:error]; + } + strongSelf->_settings.isFetchInProgress = YES; + NSString *fetchTypeHeader = [NSString stringWithFormat:@"%@/1", kBaseFetchType]; + [strongSelf refreshInstallationsTokenWithFetchHeader:fetchTypeHeader + completionHandler:completionHandler + updateCompletionHandler:nil]; + }); +} + +#pragma mark - Fetch helpers + +- (void)realtimeFetchConfigWithNoExpirationDuration:(NSInteger)fetchAttemptNumber + completionHandler:(RCNConfigFetchCompletion)completionHandler { + // Note: We expect the googleAppID to always be available. + BOOL hasDeviceContextChanged = + FIRRemoteConfigHasDeviceContextChanged(_settings.deviceContext, _options.googleAppID); + + __weak RCNConfigFetch *weakSelf = self; + dispatch_async(_lockQueue, ^{ + RCNConfigFetch *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + // Check whether cache data is within throttle limit. + if ([strongSelf->_settings shouldThrottle] && !hasDeviceContextChanged) { + // Must set lastFetchStatus before FailReason. + strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusThrottled; + strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorThrottled; + NSTimeInterval throttledEndTime = strongSelf->_settings.exponentialBackoffThrottleEndTime; + + NSError *error = + [NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorThrottled + userInfo:@{ + FIRRemoteConfigThrottledEndTimeInSecondsKey : @(throttledEndTime) + }]; + return [strongSelf reportCompletionWithStatus:FIRRemoteConfigFetchStatusFailure + withUpdate:nil + withError:error + completionHandler:nil + updateCompletionHandler:completionHandler]; + } + strongSelf->_settings.isFetchInProgress = YES; + + NSString *fetchTypeHeader = + [NSString stringWithFormat:@"%@/%ld", kRealtimeFetchType, (long)fetchAttemptNumber]; + [strongSelf refreshInstallationsTokenWithFetchHeader:fetchTypeHeader + completionHandler:nil + updateCompletionHandler:completionHandler]; + }); +} + +- (NSString *)FIRAppNameFromFullyQualifiedNamespace { + return [[_FIRNamespace componentsSeparatedByString:@":"] lastObject]; +} +/// Refresh installation ID token before fetching config. installation ID is now mandatory for fetch +/// requests to work.(b/14751422). +- (void)refreshInstallationsTokenWithFetchHeader:(NSString *)fetchTypeHeader + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler + updateCompletionHandler:(RCNConfigFetchCompletion)updateCompletionHandler { + FIRInstallations *installations = [FIRInstallations + installationsWithApp:[FIRApp appNamed:[self FIRAppNameFromFullyQualifiedNamespace]]]; + if (!installations || !_options.GCMSenderID) { + NSString *errorDescription = @"Failed to get GCMSenderID"; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000074", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + self->_settings.isFetchInProgress = NO; + return [self + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{ + NSLocalizedDescriptionKey : errorDescription + }]]; + } + + __weak RCNConfigFetch *weakSelf = self; + FIRInstallationsTokenHandler installationsTokenHandler = ^( + FIRInstallationsAuthTokenResult *tokenResult, NSError *error) { + RCNConfigFetch *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + if (!tokenResult || !tokenResult.authToken || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"Failed to get installations token. Error : %@.", error]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000073", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + strongSelf->_settings.isFetchInProgress = NO; + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = errorDescription; + userInfo[NSUnderlyingErrorKey] = error.userInfo[NSUnderlyingErrorKey]; + + return [strongSelf + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:userInfo]]; + } + + // We have a valid token. Get the backing installationID. + [installations installationIDWithCompletion:^(NSString *_Nullable identifier, + NSError *_Nullable error) { + RCNConfigFetch *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + // Dispatch to the RC serial queue to update settings on the queue. + dispatch_async(strongSelf->_lockQueue, ^{ + RCNConfigFetch *strongSelfQueue = weakSelf; + if (strongSelfQueue == nil) { + return; + } + + // Update config settings with the IID and token. + strongSelfQueue->_settings.configInstallationsToken = tokenResult.authToken; + strongSelfQueue->_settings.configInstallationsIdentifier = identifier; + + if (!identifier || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"Error getting iid : %@.", error]; + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSLocalizedDescriptionKey] = errorDescription; + userInfo[NSUnderlyingErrorKey] = error.userInfo[NSUnderlyingErrorKey]; + + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000055", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + strongSelfQueue->_settings.isFetchInProgress = NO; + return [strongSelfQueue + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:userInfo]]; + } + + FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000022", @"Success to get iid : %@.", + strongSelfQueue->_settings.configInstallationsIdentifier); + [strongSelf doFetchCall:fetchTypeHeader + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + }); + }]; + }; + + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000039", @"Starting requesting token."); + [installations authTokenWithCompletion:installationsTokenHandler]; +} + +- (void)doFetchCall:(NSString *)fetchTypeHeader + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler + updateCompletionHandler:(RCNConfigFetchCompletion)updateCompletionHandler { + [self getAnalyticsUserPropertiesWithCompletionHandler:^(NSDictionary *userProperties) { + dispatch_async(self->_lockQueue, ^{ + [self fetchWithUserProperties:userProperties + fetchTypeHeader:fetchTypeHeader + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + }); + }]; +} + +- (void)getAnalyticsUserPropertiesWithCompletionHandler: + (FIRAInteropUserPropertiesCallback)completionHandler { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000060", @"Fetch with user properties completed."); + id analytics = self->_analytics; + if (analytics == nil) { + completionHandler(@{}); + } else { + [analytics getUserPropertiesWithCallback:completionHandler]; + } +} + +- (void)reportCompletionOnHandler:(FIRRemoteConfigFetchCompletion)completionHandler + withStatus:(FIRRemoteConfigFetchStatus)status + withError:(NSError *)error { + [self reportCompletionWithStatus:status + withUpdate:nil + withError:error + completionHandler:completionHandler + updateCompletionHandler:nil]; +} + +- (void)reportCompletionWithStatus:(FIRRemoteConfigFetchStatus)status + withUpdate:(FIRRemoteConfigUpdate *)update + withError:(NSError *)error + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler + updateCompletionHandler:(RCNConfigFetchCompletion)updateCompletionHandler { + if (completionHandler) { + dispatch_async(dispatch_get_main_queue(), ^{ + completionHandler(status, error); + }); + } + // if completion handler expects a config update response + if (updateCompletionHandler) { + dispatch_async(dispatch_get_main_queue(), ^{ + updateCompletionHandler(status, update, error); + }); + } +} + +- (void)fetchWithUserProperties:(NSDictionary *)userProperties + fetchTypeHeader:(NSString *)fetchTypeHeader + completionHandler:(FIRRemoteConfigFetchCompletion)completionHandler + updateCompletionHandler:(RCNConfigFetchCompletion)updateCompletionHandler { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000061", @"Fetch with user properties initiated."); + + NSString *postRequestString = [_settings nextRequestWithUserProperties:userProperties]; + + // Get POST request content. + NSData *content = [postRequestString dataUsingEncoding:NSUTF8StringEncoding]; + NSError *compressionError; + NSData *compressedContent = [NSData gul_dataByGzippingData:content error:&compressionError]; + if (compressionError) { + NSString *errString = [NSString stringWithFormat:@"Failed to compress the config request."]; + FIRLogWarning(kFIRLoggerRemoteConfig, @"I-RCN000033", @"%@", errString); + NSError *error = [NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{NSLocalizedDescriptionKey : errString}]; + + self->_settings.isFetchInProgress = NO; + return [self reportCompletionWithStatus:FIRRemoteConfigFetchStatusFailure + withUpdate:nil + withError:error + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + } + + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000040", @"Start config fetch."); + __weak RCNConfigFetch *weakSelf = self; + RCNConfigFetcherCompletion fetcherCompletion = ^(NSData *data, NSURLResponse *response, + NSError *error) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000050", + @"config fetch completed. Error: %@ StatusCode: %ld", (error ? error : @"nil"), + (long)[((NSHTTPURLResponse *)response) statusCode]); + + RCNConfigFetch *fetcherCompletionSelf = weakSelf; + if (fetcherCompletionSelf == nil) { + return; + } + + // The fetch has completed. + fetcherCompletionSelf->_settings.isFetchInProgress = NO; + + dispatch_async(fetcherCompletionSelf->_lockQueue, ^{ + RCNConfigFetch *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + NSInteger statusCode = [((NSHTTPURLResponse *)response) statusCode]; + + if (error || (statusCode != kRCNFetchResponseHTTPStatusCodeOK)) { + // Update metadata about fetch failure. + [strongSelf->_settings updateMetadataWithFetchSuccessStatus:NO templateVersion:nil]; + if (error) { + if (strongSelf->_settings.lastFetchStatus == FIRRemoteConfigFetchStatusSuccess) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000025", + @"RCN Fetch failure: %@. Using cached config result.", error); + } else { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000026", + @"RCN Fetch failure: %@. No cached config result.", error); + } + } + if (statusCode != kRCNFetchResponseHTTPStatusCodeOK) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000026", + @"RCN Fetch failure. Response http error code: %ld", (long)statusCode); + // Response error code 429, 500, 503 will trigger exponential backoff mode. + // TODO: check error code in helper + if (statusCode == kRCNFetchResponseHTTPStatusTooManyRequests || + statusCode == kRCNFetchResponseHTTPStatusCodeInternalError || + statusCode == kRCNFetchResponseHTTPStatusCodeServiceUnavailable || + statusCode == kRCNFetchResponseHTTPStatusCodeGatewayTimeout) { + [strongSelf->_settings updateExponentialBackoffTime]; + if ([strongSelf->_settings shouldThrottle]) { + // Must set lastFetchStatus before FailReason. + strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusThrottled; + strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorThrottled; + NSTimeInterval throttledEndTime = + strongSelf->_settings.exponentialBackoffThrottleEndTime; + + NSError *error = [NSError + errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorThrottled + userInfo:@{ + FIRRemoteConfigThrottledEndTimeInSecondsKey : @(throttledEndTime) + }]; + return [strongSelf reportCompletionWithStatus:strongSelf->_settings.lastFetchStatus + withUpdate:nil + withError:error + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + } + } + } + // Return back the received error. + // Must set lastFetchStatus before setting Fetch Error. + strongSelf->_settings.lastFetchStatus = FIRRemoteConfigFetchStatusFailure; + strongSelf->_settings.lastFetchError = FIRRemoteConfigErrorInternalError; + NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; + userInfo[NSUnderlyingErrorKey] = error; + userInfo[NSLocalizedDescriptionKey] = + error.localizedDescription + ?: [NSString + stringWithFormat:@"Internal Error. Status code: %ld", (long)statusCode]; + + return [strongSelf + reportCompletionWithStatus:FIRRemoteConfigFetchStatusFailure + withUpdate:nil + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:userInfo] + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + } + + // Fetch was successful. Check if we have data. + NSError *retError; + if (!data) { + FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000043", @"RCN Fetch: No data in fetch response"); + // There may still be a difference between fetched and active config + FIRRemoteConfigUpdate *update = + [strongSelf->_content getConfigUpdateForNamespace:strongSelf->_FIRNamespace]; + return [strongSelf reportCompletionWithStatus:FIRRemoteConfigFetchStatusSuccess + withUpdate:update + withError:nil + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + } + + // Config fetch succeeded. + // JSONObjectWithData is always expected to return an NSDictionary in our case + NSMutableDictionary *fetchedConfig = + [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:&retError]; + if (retError) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000042", + @"RCN Fetch failure: %@. Could not parse response data as JSON", error); + } + + // Check and log if we received an error from the server + if (fetchedConfig && fetchedConfig.count == 1 && fetchedConfig[RCNFetchResponseKeyError]) { + NSString *errStr = [NSString stringWithFormat:@"RCN Fetch Failure: Server returned error:"]; + NSDictionary *errDict = fetchedConfig[RCNFetchResponseKeyError]; + if (errDict[RCNFetchResponseKeyErrorCode]) { + errStr = [errStr + stringByAppendingString:[NSString + stringWithFormat:@"code: %@", + errDict[RCNFetchResponseKeyErrorCode]]]; + } + if (errDict[RCNFetchResponseKeyErrorStatus]) { + errStr = [errStr stringByAppendingString: + [NSString stringWithFormat:@". Status: %@", + errDict[RCNFetchResponseKeyErrorStatus]]]; + } + if (errDict[RCNFetchResponseKeyErrorMessage]) { + errStr = + [errStr stringByAppendingString: + [NSString stringWithFormat:@". Message: %@", + errDict[RCNFetchResponseKeyErrorMessage]]]; + } + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000044", @"%@.", errStr); + NSError *error = [NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{NSLocalizedDescriptionKey : errStr}]; + return [strongSelf reportCompletionWithStatus:FIRRemoteConfigFetchStatusFailure + withUpdate:nil + withError:error + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + } + + // Add the fetched config to the database. + if (fetchedConfig) { + // Update config content to cache and DB. + [strongSelf->_content updateConfigContentWithResponse:fetchedConfig + forNamespace:strongSelf->_FIRNamespace]; + // Update experiments only for 3p namespace + NSString *namespace = [strongSelf->_FIRNamespace + substringToIndex:[strongSelf->_FIRNamespace rangeOfString:@":"].location]; + if ([namespace isEqualToString:FIRRemoteConfigConstants.FIRNamespaceGoogleMobilePlatform]) { + [strongSelf->_experiment updateExperimentsWithResponse: + fetchedConfig[RCNFetchResponseKeyExperimentDescriptions]]; + } + + strongSelf->_templateVersionNumber = [strongSelf getTemplateVersionNumber:fetchedConfig]; + } else { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000063", + @"Empty response with no fetched config."); + } + + // We had a successful fetch. Update the current eTag in settings if different. + NSString *latestETag = ((NSHTTPURLResponse *)response).allHeaderFields[kETagHeaderName]; + if (!strongSelf->_settings.lastETag || + !([strongSelf->_settings.lastETag isEqualToString:latestETag])) { + strongSelf->_settings.lastETag = latestETag; + } + // Compute config update after successful fetch + FIRRemoteConfigUpdate *update = + [strongSelf->_content getConfigUpdateForNamespace:strongSelf->_FIRNamespace]; + + [strongSelf->_settings + updateMetadataWithFetchSuccessStatus:YES + templateVersion:strongSelf->_templateVersionNumber]; + return [strongSelf reportCompletionWithStatus:FIRRemoteConfigFetchStatusSuccess + withUpdate:update + withError:nil + completionHandler:completionHandler + updateCompletionHandler:updateCompletionHandler]; + }); + }; + + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000061", @"Making remote config fetch."); + + NSURLSessionDataTask *dataTask = [self URLSessionDataTaskWithContent:compressedContent + fetchTypeHeader:fetchTypeHeader + completionHandler:fetcherCompletion]; + [dataTask resume]; +} + +- (NSString *)constructServerURL { + NSString *serverURLStr = [[NSString alloc] initWithString:kServerURLDomain]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLVersion]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLProjects]; + serverURLStr = [serverURLStr stringByAppendingString:_options.projectID]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLNamespaces]; + + // Get the namespace from the fully qualified namespace string of "namespace:FIRAppName". + NSString *namespace = + [_FIRNamespace substringToIndex:[_FIRNamespace rangeOfString:@":"].location]; + serverURLStr = [serverURLStr stringByAppendingString:namespace]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLQuery]; + + if (_options.APIKey) { + serverURLStr = [serverURLStr stringByAppendingString:kServerURLKey]; + serverURLStr = [serverURLStr stringByAppendingString:_options.APIKey]; + } else { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000071", + @"Missing `APIKey` from `FirebaseOptions`, please ensure the configured " + @"`FirebaseApp` is configured with `FirebaseOptions` that contains an `APIKey`."); + } + + return serverURLStr; +} + +- (NSURLSession *)newFetchSession { + NSURLSessionConfiguration *config = + [[NSURLSessionConfiguration defaultSessionConfiguration] copy]; + config.timeoutIntervalForRequest = _settings.fetchTimeout; + config.timeoutIntervalForResource = _settings.fetchTimeout; + NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; + return session; +} + +- (NSURLSessionDataTask *)URLSessionDataTaskWithContent:(NSData *)content + fetchTypeHeader:(NSString *)fetchTypeHeader + completionHandler: + (RCNConfigFetcherCompletion)fetcherCompletion { + NSURL *URL = [NSURL URLWithString:[self constructServerURL]]; + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000046", @"%@", + [NSString stringWithFormat:@"Making config request: %@", [URL absoluteString]]); + + NSTimeInterval timeoutInterval = _fetchSession.configuration.timeoutIntervalForResource; + NSMutableURLRequest *URLRequest = + [[NSMutableURLRequest alloc] initWithURL:URL + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeoutInterval]; + URLRequest.HTTPMethod = kHTTPMethodPost; + [URLRequest setValue:kContentTypeValueJSON forHTTPHeaderField:kContentTypeHeaderName]; + [URLRequest setValue:_settings.configInstallationsToken + forHTTPHeaderField:kInstallationsAuthTokenHeaderName]; + [URLRequest setValue:[[NSBundle mainBundle] bundleIdentifier] + forHTTPHeaderField:kiOSBundleIdentifierHeaderName]; + [URLRequest setValue:@"gzip" forHTTPHeaderField:kContentEncodingHeaderName]; + [URLRequest setValue:@"gzip" forHTTPHeaderField:kAcceptEncodingHeaderName]; + [URLRequest setValue:fetchTypeHeader forHTTPHeaderField:kFetchTypeHeaderName]; + // Set the eTag from the last successful fetch, if available. + if (_settings.lastETag) { + [URLRequest setValue:_settings.lastETag forHTTPHeaderField:kIfNoneMatchETagHeaderName]; + } + [URLRequest setHTTPBody:content]; + + return [_fetchSession dataTaskWithRequest:URLRequest completionHandler:fetcherCompletion]; +} + +- (NSString *)getTemplateVersionNumber:(NSDictionary *)fetchedConfig { + if (fetchedConfig != nil && [fetchedConfig objectForKey:RCNFetchResponseKeyTemplateVersion] && + [[fetchedConfig objectForKey:RCNFetchResponseKeyTemplateVersion] + isKindOfClass:[NSString class]]) { + return (NSString *)[fetchedConfig objectForKey:RCNFetchResponseKeyTemplateVersion]; + } + + return @"0"; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.h new file mode 100644 index 0000000..56b6ad1 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h" +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +@class RCNConfigSettings; + +@interface RCNConfigRealtime : NSObject + +/// Completion handler invoked by config update methods when they get a response from the server. +/// +/// @param error Error message on failure. +typedef void (^RCNConfigUpdateCompletion)(FIRRemoteConfigUpdate *_Nullable configUpdate, + NSError *_Nullable error); + +- (instancetype _Nonnull)init:(RCNConfigFetch *_Nonnull)configFetch + settings:(RCNConfigSettings *_Nonnull)settings + namespace:(NSString *_Nonnull)namespace + options:(FIROptions *_Nonnull)options; + +- (FIRConfigUpdateListenerRegistration *_Nonnull)addConfigUpdateListener: + (RCNConfigUpdateCompletion _Nonnull)listener; +- (void)removeConfigUpdateListener:(RCNConfigUpdateCompletion _Nonnull)listener; + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m new file mode 100644 index 0000000..921bb31 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigRealtime.m @@ -0,0 +1,732 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNConfigRealtime.h" +#import +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigFetch.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNDevice.h" + +/// URL params +static NSString *const kServerURLDomain = @"https://firebaseremoteconfigrealtime.googleapis.com"; +static NSString *const kServerURLVersion = @"/v1"; +static NSString *const kServerURLProjects = @"/projects/"; +static NSString *const kServerURLNamespaces = @"/namespaces/"; +static NSString *const kServerURLQuery = @":streamFetchInvalidations?"; +static NSString *const kServerURLKey = @"key="; + +/// Realtime API enablement +static NSString *const kServerForbiddenStatusCode = @"\"code\": 403"; + +/// Header names +static NSString *const kHTTPMethodPost = @"POST"; ///< HTTP request method config fetch using +static NSString *const kContentTypeHeaderName = @"Content-Type"; ///< HTTP Header Field Name +static NSString *const kContentEncodingHeaderName = + @"Content-Encoding"; ///< HTTP Header Field Name +static NSString *const kAcceptEncodingHeaderName = @"Accept"; ///< HTTP Header Field Name +static NSString *const kETagHeaderName = @"etag"; ///< HTTP Header Field Name +static NSString *const kIfNoneMatchETagHeaderName = @"if-none-match"; ///< HTTP Header Field Name +static NSString *const kInstallationsAuthTokenHeaderName = @"x-goog-firebase-installations-auth"; +// Sends the bundle ID. Refer to b/130301479 for details. +static NSString *const kiOSBundleIdentifierHeaderName = + @"X-Ios-Bundle-Identifier"; ///< HTTP Header Field Name + +/// Retryable HTTP status code. +static NSInteger const kRCNFetchResponseHTTPStatusOk = 200; +static NSInteger const kRCNFetchResponseHTTPStatusClientTimeout = 429; +static NSInteger const kRCNFetchResponseHTTPStatusTooManyRequests = 429; +static NSInteger const kRCNFetchResponseHTTPStatusCodeBadGateway = 502; +static NSInteger const kRCNFetchResponseHTTPStatusCodeServiceUnavailable = 503; +static NSInteger const kRCNFetchResponseHTTPStatusCodeGatewayTimeout = 504; + +/// Invalidation message field names. +static NSString *const kTemplateVersionNumberKey = @"latestTemplateVersionNumber"; +static NSString *const kIsFeatureDisabled = @"featureDisabled"; + +static NSTimeInterval gTimeoutSeconds = 330; +static NSInteger const gFetchAttempts = 3; + +// Retry parameters +static NSInteger const gMaxRetries = 7; + +@interface FIRConfigUpdateListenerRegistration () +@property(strong, atomic, nonnull) RCNConfigUpdateCompletion completionHandler; +@end + +@implementation FIRConfigUpdateListenerRegistration { + RCNConfigRealtime *_realtimeClient; +} + +- (instancetype)initWithClient:(RCNConfigRealtime *)realtimeClient + completionHandler:(RCNConfigUpdateCompletion)completionHandler { + self = [super init]; + if (self) { + _realtimeClient = realtimeClient; + _completionHandler = completionHandler; + } + return self; +} + +- (void)remove { + [self->_realtimeClient removeConfigUpdateListener:_completionHandler]; +} + +@end + +@interface RCNConfigRealtime () + +@property(strong, atomic, nonnull) NSMutableSet *listeners; +@property(strong, atomic, nonnull) dispatch_queue_t realtimeLockQueue; +@property(strong, atomic, nonnull) NSNotificationCenter *notificationCenter; + +@property(strong, atomic) NSURLSession *session; +@property(strong, atomic) NSURLSessionDataTask *dataTask; +@property(strong, atomic) NSMutableURLRequest *request; + +@end + +@implementation RCNConfigRealtime { + RCNConfigFetch *_configFetch; + RCNConfigSettings *_settings; + FIROptions *_options; + NSString *_namespace; + NSInteger _remainingRetryCount; + bool _isRequestInProgress; + bool _isInBackground; + bool _isRealtimeDisabled; +} + +- (instancetype)init:(RCNConfigFetch *)configFetch + settings:(RCNConfigSettings *)settings + namespace:(NSString *)namespace + options:(FIROptions *)options { + self = [super init]; + if (self) { + _listeners = [[NSMutableSet alloc] init]; + _realtimeLockQueue = [RCNConfigRealtime realtimeRemoteConfigSerialQueue]; + _notificationCenter = [NSNotificationCenter defaultCenter]; + + _configFetch = configFetch; + _settings = settings; + _options = options; + _namespace = namespace; + + _remainingRetryCount = MAX(gMaxRetries - [_settings realtimeRetryCount], 1); + _isRequestInProgress = false; + _isRealtimeDisabled = false; + _isInBackground = false; + + [self setUpHttpRequest]; + [self setUpHttpSession]; + [self backgroundChangeListener]; + } + + return self; +} + +/// Singleton instance of serial queue for queuing all incoming RC calls. ++ (dispatch_queue_t)realtimeRemoteConfigSerialQueue { + static dispatch_once_t onceToken; + static dispatch_queue_t realtimeRemoteConfigQueue; + dispatch_once(&onceToken, ^{ + realtimeRemoteConfigQueue = + dispatch_queue_create(RCNRemoteConfigQueueLabel, DISPATCH_QUEUE_SERIAL); + }); + return realtimeRemoteConfigQueue; +} + +- (void)propogateErrors:(NSError *)error { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + for (RCNConfigUpdateCompletion listener in strongSelf->_listeners) { + listener(nil, error); + } + }); +} + +#pragma mark - Test Only Helpers + +// TESTING ONLY +- (void)triggerListenerForTesting:(void (^_Nonnull)(FIRRemoteConfigUpdate *configUpdate, + NSError *_Nullable error))listener { + listener([[FIRRemoteConfigUpdate alloc] init], nil); +} + +#pragma mark - Http Helpers + +- (NSString *)constructServerURL { + NSString *serverURLStr = [[NSString alloc] initWithString:kServerURLDomain]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLVersion]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLProjects]; + serverURLStr = [serverURLStr stringByAppendingString:_options.GCMSenderID]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLNamespaces]; + + /// Get the namespace from the fully qualified namespace string of "namespace:FIRAppName". + NSString *namespace = [_namespace substringToIndex:[_namespace rangeOfString:@":"].location]; + serverURLStr = [serverURLStr stringByAppendingString:namespace]; + serverURLStr = [serverURLStr stringByAppendingString:kServerURLQuery]; + if (_options.APIKey) { + serverURLStr = [serverURLStr stringByAppendingString:kServerURLKey]; + serverURLStr = [serverURLStr stringByAppendingString:_options.APIKey]; + } else { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000071", + @"Missing `APIKey` from `FirebaseOptions`, please ensure the configured " + @"`FirebaseApp` is configured with `FirebaseOptions` that contains an `APIKey`."); + } + + return serverURLStr; +} + +- (NSString *)FIRAppNameFromFullyQualifiedNamespace { + return [[_namespace componentsSeparatedByString:@":"] lastObject]; +} + +- (void)reportCompletionOnHandler:(FIRRemoteConfigFetchCompletion)completionHandler + withStatus:(FIRRemoteConfigFetchStatus)status + withError:(NSError *)error { + if (completionHandler) { + dispatch_async(_realtimeLockQueue, ^{ + completionHandler(status, error); + }); + } +} + +/// Refresh installation ID token before fetching config. installation ID is now mandatory for fetch +/// requests to work.(b/14751422). +- (void)refreshInstallationsTokenWithCompletionHandler: + (FIRRemoteConfigFetchCompletion)completionHandler { + FIRInstallations *installations = [FIRInstallations + installationsWithApp:[FIRApp appNamed:[self FIRAppNameFromFullyQualifiedNamespace]]]; + if (!installations || !_options.GCMSenderID) { + NSString *errorDescription = @"Failed to get GCMSenderID"; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000074", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + return [self + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{ + NSLocalizedDescriptionKey : errorDescription + }]]; + } + + __weak RCNConfigRealtime *weakSelf = self; + FIRInstallationsTokenHandler installationsTokenHandler = ^( + FIRInstallationsAuthTokenResult *tokenResult, NSError *error) { + RCNConfigRealtime *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + if (!tokenResult || !tokenResult.authToken || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"Failed to get installations token. Error : %@.", error]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000073", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + return [strongSelf + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{ + NSLocalizedDescriptionKey : errorDescription + }]]; + } + + /// We have a valid token. Get the backing installationID. + [installations installationIDWithCompletion:^(NSString *_Nullable identifier, + NSError *_Nullable error) { + RCNConfigRealtime *strongSelf = weakSelf; + if (strongSelf == nil) { + return; + } + + // Dispatch to the RC serial queue to update settings on the queue. + dispatch_async(strongSelf->_realtimeLockQueue, ^{ + RCNConfigRealtime *strongSelfQueue = weakSelf; + if (strongSelfQueue == nil) { + return; + } + + /// Update config settings with the IID and token. + strongSelfQueue->_settings.configInstallationsToken = tokenResult.authToken; + strongSelfQueue->_settings.configInstallationsIdentifier = identifier; + + if (!identifier || error) { + NSString *errorDescription = + [NSString stringWithFormat:@"Error getting iid : %@.", error]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000055", @"%@", + [NSString stringWithFormat:@"%@", errorDescription]); + strongSelfQueue->_settings.isFetchInProgress = NO; + return [strongSelfQueue + reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusFailure + withError:[NSError + errorWithDomain:FIRRemoteConfigErrorDomain + code:FIRRemoteConfigErrorInternalError + userInfo:@{ + NSLocalizedDescriptionKey : errorDescription + }]]; + } + + FIRLogInfo(kFIRLoggerRemoteConfig, @"I-RCN000022", @"Success to get iid : %@.", + strongSelfQueue->_settings.configInstallationsIdentifier); + return [strongSelfQueue reportCompletionOnHandler:completionHandler + withStatus:FIRRemoteConfigFetchStatusNoFetchYet + withError:nil]; + }); + }]; + }; + + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000039", @"Starting requesting token."); + [installations authTokenWithCompletion:installationsTokenHandler]; +} + +- (void)createRequestBodyWithCompletion:(void (^)(NSData *_Nonnull requestBody))completion { + __weak __typeof(self) weakSelf = self; + [self refreshInstallationsTokenWithCompletionHandler:^(FIRRemoteConfigFetchStatus status, + NSError *_Nullable error) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) return; + + if (![strongSelf->_settings.configInstallationsIdentifier length]) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000013", + @"Installation token retrieval failed. Realtime connection will not include " + @"valid installations token."); + } + + [strongSelf.request setValue:strongSelf->_settings.configInstallationsToken + forHTTPHeaderField:kInstallationsAuthTokenHeaderName]; + if (strongSelf->_settings.lastETag) { + [strongSelf.request setValue:strongSelf->_settings.lastETag + forHTTPHeaderField:kIfNoneMatchETagHeaderName]; + } + + NSString *namespace = [strongSelf->_namespace + substringToIndex:[strongSelf->_namespace rangeOfString:@":"].location]; + NSString *postBody = [NSString + stringWithFormat:@"{project:'%@', namespace:'%@', lastKnownVersionNumber:'%@', appId:'%@', " + @"sdkVersion:'%@', appInstanceId:'%@'}", + [strongSelf->_options GCMSenderID], namespace, + strongSelf->_configFetch.templateVersionNumber, + strongSelf->_options.googleAppID, FIRRemoteConfigPodVersion(), + strongSelf->_settings.configInstallationsIdentifier]; + NSData *postData = [postBody dataUsingEncoding:NSUTF8StringEncoding]; + NSError *compressionError; + completion([NSData gul_dataByGzippingData:postData error:&compressionError]); + }]; +} + +/// Creates request. +- (void)setUpHttpRequest { + NSString *address = [self constructServerURL]; + _request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:address] + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:gTimeoutSeconds]; + [_request setHTTPMethod:kHTTPMethodPost]; + [_request setValue:@"application/json" forHTTPHeaderField:kContentTypeHeaderName]; + [_request setValue:@"application/json" forHTTPHeaderField:kAcceptEncodingHeaderName]; + [_request setValue:@"gzip" forHTTPHeaderField:kContentEncodingHeaderName]; + [_request setValue:@"true" forHTTPHeaderField:@"X-Google-GFE-Can-Retry"]; + [_request setValue:[_options APIKey] forHTTPHeaderField:@"X-Goog-Api-Key"]; + [_request setValue:[[NSBundle mainBundle] bundleIdentifier] + forHTTPHeaderField:kiOSBundleIdentifierHeaderName]; +} + +/// Makes call to create session. +- (void)setUpHttpSession { + NSURLSessionConfiguration *sessionConfig = + [[NSURLSessionConfiguration defaultSessionConfiguration] copy]; + [sessionConfig setTimeoutIntervalForResource:gTimeoutSeconds]; + [sessionConfig setTimeoutIntervalForRequest:gTimeoutSeconds]; + _session = [NSURLSession sessionWithConfiguration:sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; +} + +#pragma mark - Retry Helpers + +- (BOOL)canMakeConnection { + BOOL noRunningConnection = + self->_dataTask == nil || self->_dataTask.state != NSURLSessionTaskStateRunning; + BOOL canMakeConnection = noRunningConnection && [self->_listeners count] > 0 && + !self->_isInBackground && !self->_isRealtimeDisabled; + return canMakeConnection; +} + +// Retry mechanism for HTTP connections +- (void)retryHTTPConnection { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + if (!strongSelf || strongSelf->_isInBackground) { + return; + } + + if ([strongSelf canMakeConnection] && strongSelf->_remainingRetryCount > 0) { + NSTimeInterval backOffInterval = self->_settings.getRealtimeBackoffInterval; + + strongSelf->_remainingRetryCount--; + [strongSelf->_settings setRealtimeRetryCount:[strongSelf->_settings realtimeRetryCount] + 1]; + dispatch_time_t executionDelay = + dispatch_time(DISPATCH_TIME_NOW, (backOffInterval * NSEC_PER_SEC)); + dispatch_after(executionDelay, strongSelf->_realtimeLockQueue, ^{ + [strongSelf beginRealtimeStream]; + }); + } else { + NSError *error = [NSError + errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorStreamError + userInfo:@{ + NSLocalizedDescriptionKey : + @"Unable to connect to the server. Check your connection and try again." + }]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000014", @"Cannot establish connection. Error: %@", + error); + [self propogateErrors:error]; + } + }); +} + +- (void)backgroundChangeListener { + [_notificationCenter addObserver:self + selector:@selector(isInForeground) + name:@"UIApplicationWillEnterForegroundNotification" + object:nil]; + + [_notificationCenter addObserver:self + selector:@selector(isInBackground) + name:@"UIApplicationDidEnterBackgroundNotification" + object:nil]; +} + +- (void)isInForeground { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + strongSelf->_isInBackground = false; + [strongSelf beginRealtimeStream]; + }); +} + +- (void)isInBackground { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + [strongSelf pauseRealtimeStream]; + strongSelf->_isInBackground = true; + }); +} + +#pragma mark - Autofetch Helpers + +- (void)fetchLatestConfig:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + NSInteger attempts = remainingAttempts - 1; + + [strongSelf->_configFetch + realtimeFetchConfigWithNoExpirationDuration:gFetchAttempts - attempts + completionHandler:^(FIRRemoteConfigFetchStatus status, + FIRRemoteConfigUpdate *update, + NSError *error) { + if (error != nil) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000010", + @"Failed to retrieve config due to fetch error. " + @"Error: %@", + error); + return [self propogateErrors:error]; + } + if (status == FIRRemoteConfigFetchStatusSuccess) { + if ([strongSelf->_configFetch.templateVersionNumber + integerValue] >= targetVersion) { + // only notify listeners if there is a change + if ([update updatedKeys].count > 0) { + for (RCNConfigUpdateCompletion listener in strongSelf + ->_listeners) { + listener(update, nil); + } + } + } else { + FIRLogDebug( + kFIRLoggerRemoteConfig, @"I-RCN000016", + @"Fetched config's template version is outdated, " + @"re-fetching"); + [strongSelf autoFetch:attempts targetVersion:targetVersion]; + } + } else { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000016", + @"Fetched config's template version is " + @"outdated, re-fetching"); + [strongSelf autoFetch:attempts targetVersion:targetVersion]; + } + }]; + }); +} + +- (void)scheduleFetch:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion { + /// Needs fetch to occur between 0 - 3 seconds. Randomize to not cause DDoS alerts in backend + dispatch_time_t executionDelay = + dispatch_time(DISPATCH_TIME_NOW, arc4random_uniform(4) * NSEC_PER_SEC); + dispatch_after(executionDelay, _realtimeLockQueue, ^{ + [self fetchLatestConfig:remainingAttempts targetVersion:targetVersion]; + }); +} + +/// Perform fetch and handle developers callbacks +- (void)autoFetch:(NSInteger)remainingAttempts targetVersion:(NSInteger)targetVersion { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + if (remainingAttempts == 0) { + NSError *error = [NSError errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorNotFetched + userInfo:@{ + NSLocalizedDescriptionKey : + @"Unable to fetch the latest version of the template." + }]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000011", + @"Ran out of fetch attempts, cannot find target config version."); + [self propogateErrors:error]; + return; + } + + [strongSelf scheduleFetch:remainingAttempts targetVersion:targetVersion]; + }); +} + +#pragma mark - NSURLSession Delegates + +- (void)evaluateStreamResponse:(NSDictionary *)response error:(NSError *)dataError { + NSInteger updateTemplateVersion = 1; + if (dataError == nil) { + if ([response objectForKey:kTemplateVersionNumberKey]) { + updateTemplateVersion = [[response objectForKey:kTemplateVersionNumberKey] integerValue]; + } + if ([response objectForKey:kIsFeatureDisabled]) { + self->_isRealtimeDisabled = [response objectForKey:kIsFeatureDisabled]; + } + + if (self->_isRealtimeDisabled) { + [self pauseRealtimeStream]; + NSError *error = [NSError + errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorUnavailable + userInfo:@{ + NSLocalizedDescriptionKey : + @"The server is temporarily unavailable. Try again in a few minutes." + }]; + [self propogateErrors:error]; + } else { + NSInteger clientTemplateVersion = [_configFetch.templateVersionNumber integerValue]; + if (updateTemplateVersion > clientTemplateVersion) { + [self autoFetch:gFetchAttempts targetVersion:updateTemplateVersion]; + } + } + } else { + NSError *error = + [NSError errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorMessageInvalid + userInfo:@{NSLocalizedDescriptionKey : @"Unable to parse ConfigUpdate."}]; + [self propogateErrors:error]; + } +} + +/// Delegate to asynchronously handle every new notification that comes over the wire. Auto-fetches +/// and runs callback for each new notification +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + NSError *dataError; + NSString *strData = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + + /// If response data contains the API enablement link, return the entire message to the user in + /// the form of a error. + if ([strData containsString:kServerForbiddenStatusCode]) { + NSError *error = [NSError errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorStreamError + userInfo:@{NSLocalizedDescriptionKey : strData}]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000021", @"Cannot establish connection. %@", error); + [self propogateErrors:error]; + return; + } + + NSRange endRange = [strData rangeOfString:@"}"]; + NSRange beginRange = [strData rangeOfString:@"{"]; + if (beginRange.location != NSNotFound && endRange.location != NSNotFound) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000015", + @"Received config update message on stream."); + NSRange msgRange = + NSMakeRange(beginRange.location, endRange.location - beginRange.location + 1); + strData = [strData substringWithRange:msgRange]; + data = [strData dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data + options:NSJSONReadingMutableContainers + error:&dataError]; + + [self evaluateStreamResponse:response error:dataError]; + } +} + +/// Check if response code is retryable +- (bool)isStatusCodeRetryable:(NSInteger)statusCode { + return statusCode == kRCNFetchResponseHTTPStatusClientTimeout || + statusCode == kRCNFetchResponseHTTPStatusTooManyRequests || + statusCode == kRCNFetchResponseHTTPStatusCodeServiceUnavailable || + statusCode == kRCNFetchResponseHTTPStatusCodeBadGateway || + statusCode == kRCNFetchResponseHTTPStatusCodeGatewayTimeout; +} + +/// Delegate to handle initial reply from the server +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveResponse:(NSURLResponse *)response + completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { + _isRequestInProgress = false; + NSHTTPURLResponse *_httpURLResponse = (NSHTTPURLResponse *)response; + NSInteger statusCode = [_httpURLResponse statusCode]; + + if (statusCode == 403) { + completionHandler(NSURLSessionResponseAllow); + return; + } + + if (statusCode != kRCNFetchResponseHTTPStatusOk) { + [self->_settings updateRealtimeExponentialBackoffTime]; + [self pauseRealtimeStream]; + + if ([self isStatusCodeRetryable:statusCode]) { + [self retryHTTPConnection]; + } else { + NSError *error = [NSError + errorWithDomain:FIRRemoteConfigUpdateErrorDomain + code:FIRRemoteConfigUpdateErrorStreamError + userInfo:@{ + NSLocalizedDescriptionKey : + [NSString stringWithFormat:@"Unable to connect to the server. Try again in " + @"a few minutes. Http Status code: %@", + [@(statusCode) stringValue]] + }]; + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000021", @"Cannot establish connection. Error: %@", + error); + } + } else { + /// on success reset retry parameters + _remainingRetryCount = gMaxRetries; + [self->_settings setRealtimeRetryCount:0]; + } + + completionHandler(NSURLSessionResponseAllow); +} + +/// Delegate to handle data task completion +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + _isRequestInProgress = false; + if (error != nil && [error code] != NSURLErrorCancelled) { + [self->_settings updateRealtimeExponentialBackoffTime]; + } + [self pauseRealtimeStream]; + [self retryHTTPConnection]; +} + +/// Delegate to handle session invalidation +- (void)URLSession:(NSURLSession *)session didBecomeInvalidWithError:(NSError *)error { + if (!_isRequestInProgress) { + if (error != nil) { + [self->_settings updateRealtimeExponentialBackoffTime]; + } + [self pauseRealtimeStream]; + [self retryHTTPConnection]; + } +} + +#pragma mark - Top level methods + +- (void)beginRealtimeStream { + __weak __typeof(self) weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong __typeof(self) strongSelf = weakSelf; + + if (strongSelf->_settings.getRealtimeBackoffInterval > 0) { + [strongSelf retryHTTPConnection]; + return; + } + + if ([strongSelf canMakeConnection]) { + __weak __typeof(self) weakSelf = strongSelf; + [strongSelf createRequestBodyWithCompletion:^(NSData *_Nonnull requestBody) { + __strong __typeof(self) strongSelf = weakSelf; + if (!strongSelf) return; + strongSelf->_isRequestInProgress = true; + [strongSelf->_request setHTTPBody:requestBody]; + strongSelf->_dataTask = [strongSelf->_session dataTaskWithRequest:strongSelf->_request]; + [strongSelf->_dataTask resume]; + }]; + } + }); +} + +- (void)pauseRealtimeStream { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + if (strongSelf->_dataTask != nil) { + [strongSelf->_dataTask cancel]; + strongSelf->_dataTask = nil; + } + }); +} + +- (FIRConfigUpdateListenerRegistration *)addConfigUpdateListener: + (void (^_Nonnull)(FIRRemoteConfigUpdate *configUpdate, NSError *_Nullable error))listener { + if (listener == nil) { + return nil; + } + __block id listenerCopy = listener; + + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + [strongSelf->_listeners addObject:listenerCopy]; + [strongSelf beginRealtimeStream]; + }); + + return [[FIRConfigUpdateListenerRegistration alloc] initWithClient:self + completionHandler:listenerCopy]; +} + +- (void)removeConfigUpdateListener:(void (^_Nonnull)(FIRRemoteConfigUpdate *configUpdate, + NSError *_Nullable error))listener { + __weak RCNConfigRealtime *weakSelf = self; + dispatch_async(_realtimeLockQueue, ^{ + __strong RCNConfigRealtime *strongSelf = weakSelf; + [strongSelf->_listeners removeObject:listener]; + if (strongSelf->_listeners.count == 0) { + [strongSelf pauseRealtimeStream]; + } + }); +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m new file mode 100644 index 0000000..48e414e --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigSettings.m @@ -0,0 +1,537 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h" + +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigDBManager.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" +#import "FirebaseRemoteConfig/Sources/RCNDevice.h" +#import "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h" + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" + +static NSString *const kRCNGroupPrefix = @"frc.group."; +static NSString *const kRCNUserDefaultsKeyNamelastETag = @"lastETag"; +static NSString *const kRCNUserDefaultsKeyNameLastSuccessfulFetchTime = @"lastSuccessfulFetchTime"; +static NSString *const kRCNAnalyticsFirstOpenTimePropertyName = @"_fot"; +static const int kRCNExponentialBackoffMinimumInterval = 60 * 2; // 2 mins. +static const int kRCNExponentialBackoffMaximumInterval = 60 * 60 * 4; // 4 hours. + +@interface RCNConfigSettings () { + /// A list of successful fetch timestamps in seconds. + NSMutableArray *_successFetchTimes; + /// A list of failed fetch timestamps in seconds. + NSMutableArray *_failureFetchTimes; + /// Device conditions since last successful fetch from the backend. Device conditions including + /// app + /// version, iOS version, device localte, language, GMP project ID and Game project ID. Used for + /// determing whether to throttle. + NSMutableDictionary *_deviceContext; + /// Custom variables (aka App context digest). This is the pending custom variables request before + /// fetching. + NSMutableDictionary *_customVariables; + /// Cached internal metadata from internal metadata table. It contains customized information such + /// as HTTP connection timeout, HTTP read timeout, success/failure throttling rate and time + /// interval. Client has the default value of each parameters, they are only saved in + /// internalMetadata if they have been customize by developers. + NSMutableDictionary *_internalMetadata; + /// Last fetch status. + FIRRemoteConfigFetchStatus _lastFetchStatus; + /// Last fetch Error. + FIRRemoteConfigError _lastFetchError; + /// The time of last apply timestamp. + NSTimeInterval _lastApplyTimeInterval; + /// The time of last setDefaults timestamp. + NSTimeInterval _lastSetDefaultsTimeInterval; + /// The database manager. + RCNConfigDBManager *_DBManager; + // The namespace for this instance. + NSString *_FIRNamespace; + // The Google App ID of the configured FIRApp. + NSString *_googleAppID; + /// The user defaults manager scoped to this RC instance of FIRApp and namespace. + RCNUserDefaultsManager *_userDefaultsManager; + /// The timestamp of last eTag update. + NSTimeInterval _lastETagUpdateTime; +} +@end + +@implementation RCNConfigSettings + +- (instancetype)initWithDatabaseManager:(RCNConfigDBManager *)manager + namespace:(NSString *)FIRNamespace + firebaseAppName:(NSString *)appName + googleAppID:(NSString *)googleAppID { + self = [super init]; + if (self) { + _FIRNamespace = FIRNamespace; + _googleAppID = googleAppID; + _bundleIdentifier = [[NSBundle mainBundle] bundleIdentifier]; + if (!_bundleIdentifier) { + FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000038", + @"Main bundle identifier is missing. Remote Config might not work properly."); + _bundleIdentifier = @""; + } + _minimumFetchInterval = RCNDefaultMinimumFetchInterval; + _deviceContext = [[NSMutableDictionary alloc] init]; + _customVariables = [[NSMutableDictionary alloc] init]; + _successFetchTimes = [[NSMutableArray alloc] init]; + _failureFetchTimes = [[NSMutableArray alloc] init]; + _DBManager = manager; + + _internalMetadata = [[_DBManager loadInternalMetadataTable] mutableCopy]; + if (!_internalMetadata) { + _internalMetadata = [[NSMutableDictionary alloc] init]; + } + _userDefaultsManager = [[RCNUserDefaultsManager alloc] initWithAppName:appName + bundleID:_bundleIdentifier + namespace:_FIRNamespace]; + + // Check if the config database is new. If so, clear the configs saved in userDefaults. + if ([_DBManager isNewDatabase]) { + FIRLogNotice(kFIRLoggerRemoteConfig, @"I-RCN000072", + @"New config database created. Resetting user defaults."); + [_userDefaultsManager resetUserDefaults]; + } + + _isFetchInProgress = NO; + _lastFetchedTemplateVersion = [_userDefaultsManager lastFetchedTemplateVersion]; + _lastActiveTemplateVersion = [_userDefaultsManager lastActiveTemplateVersion]; + _realtimeExponentialBackoffRetryInterval = + [_userDefaultsManager currentRealtimeThrottlingRetryIntervalSeconds]; + _realtimeExponentialBackoffThrottleEndTime = [_userDefaultsManager realtimeThrottleEndTime]; + _realtimeRetryCount = [_userDefaultsManager realtimeRetryCount]; + } + return self; +} + +#pragma mark - read from / update userDefaults +- (NSString *)lastETag { + return [_userDefaultsManager lastETag]; +} + +- (void)setLastETag:(NSString *)lastETag { + [self setLastETagUpdateTime:[[NSDate date] timeIntervalSince1970]]; + [_userDefaultsManager setLastETag:lastETag]; +} + +- (void)setLastETagUpdateTime:(NSTimeInterval)lastETagUpdateTime { + [_userDefaultsManager setLastETagUpdateTime:lastETagUpdateTime]; +} + +- (NSTimeInterval)lastFetchTimeInterval { + return _userDefaultsManager.lastFetchTime; +} + +- (NSTimeInterval)lastETagUpdateTime { + return _userDefaultsManager.lastETagUpdateTime; +} + +// TODO: Update logic for app extensions as required. +- (void)updateLastFetchTimeInterval:(NSTimeInterval)lastFetchTimeInterval { + _userDefaultsManager.lastFetchTime = lastFetchTimeInterval; +} + +#pragma mark - load from DB +- (NSDictionary *)loadConfigFromMetadataTable { + NSDictionary *metadata = [[_DBManager loadMetadataWithBundleIdentifier:_bundleIdentifier + namespace:_FIRNamespace] copy]; + if (metadata) { + // TODO: Remove (all metadata in general) once ready to + // migrate to user defaults completely. + if (metadata[RCNKeyDeviceContext]) { + self->_deviceContext = [metadata[RCNKeyDeviceContext] mutableCopy]; + } + if (metadata[RCNKeyAppContext]) { + self->_customVariables = [metadata[RCNKeyAppContext] mutableCopy]; + } + if (metadata[RCNKeySuccessFetchTime]) { + self->_successFetchTimes = [metadata[RCNKeySuccessFetchTime] mutableCopy]; + } + if (metadata[RCNKeyFailureFetchTime]) { + self->_failureFetchTimes = [metadata[RCNKeyFailureFetchTime] mutableCopy]; + } + if (metadata[RCNKeyLastFetchStatus]) { + self->_lastFetchStatus = + (FIRRemoteConfigFetchStatus)[metadata[RCNKeyLastFetchStatus] intValue]; + } + if (metadata[RCNKeyLastFetchError]) { + self->_lastFetchError = (FIRRemoteConfigError)[metadata[RCNKeyLastFetchError] intValue]; + } + if (metadata[RCNKeyLastApplyTime]) { + self->_lastApplyTimeInterval = [metadata[RCNKeyLastApplyTime] doubleValue]; + } + if (metadata[RCNKeyLastFetchStatus]) { + self->_lastSetDefaultsTimeInterval = [metadata[RCNKeyLastSetDefaultsTime] doubleValue]; + } + } + return metadata; +} + +#pragma mark - update DB/cached + +// Update internal metadata content to cache and DB. +- (void)updateInternalContentWithResponse:(NSDictionary *)response { + // Remove all the keys with current package name. + [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier + namespace:_FIRNamespace + isInternalDB:YES]; + + for (NSString *key in _internalMetadata.allKeys) { + if ([key hasPrefix:_bundleIdentifier]) { + [_internalMetadata removeObjectForKey:key]; + } + } + + for (NSString *entry in response) { + NSData *val = [response[entry] dataUsingEncoding:NSUTF8StringEncoding]; + NSArray *values = @[ entry, val ]; + _internalMetadata[entry] = response[entry]; + [self updateInternalMetadataTableWithValues:values]; + } +} + +- (void)updateInternalMetadataTableWithValues:(NSArray *)values { + [_DBManager insertInternalMetadataTableWithValues:values completionHandler:nil]; +} + +/// If the last fetch was not successful, update the (exponential backoff) period that we wait until +/// fetching again. Any subsequent fetch requests will be checked and allowed only if past this +/// throttle end time. +- (void)updateExponentialBackoffTime { + // If not in exponential backoff mode, reset the retry interval. + if (_lastFetchStatus == FIRRemoteConfigFetchStatusSuccess) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000057", + @"Throttling: Entering exponential backoff mode."); + _exponentialBackoffRetryInterval = kRCNExponentialBackoffMinimumInterval; + } else { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000057", + @"Throttling: Updating throttling interval."); + // Double the retry interval until we hit the truncated exponential backoff. More info here: + // https://cloud.google.com/storage/docs/exponential-backoff + _exponentialBackoffRetryInterval = + ((_exponentialBackoffRetryInterval * 2) < kRCNExponentialBackoffMaximumInterval) + ? _exponentialBackoffRetryInterval * 2 + : _exponentialBackoffRetryInterval; + } + + // Randomize the next retry interval. + int randomPlusMinusInterval = ((arc4random() % 2) == 0) ? -1 : 1; + NSTimeInterval randomizedRetryInterval = + _exponentialBackoffRetryInterval + + (0.5 * _exponentialBackoffRetryInterval * randomPlusMinusInterval); + _exponentialBackoffThrottleEndTime = + [[NSDate date] timeIntervalSince1970] + randomizedRetryInterval; +} + +/// If the last Realtime stream attempt was not successful, update the (exponential backoff) period +/// that we wait until trying again. Any subsequent Realtime requests will be checked and allowed +/// only if past this throttle end time. +- (void)updateRealtimeExponentialBackoffTime { + // If there was only one stream attempt before, reset the retry interval. + if (_realtimeRetryCount == 0) { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000058", + @"Throttling: Entering exponential Realtime backoff mode."); + _realtimeExponentialBackoffRetryInterval = kRCNExponentialBackoffMinimumInterval; + } else { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000058", + @"Throttling: Updating Realtime throttling interval."); + // Double the retry interval until we hit the truncated exponential backoff. More info here: + // https://cloud.google.com/storage/docs/exponential-backoff + _realtimeExponentialBackoffRetryInterval = + ((_realtimeExponentialBackoffRetryInterval * 2) < kRCNExponentialBackoffMaximumInterval) + ? _realtimeExponentialBackoffRetryInterval * 2 + : _realtimeExponentialBackoffRetryInterval; + } + + // Randomize the next retry interval. + int randomPlusMinusInterval = ((arc4random() % 2) == 0) ? -1 : 1; + NSTimeInterval randomizedRetryInterval = + _realtimeExponentialBackoffRetryInterval + + (0.5 * _realtimeExponentialBackoffRetryInterval * randomPlusMinusInterval); + _realtimeExponentialBackoffThrottleEndTime = + [[NSDate date] timeIntervalSince1970] + randomizedRetryInterval; + + [_userDefaultsManager setRealtimeThrottleEndTime:_realtimeExponentialBackoffThrottleEndTime]; + [_userDefaultsManager + setCurrentRealtimeThrottlingRetryIntervalSeconds:_realtimeExponentialBackoffRetryInterval]; +} + +- (void)setRealtimeRetryCount:(int)realtimeRetryCount { + _realtimeRetryCount = realtimeRetryCount; + [_userDefaultsManager setRealtimeRetryCount:_realtimeRetryCount]; +} + +- (NSTimeInterval)getRealtimeBackoffInterval { + NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; + return _realtimeExponentialBackoffThrottleEndTime - now; +} + +- (void)updateMetadataWithFetchSuccessStatus:(BOOL)fetchSuccess + templateVersion:(NSString *)templateVersion { + FIRLogDebug(kFIRLoggerRemoteConfig, @"I-RCN000056", @"Updating metadata with fetch result."); + [self updateFetchTimeWithSuccessFetch:fetchSuccess]; + _lastFetchStatus = + fetchSuccess ? FIRRemoteConfigFetchStatusSuccess : FIRRemoteConfigFetchStatusFailure; + _lastFetchError = fetchSuccess ? FIRRemoteConfigErrorUnknown : FIRRemoteConfigErrorInternalError; + if (fetchSuccess) { + [self updateLastFetchTimeInterval:[[NSDate date] timeIntervalSince1970]]; + // Note: We expect the googleAppID to always be available. + _deviceContext = FIRRemoteConfigDeviceContextWithProjectIdentifier(_googleAppID); + _lastFetchedTemplateVersion = templateVersion; + [_userDefaultsManager setLastFetchedTemplateVersion:templateVersion]; + } + + [self updateMetadataTable]; +} + +- (void)updateFetchTimeWithSuccessFetch:(BOOL)isSuccessfulFetch { + NSTimeInterval epochTimeInterval = [[NSDate date] timeIntervalSince1970]; + if (isSuccessfulFetch) { + [_successFetchTimes addObject:@(epochTimeInterval)]; + } else { + [_failureFetchTimes addObject:@(epochTimeInterval)]; + } +} + +- (void)updateMetadataTable { + [_DBManager deleteRecordWithBundleIdentifier:_bundleIdentifier + namespace:_FIRNamespace + isInternalDB:NO]; + NSError *error; + // Objects to be serialized cannot be invalid. + if (!_bundleIdentifier) { + return; + } + if (![NSJSONSerialization isValidJSONObject:_customVariables]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000028", + @"Invalid custom variables to be serialized."); + return; + } + if (![NSJSONSerialization isValidJSONObject:_deviceContext]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000029", + @"Invalid device context to be serialized."); + return; + } + + if (![NSJSONSerialization isValidJSONObject:_successFetchTimes]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000031", + @"Invalid success fetch times to be serialized."); + return; + } + if (![NSJSONSerialization isValidJSONObject:_failureFetchTimes]) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000032", + @"Invalid failure fetch times to be serialized."); + return; + } + NSData *serializedAppContext = [NSJSONSerialization dataWithJSONObject:_customVariables + options:NSJSONWritingPrettyPrinted + error:&error]; + NSData *serializedDeviceContext = + [NSJSONSerialization dataWithJSONObject:_deviceContext + options:NSJSONWritingPrettyPrinted + error:&error]; + // The digestPerNamespace is not used and only meant for backwards DB compatibility. + NSData *serializedDigestPerNamespace = + [NSJSONSerialization dataWithJSONObject:@{} options:NSJSONWritingPrettyPrinted error:&error]; + NSData *serializedSuccessTime = [NSJSONSerialization dataWithJSONObject:_successFetchTimes + options:NSJSONWritingPrettyPrinted + error:&error]; + NSData *serializedFailureTime = [NSJSONSerialization dataWithJSONObject:_failureFetchTimes + options:NSJSONWritingPrettyPrinted + error:&error]; + + if (!serializedDigestPerNamespace || !serializedDeviceContext || !serializedAppContext || + !serializedSuccessTime || !serializedFailureTime) { + return; + } + + NSDictionary *columnNameToValue = @{ + RCNKeyBundleIdentifier : _bundleIdentifier, + RCNKeyNamespace : _FIRNamespace, + RCNKeyFetchTime : @(self.lastFetchTimeInterval), + RCNKeyDigestPerNamespace : serializedDigestPerNamespace, + RCNKeyDeviceContext : serializedDeviceContext, + RCNKeyAppContext : serializedAppContext, + RCNKeySuccessFetchTime : serializedSuccessTime, + RCNKeyFailureFetchTime : serializedFailureTime, + RCNKeyLastFetchStatus : [NSString stringWithFormat:@"%ld", (long)_lastFetchStatus], + RCNKeyLastFetchError : [NSString stringWithFormat:@"%ld", (long)_lastFetchError], + RCNKeyLastApplyTime : @(_lastApplyTimeInterval), + RCNKeyLastSetDefaultsTime : @(_lastSetDefaultsTimeInterval) + }; + + [_DBManager insertMetadataTableWithValues:columnNameToValue completionHandler:nil]; +} + +- (void)updateLastActiveTemplateVersion { + _lastActiveTemplateVersion = _lastFetchedTemplateVersion; + [_userDefaultsManager setLastActiveTemplateVersion:_lastActiveTemplateVersion]; +} + +#pragma mark - fetch request + +/// Returns a fetch request with the latest device and config change. +/// Whenever user issues a fetch api call, collect the latest request. +- (NSString *)nextRequestWithUserProperties:(NSDictionary *)userProperties { + // Note: We only set user properties as mentioned in the new REST API Design doc + NSString *ret = [NSString stringWithFormat:@"{"]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@"app_instance_id:'%@'", + _configInstallationsIdentifier]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_instance_id_token:'%@'", + _configInstallationsToken]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_id:'%@'", _googleAppID]]; + + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", country_code:'%@'", + FIRRemoteConfigDeviceCountry()]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", language_code:'%@'", + FIRRemoteConfigDeviceLocale()]]; + ret = [ret + stringByAppendingString:[NSString stringWithFormat:@", platform_version:'%@'", + [GULAppEnvironmentUtil systemVersion]]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", time_zone:'%@'", + FIRRemoteConfigTimezone()]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", package_name:'%@'", + _bundleIdentifier]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_version:'%@'", + FIRRemoteConfigAppVersion()]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", app_build:'%@'", + FIRRemoteConfigAppBuildVersion()]]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", sdk_version:'%@'", + FIRRemoteConfigPodVersion()]]; + + if (userProperties && userProperties.count > 0) { + NSError *error; + + // Extract first open time from user properties and send as a separate field + NSNumber *firstOpenTime = userProperties[kRCNAnalyticsFirstOpenTimePropertyName]; + NSMutableDictionary *remainingUserProperties = [userProperties mutableCopy]; + if (firstOpenTime != nil) { + NSDate *date = [NSDate dateWithTimeIntervalSince1970:([firstOpenTime longValue] / 1000)]; + NSISO8601DateFormatter *formatter = [[NSISO8601DateFormatter alloc] init]; + NSString *firstOpenTimeISOString = [formatter stringFromDate:date]; + ret = [ret stringByAppendingString:[NSString stringWithFormat:@", first_open_time:'%@'", + firstOpenTimeISOString]]; + + [remainingUserProperties removeObjectForKey:kRCNAnalyticsFirstOpenTimePropertyName]; + } + if (remainingUserProperties.count > 0) { + NSData *jsonData = [NSJSONSerialization dataWithJSONObject:remainingUserProperties + options:0 + error:&error]; + if (!error) { + ret = [ret + stringByAppendingString:[NSString + stringWithFormat:@", analytics_user_properties:%@", + [[NSString alloc] + initWithData:jsonData + encoding:NSUTF8StringEncoding]]]; + } + } + } + ret = [ret stringByAppendingString:@"}"]; + return ret; +} + +#pragma mark - getter/setter + +- (void)setLastFetchError:(FIRRemoteConfigError)lastFetchError { + if (_lastFetchError != lastFetchError) { + _lastFetchError = lastFetchError; + [_DBManager updateMetadataWithOption:RCNUpdateOptionFetchStatus + namespace:_FIRNamespace + values:@[ @(_lastFetchStatus), @(_lastFetchError) ] + completionHandler:nil]; + } +} + +- (NSArray *)successFetchTimes { + return [_successFetchTimes copy]; +} + +- (NSArray *)failureFetchTimes { + return [_failureFetchTimes copy]; +} + +- (NSDictionary *)customVariables { + return [_customVariables copy]; +} + +- (NSDictionary *)internalMetadata { + return [_internalMetadata copy]; +} + +- (NSDictionary *)deviceContext { + return [_deviceContext copy]; +} + +- (void)setCustomVariables:(NSDictionary *)customVariables { + _customVariables = [[NSMutableDictionary alloc] initWithDictionary:customVariables]; + [self updateMetadataTable]; +} + +- (void)setMinimumFetchInterval:(NSTimeInterval)minimumFetchInterval { + if (minimumFetchInterval < 0) { + _minimumFetchInterval = 0; + } else { + _minimumFetchInterval = minimumFetchInterval; + } +} + +- (void)setFetchTimeout:(NSTimeInterval)fetchTimeout { + if (fetchTimeout <= 0) { + _fetchTimeout = RCNHTTPDefaultConnectionTimeout; + } else { + _fetchTimeout = fetchTimeout; + } +} + +- (void)setLastApplyTimeInterval:(NSTimeInterval)lastApplyTimestamp { + _lastApplyTimeInterval = lastApplyTimestamp; + [_DBManager updateMetadataWithOption:RCNUpdateOptionApplyTime + namespace:_FIRNamespace + values:@[ @(lastApplyTimestamp) ] + completionHandler:nil]; +} + +- (void)setLastSetDefaultsTimeInterval:(NSTimeInterval)lastSetDefaultsTimestamp { + _lastSetDefaultsTimeInterval = lastSetDefaultsTimestamp; + [_DBManager updateMetadataWithOption:RCNUpdateOptionDefaultTime + namespace:_FIRNamespace + values:@[ @(lastSetDefaultsTimestamp) ] + completionHandler:nil]; +} + +#pragma mark Throttling + +- (BOOL)hasMinimumFetchIntervalElapsed:(NSTimeInterval)minimumFetchInterval { + if (self.lastFetchTimeInterval == 0) return YES; + + // Check if last config fetch is within minimum fetch interval in seconds. + NSTimeInterval diffInSeconds = [[NSDate date] timeIntervalSince1970] - self.lastFetchTimeInterval; + return diffInSeconds > minimumFetchInterval; +} + +- (BOOL)shouldThrottle { + NSTimeInterval now = [[NSDate date] timeIntervalSince1970]; + return ((self.lastFetchTimeInterval > 0) && + (_lastFetchStatus != FIRRemoteConfigFetchStatusSuccess) && + (_exponentialBackoffThrottleEndTime - now > 0)); +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h new file mode 100644 index 0000000..5c9ef0c --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h @@ -0,0 +1,25 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +@interface FIRRemoteConfigValue () +@property(nonatomic, readwrite, assign) FIRRemoteConfigSource source; + +/// Designated initializer. +- (instancetype)initWithData:(NSData *)data + source:(FIRRemoteConfigSource)source NS_DESIGNATED_INITIALIZER; +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m new file mode 100644 index 0000000..e64295b --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNConstants3P.m @@ -0,0 +1,21 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" + +/// Firebase Remote Config service default namespace. +/// TODO(doudounan): Change to use this namespace defined in RemoteConfigInterop. +NSString *const FIRNamespaceGoogleMobilePlatform = @"firebase"; diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h new file mode 100644 index 0000000..15697e3 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.h @@ -0,0 +1,57 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +typedef NS_ENUM(NSInteger, RCNDeviceModel) { + RCNDeviceModelOther, + RCNDeviceModelPhone, + RCNDeviceModelTablet, + RCNDeviceModelTV, + RCNDeviceModelGlass, + RCNDeviceModelCar, + RCNDeviceModelWearable, +}; + +/// CocoaPods SDK version +NSString *FIRRemoteConfigPodVersion(void); + +/// App version. +NSString *FIRRemoteConfigAppVersion(void); + +/// App build version +NSString *FIRRemoteConfigAppBuildVersion(void); + +/// Device country, in lowercase. +NSString *FIRRemoteConfigDeviceCountry(void); + +/// Device locale, in language_country format, e.g. en_US. +NSString *FIRRemoteConfigDeviceLocale(void); + +/// Device subtype. +RCNDeviceModel FIRRemoteConfigDeviceSubtype(void); + +/// Device timezone. +NSString *FIRRemoteConfigTimezone(void); + +/// Update device context to the given dictionary. +NSMutableDictionary *FIRRemoteConfigDeviceContextWithProjectIdentifier( + NSString *GMPProjectIdentifier); + +/// Check whether client has changed device context, including app version, +/// iOS version, device country etc. This is used to determine whether to throttle. +BOOL FIRRemoteConfigHasDeviceContextChanged(NSDictionary *deviceContext, + NSString *GMPProjectIdentifier); diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m new file mode 100644 index 0000000..48cda11 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNDevice.m @@ -0,0 +1,241 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNDevice.h" + +#import + +#import +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/Private/RCNConfigSettings.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" + +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x + +static NSString *const RCNDeviceContextKeyVersion = @"app_version"; +static NSString *const RCNDeviceContextKeyBuild = @"app_build"; +static NSString *const RCNDeviceContextKeyOSVersion = @"os_version"; +static NSString *const RCNDeviceContextKeyDeviceLocale = @"device_locale"; +static NSString *const RCNDeviceContextKeyLocaleLanguage = @"locale_language"; +static NSString *const RCNDeviceContextKeyGMPProjectIdentifier = @"GMP_project_Identifier"; + +NSString *FIRRemoteConfigAppVersion(void) { + return [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"]; +} + +NSString *FIRRemoteConfigAppBuildVersion(void) { + return [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"]; +} + +NSString *FIRRemoteConfigPodVersion(void) { + return FIRFirebaseVersion(); +} + +RCNDeviceModel FIRRemoteConfigDeviceSubtype(void) { + NSString *model = [GULAppEnvironmentUtil deviceModel]; + if ([model hasPrefix:@"iPhone"]) { + return RCNDeviceModelPhone; + } + if ([model isEqualToString:@"iPad"]) { + return RCNDeviceModelTablet; + } + return RCNDeviceModelOther; +} + +NSString *FIRRemoteConfigDeviceCountry(void) { + return [[[NSLocale currentLocale] objectForKey:NSLocaleCountryCode] lowercaseString]; +} + +NSDictionary *FIRRemoteConfigFirebaseLocaleMap(void) { + return @{ + // Albanian + @"sq" : @[ @"sq_AL" ], + // Belarusian + @"be" : @[ @"be_BY" ], + // Bulgarian + @"bg" : @[ @"bg_BG" ], + // Catalan + @"ca" : @[ @"ca", @"ca_ES" ], + // Croatian + @"hr" : @[ @"hr", @"hr_HR" ], + // Czech + @"cs" : @[ @"cs", @"cs_CZ" ], + // Danish + @"da" : @[ @"da", @"da_DK" ], + // Estonian + @"et" : @[ @"et_EE" ], + // Finnish + @"fi" : @[ @"fi", @"fi_FI" ], + // Hebrew + @"he" : @[ @"he", @"iw_IL" ], + // Hindi + @"hi" : @[ @"hi_IN" ], + // Hungarian + @"hu" : @[ @"hu", @"hu_HU" ], + // Icelandic + @"is" : @[ @"is_IS" ], + // Indonesian + @"id" : @[ @"id", @"in_ID", @"id_ID" ], + // Irish + @"ga" : @[ @"ga_IE" ], + // Korean + @"ko" : @[ @"ko", @"ko_KR", @"ko-KR" ], + // Latvian + @"lv" : @[ @"lv_LV" ], + // Lithuanian + @"lt" : @[ @"lt_LT" ], + // Macedonian + @"mk" : @[ @"mk_MK" ], + // Malay + @"ms" : @[ @"ms_MY" ], + // Maltese + @"mt" : @[ @"mt_MT" ], + // Polish + @"pl" : @[ @"pl", @"pl_PL", @"pl-PL" ], + // Romanian + @"ro" : @[ @"ro", @"ro_RO" ], + // Russian + @"ru" : @[ @"ru_RU", @"ru", @"ru_BY", @"ru_KZ", @"ru-RU" ], + // Slovak + @"sk" : @[ @"sk", @"sk_SK" ], + // Slovenian + @"sl" : @[ @"sl_SI" ], + // Swedish + @"sv" : @[ @"sv", @"sv_SE", @"sv-SE" ], + // Turkish + @"tr" : @[ @"tr", @"tr-TR", @"tr_TR" ], + // Ukrainian + @"uk" : @[ @"uk", @"uk_UA" ], + // Vietnamese + @"vi" : @[ @"vi", @"vi_VN" ], + // The following are groups of locales or locales that sub-divide a + // language). + // Arabic + @"ar" : @[ + @"ar", @"ar_DZ", @"ar_BH", @"ar_EG", @"ar_IQ", @"ar_JO", @"ar_KW", + @"ar_LB", @"ar_LY", @"ar_MA", @"ar_OM", @"ar_QA", @"ar_SA", @"ar_SD", + @"ar_SY", @"ar_TN", @"ar_AE", @"ar_YE", @"ar_GB", @"ar-IQ", @"ar_US" + ], + // Simplified Chinese + @"zh_Hans" : @[ @"zh_CN", @"zh_SG", @"zh-Hans" ], + // Traditional Chinese + // Remove zh_HK until console added to the list. Otherwise client sends + // zh_HK and server/console falls back to zh. + // @"zh_Hant" : @[ @"zh_HK", @"zh_TW", @"zh-Hant", @"zh-HK", @"zh-TW" ], + @"zh_Hant" : @[ @"zh_TW", @"zh-Hant", @"zh-TW" ], + // Dutch + @"nl" : @[ @"nl", @"nl_BE", @"nl_NL", @"nl-NL" ], + // English + @"en" : @[ + @"en", @"en_AU", @"en_CA", @"en_IN", @"en_IE", @"en_MT", @"en_NZ", @"en_PH", + @"en_SG", @"en_ZA", @"en_GB", @"en_US", @"en_AE", @"en-AE", @"en_AS", @"en-AU", + @"en_BD", @"en-CA", @"en_EG", @"en_ES", @"en_GB", @"en-GB", @"en_HK", @"en_ID", + @"en-IN", @"en_NG", @"en-PH", @"en_PK", @"en-SG", @"en-US" + ], + // French + @"fr" : + @[ @"fr", @"fr_BE", @"fr_CA", @"fr_FR", @"fr_LU", @"fr_CH", @"fr-CA", @"fr-FR", @"fr_MA" ], + // German + @"de" : @[ @"de", @"de_AT", @"de_DE", @"de_LU", @"de_CH", @"de-DE" ], + // Greek + @"el" : @[ @"el", @"el_CY", @"el_GR" ], + // Italian + @"it" : @[ @"it", @"it_IT", @"it_CH", @"it-IT" ], + // Japanese + @"ja" : @[ @"ja", @"ja_JP", @"ja_JP_JP", @"ja-JP" ], + // Norwegian + @"no" : @[ @"nb", @"no_NO", @"no_NO_NY", @"nb_NO" ], + // Brazilian Portuguese + @"pt_BR" : @[ @"pt_BR", @"pt-BR" ], + // European Portuguese + @"pt_PT" : @[ @"pt", @"pt_PT", @"pt-PT" ], + // Serbian + @"sr" : @[ @"sr_BA", @"sr_ME", @"sr_RS", @"sr_Latn_BA", @"sr_Latn_ME", @"sr_Latn_RS" ], + // European Spanish + @"es_ES" : @[ @"es", @"es_ES", @"es-ES" ], + // Mexican Spanish + @"es_MX" : @[ @"es-MX", @"es_MX", @"es_US", @"es-US" ], + // Latin American Spanish + @"es_419" : @[ + @"es_AR", @"es_BO", @"es_CL", @"es_CO", @"es_CR", @"es_DO", @"es_EC", + @"es_SV", @"es_GT", @"es_HN", @"es_NI", @"es_PA", @"es_PY", @"es_PE", + @"es_PR", @"es_UY", @"es_VE", @"es-AR", @"es-CL", @"es-CO" + ], + // Thai + @"th" : @[ @"th", @"th_TH", @"th_TH_TH" ], + }; +} + +NSArray *FIRRemoteConfigAppManagerLocales(void) { + NSMutableArray *locales = [NSMutableArray array]; + NSDictionary *localesMap = FIRRemoteConfigFirebaseLocaleMap(); + for (NSString *key in localesMap) { + [locales addObjectsFromArray:localesMap[key]]; + } + return locales; +} +NSString *FIRRemoteConfigDeviceLocale(void) { + NSArray *locales = FIRRemoteConfigAppManagerLocales(); + NSArray *preferredLocalizations = + [NSBundle preferredLocalizationsFromArray:locales + forPreferences:[NSLocale preferredLanguages]]; + NSString *legalDocsLanguage = [preferredLocalizations firstObject]; + // Use en as the default language + return legalDocsLanguage ? legalDocsLanguage : @"en"; +} + +NSString *FIRRemoteConfigTimezone(void) { + NSTimeZone *timezone = [NSTimeZone systemTimeZone]; + return timezone.name; +} + +NSMutableDictionary *FIRRemoteConfigDeviceContextWithProjectIdentifier( + NSString *GMPProjectIdentifier) { + NSMutableDictionary *deviceContext = [[NSMutableDictionary alloc] init]; + deviceContext[RCNDeviceContextKeyVersion] = FIRRemoteConfigAppVersion(); + deviceContext[RCNDeviceContextKeyBuild] = FIRRemoteConfigAppBuildVersion(); + deviceContext[RCNDeviceContextKeyOSVersion] = [GULAppEnvironmentUtil systemVersion]; + deviceContext[RCNDeviceContextKeyDeviceLocale] = FIRRemoteConfigDeviceLocale(); + // NSDictionary setObjectForKey will fail if there's no GMP project ID, must check ahead. + if (GMPProjectIdentifier) { + deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] = GMPProjectIdentifier; + } + return deviceContext; +} + +BOOL FIRRemoteConfigHasDeviceContextChanged(NSDictionary *deviceContext, + NSString *GMPProjectIdentifier) { + if (![deviceContext[RCNDeviceContextKeyVersion] isEqual:FIRRemoteConfigAppVersion()]) { + return YES; + } + if (![deviceContext[RCNDeviceContextKeyBuild] isEqual:FIRRemoteConfigAppBuildVersion()]) { + return YES; + } + if (![deviceContext[RCNDeviceContextKeyOSVersion] + isEqual:[GULAppEnvironmentUtil systemVersion]]) { + return YES; + } + if (![deviceContext[RCNDeviceContextKeyDeviceLocale] isEqual:FIRRemoteConfigDeviceLocale()]) { + return YES; + } + // GMP project id is optional. + if (deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] && + ![deviceContext[RCNDeviceContextKeyGMPProjectIdentifier] isEqual:GMPProjectIdentifier]) { + return YES; + } + return NO; +} diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.h new file mode 100644 index 0000000..556eb0f --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.h @@ -0,0 +1,56 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "Interop/Analytics/Public/FIRAnalyticsInterop.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kAnalyticsOriginPersonalization = @"fp"; + +static NSString *const kExternalEvent = @"personalization_assignment"; +static NSString *const kExternalRcParameterParam = @"arm_key"; +static NSString *const kExternalArmValueParam = @"arm_value"; +static NSString *const kPersonalizationId = @"personalizationId"; +static NSString *const kExternalPersonalizationIdParam = @"personalization_id"; +static NSString *const kArmIndex = @"armIndex"; +static NSString *const kExternalArmIndexParam = @"arm_index"; +static NSString *const kGroup = @"group"; +static NSString *const kExternalGroupParam = @"group"; + +static NSString *const kInternalEvent = @"_fpc"; +static NSString *const kChoiceId = @"choiceId"; +static NSString *const kInternalChoiceIdParam = @"_fpid"; + +@interface RCNPersonalization : NSObject + +/// Analytics connector +@property(nonatomic, strong) id _Nullable analytics; + +@property(atomic, strong) NSMutableDictionary *loggedChoiceIds; + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer. +- (instancetype)initWithAnalytics:(id _Nullable)analytics + NS_DESIGNATED_INITIALIZER; + +/// Called when an arm is pulled from Remote Config. If the arm is personalized, log information to +/// Google in another thread. +- (void)logArmActive:(NSString *)rcParameter config:(NSDictionary *)config; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.m new file mode 100644 index 0000000..0bcb411 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNPersonalization.m @@ -0,0 +1,72 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNPersonalization.h" + +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigValue_Internal.h" + +@implementation RCNPersonalization + +- (instancetype)initWithAnalytics:(id _Nullable)analytics { + self = [super init]; + if (self) { + self->_analytics = analytics; + self->_loggedChoiceIds = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)logArmActive:(NSString *)rcParameter config:(NSDictionary *)config { + NSDictionary *ids = config[RCNFetchResponseKeyPersonalizationMetadata]; + NSDictionary *values = config[RCNFetchResponseKeyEntries]; + if (ids.count < 1 || values.count < 1 || !values[rcParameter]) { + return; + } + + NSDictionary *metadata = ids[rcParameter]; + if (!metadata) { + return; + } + + NSString *choiceId = metadata[kChoiceId]; + if (choiceId == nil) { + return; + } + + // Listeners like logArmActive() are dispatched to a serial queue, so loggedChoiceIds should + // contain any previously logged RC parameter / choice ID pairs. + if (self->_loggedChoiceIds[rcParameter] == choiceId) { + return; + } + self->_loggedChoiceIds[rcParameter] = choiceId; + + [self->_analytics logEventWithOrigin:kAnalyticsOriginPersonalization + name:kExternalEvent + parameters:@{ + kExternalRcParameterParam : rcParameter, + kExternalArmValueParam : values[rcParameter].stringValue, + kExternalPersonalizationIdParam : metadata[kPersonalizationId], + kExternalArmIndexParam : metadata[kArmIndex], + kExternalGroupParam : metadata[kGroup] + }]; + + [self->_analytics logEventWithOrigin:kAnalyticsOriginPersonalization + name:kInternalEvent + parameters:@{kInternalChoiceIdParam : choiceId}]; +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h new file mode 100644 index 0000000..b235f21 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h @@ -0,0 +1,66 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface RCNUserDefaultsManager : NSObject + +/// The last eTag received from the backend. +@property(nonatomic, assign) NSString *lastETag; +/// The time of the last eTag update. +@property(nonatomic, assign) NSTimeInterval lastETagUpdateTime; +/// The time of the last successful fetch. +@property(nonatomic, assign) NSTimeInterval lastFetchTime; +/// The time of the last successful fetch. +@property(nonatomic, assign) NSString *lastFetchStatus; +/// Boolean indicating if the last (one or more) fetch(es) was/were unsuccessful, in which case we +/// are in an exponential backoff mode. +@property(nonatomic, assign) BOOL isClientThrottledWithExponentialBackoff; +/// Time when the next request can be made while being throttled. +@property(nonatomic, assign) NSTimeInterval throttleEndTime; +/// The retry interval increases exponentially for cumulative fetch failures. Refer to +/// go/rc-client-throttling for details. +@property(nonatomic, assign) NSTimeInterval currentThrottlingRetryIntervalSeconds; +/// Time when the next request can be made while being throttled. +@property(nonatomic, assign) NSTimeInterval realtimeThrottleEndTime; +/// The retry interval increases exponentially for cumulative Realtime failures. Refer to +/// go/rc-client-throttling for details. +@property(nonatomic, assign) NSTimeInterval currentRealtimeThrottlingRetryIntervalSeconds; +/// Realtime retry count. +@property(nonatomic, assign) int realtimeRetryCount; +/// Last fetched template version. +@property(nonatomic, assign) NSString *lastFetchedTemplateVersion; +/// Last active template version. +@property(nonatomic, assign) NSString *lastActiveTemplateVersion; + +/// Designated initializer. +- (instancetype)initWithAppName:(NSString *)appName + bundleID:(NSString *)bundleIdentifier + namespace:(NSString *)firebaseNamespace NS_DESIGNATED_INITIALIZER; + +// NOLINTBEGIN +/// Use `initWithAppName:bundleID:namespace:` instead. +- (instancetype)init + __attribute__((unavailable("Use `initWithAppName:bundleID:namespace:` instead."))); +// NOLINTEND + +/// Delete all saved userdefaults for this instance. +- (void)resetUserDefaults; +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m new file mode 100644 index 0000000..880a215 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.m @@ -0,0 +1,313 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "FirebaseRemoteConfig/Sources/RCNUserDefaultsManager.h" +#import "FirebaseCore/Extension/FirebaseCoreInternal.h" +#import "FirebaseRemoteConfig/Sources/Public/FirebaseRemoteConfig/FIRRemoteConfig.h" +#import "FirebaseRemoteConfig/Sources/RCNConfigConstants.h" + +static NSString *const kRCNGroupPrefix = @"group"; +static NSString *const kRCNGroupSuffix = @"firebase"; +static NSString *const kRCNUserDefaultsKeyNamelastETag = @"lastETag"; +static NSString *const kRCNUserDefaultsKeyNamelastETagUpdateTime = @"lastETagUpdateTime"; +static NSString *const kRCNUserDefaultsKeyNameLastSuccessfulFetchTime = @"lastSuccessfulFetchTime"; +static NSString *const kRCNUserDefaultsKeyNamelastFetchStatus = @"lastFetchStatus"; +static NSString *const kRCNUserDefaultsKeyNameIsClientThrottled = + @"isClientThrottledWithExponentialBackoff"; +static NSString *const kRCNUserDefaultsKeyNameThrottleEndTime = @"throttleEndTime"; +static NSString *const kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval = + @"currentThrottlingRetryInterval"; +static NSString *const kRCNUserDefaultsKeyNameRealtimeThrottleEndTime = @"throttleRealtimeEndTime"; +static NSString *const kRCNUserDefaultsKeyNameCurrentRealtimeThrottlingRetryInterval = + @"currentRealtimeThrottlingRetryInterval"; +static NSString *const kRCNUserDefaultsKeyNameRealtimeRetryCount = @"realtimeRetryCount"; + +@interface RCNUserDefaultsManager () { + /// User Defaults instance for this bundleID. NSUserDefaults is guaranteed to be thread-safe. + NSUserDefaults *_userDefaults; + /// The suite name for this user defaults instance. It is a combination of a prefix and the + /// bundleID. This is because you cannot use just the bundleID of the current app as the suite + /// name when initializing user defaults. + NSString *_userDefaultsSuiteName; + /// The FIRApp that this instance is scoped within. + NSString *_firebaseAppName; + /// The Firebase Namespace that this instance is scoped within. + NSString *_firebaseNamespace; + /// The bundleID of the app. In case of an extension, this will be the bundleID of the parent app. + NSString *_bundleIdentifier; +} + +@end + +@implementation RCNUserDefaultsManager + +#pragma mark Initializers. + +/// Designated initializer. +- (instancetype)initWithAppName:(NSString *)appName + bundleID:(NSString *)bundleIdentifier + namespace:(NSString *)firebaseNamespace { + self = [super init]; + if (self) { + _firebaseAppName = appName; + _bundleIdentifier = bundleIdentifier; + NSInteger location = [firebaseNamespace rangeOfString:@":"].location; + if (location == NSNotFound) { + FIRLogError(kFIRLoggerRemoteConfig, @"I-RCN000064", + @"Error: Namespace %@ is not fully qualified app:namespace.", firebaseNamespace); + _firebaseNamespace = firebaseNamespace; + } else { + _firebaseNamespace = [firebaseNamespace substringToIndex:location]; + } + + // Initialize the user defaults with a prefix and the bundleID. For app extensions, this will be + // the bundleID of the app extension. + _userDefaults = + [RCNUserDefaultsManager sharedUserDefaultsForBundleIdentifier:_bundleIdentifier]; + } + + return self; +} + ++ (NSUserDefaults *)sharedUserDefaultsForBundleIdentifier:(NSString *)bundleIdentifier { + static dispatch_once_t onceToken; + static NSUserDefaults *sharedInstance; + dispatch_once(&onceToken, ^{ + NSString *userDefaultsSuiteName = + [RCNUserDefaultsManager userDefaultsSuiteNameForBundleIdentifier:bundleIdentifier]; + sharedInstance = [[NSUserDefaults alloc] initWithSuiteName:userDefaultsSuiteName]; + }); + return sharedInstance; +} + ++ (NSString *)userDefaultsSuiteNameForBundleIdentifier:(NSString *)bundleIdentifier { + NSString *suiteName = + [NSString stringWithFormat:@"%@.%@.%@", kRCNGroupPrefix, bundleIdentifier, kRCNGroupSuffix]; + return suiteName; +} + +#pragma mark Public properties. + +- (NSString *)lastETag { + return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETag]; +} + +- (void)setLastETag:(NSString *)lastETag { + if (lastETag) { + [self setInstanceUserDefaultsValue:lastETag forKey:kRCNUserDefaultsKeyNamelastETag]; + } +} + +- (NSString *)lastFetchedTemplateVersion { + NSDictionary *userDefaults = [self instanceUserDefaults]; + if ([userDefaults objectForKey:RCNFetchResponseKeyTemplateVersion]) { + return [userDefaults objectForKey:RCNFetchResponseKeyTemplateVersion]; + } + + return @"0"; +} + +- (void)setLastFetchedTemplateVersion:(NSString *)templateVersion { + if (templateVersion) { + [self setInstanceUserDefaultsValue:templateVersion forKey:RCNFetchResponseKeyTemplateVersion]; + } +} + +- (NSString *)lastActiveTemplateVersion { + NSDictionary *userDefaults = [self instanceUserDefaults]; + if ([userDefaults objectForKey:RCNActiveKeyTemplateVersion]) { + return [userDefaults objectForKey:RCNActiveKeyTemplateVersion]; + } + + return @"0"; +} + +- (void)setLastActiveTemplateVersion:(NSString *)templateVersion { + if (templateVersion) { + [self setInstanceUserDefaultsValue:templateVersion forKey:RCNActiveKeyTemplateVersion]; + } +} + +- (NSTimeInterval)lastETagUpdateTime { + NSNumber *lastETagUpdateTime = + [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastETagUpdateTime]; + return lastETagUpdateTime.doubleValue; +} + +- (void)setLastETagUpdateTime:(NSTimeInterval)lastETagUpdateTime { + if (lastETagUpdateTime) { + [self setInstanceUserDefaultsValue:@(lastETagUpdateTime) + forKey:kRCNUserDefaultsKeyNamelastETagUpdateTime]; + } +} + +- (NSTimeInterval)lastFetchTime { + NSNumber *lastFetchTime = + [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime]; + return lastFetchTime.doubleValue; +} + +- (void)setLastFetchTime:(NSTimeInterval)lastFetchTime { + [self setInstanceUserDefaultsValue:@(lastFetchTime) + forKey:kRCNUserDefaultsKeyNameLastSuccessfulFetchTime]; +} + +- (NSString *)lastFetchStatus { + return [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNamelastFetchStatus]; +} + +- (void)setLastFetchStatus:(NSString *)lastFetchStatus { + if (lastFetchStatus) { + [self setInstanceUserDefaultsValue:lastFetchStatus + forKey:kRCNUserDefaultsKeyNamelastFetchStatus]; + } +} + +- (BOOL)isClientThrottledWithExponentialBackoff { + NSNumber *isClientThrottled = + [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameIsClientThrottled]; + return isClientThrottled.boolValue; +} + +- (void)setIsClientThrottledWithExponentialBackoff:(BOOL)isClientThrottled { + [self setInstanceUserDefaultsValue:@(isClientThrottled) + forKey:kRCNUserDefaultsKeyNameIsClientThrottled]; +} + +- (NSTimeInterval)throttleEndTime { + NSNumber *throttleEndTime = + [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameThrottleEndTime]; + return throttleEndTime.doubleValue; +} + +- (void)setThrottleEndTime:(NSTimeInterval)throttleEndTime { + [self setInstanceUserDefaultsValue:@(throttleEndTime) + forKey:kRCNUserDefaultsKeyNameThrottleEndTime]; +} + +- (NSTimeInterval)currentThrottlingRetryIntervalSeconds { + NSNumber *throttleEndTime = [[self instanceUserDefaults] + objectForKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval]; + return throttleEndTime.doubleValue; +} + +- (void)setCurrentThrottlingRetryIntervalSeconds:(NSTimeInterval)throttlingRetryIntervalSeconds { + [self setInstanceUserDefaultsValue:@(throttlingRetryIntervalSeconds) + forKey:kRCNUserDefaultsKeyNamecurrentThrottlingRetryInterval]; +} + +- (int)realtimeRetryCount { + int realtimeRetryCount = 0; + if ([[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameRealtimeRetryCount]) { + realtimeRetryCount = [[[self instanceUserDefaults] + objectForKey:kRCNUserDefaultsKeyNameRealtimeRetryCount] intValue]; + } + + return realtimeRetryCount; +} + +- (void)setRealtimeRetryCount:(int)realtimeRetryCount { + [self setInstanceUserDefaultsValue:[NSNumber numberWithInt:realtimeRetryCount] + forKey:kRCNUserDefaultsKeyNameRealtimeRetryCount]; +} + +- (NSTimeInterval)realtimeThrottleEndTime { + NSNumber *realtimeThrottleEndTime = 0; + if ([[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameRealtimeThrottleEndTime]) { + realtimeThrottleEndTime = + [[self instanceUserDefaults] objectForKey:kRCNUserDefaultsKeyNameRealtimeThrottleEndTime]; + } + return realtimeThrottleEndTime.doubleValue; +} + +- (void)setRealtimeThrottleEndTime:(NSTimeInterval)throttleEndTime { + [self setInstanceUserDefaultsValue:@(throttleEndTime) + forKey:kRCNUserDefaultsKeyNameRealtimeThrottleEndTime]; +} + +- (NSTimeInterval)currentRealtimeThrottlingRetryIntervalSeconds { + NSNumber *realtimeThrottleEndTime = 0; + if ([[self instanceUserDefaults] + objectForKey:kRCNUserDefaultsKeyNameCurrentRealtimeThrottlingRetryInterval]) { + realtimeThrottleEndTime = [[self instanceUserDefaults] + objectForKey:kRCNUserDefaultsKeyNameCurrentRealtimeThrottlingRetryInterval]; + } + return realtimeThrottleEndTime.doubleValue; +} + +- (void)setCurrentRealtimeThrottlingRetryIntervalSeconds: + (NSTimeInterval)throttlingRetryIntervalSeconds { + [self setInstanceUserDefaultsValue:@(throttlingRetryIntervalSeconds) + forKey:kRCNUserDefaultsKeyNameCurrentRealtimeThrottlingRetryInterval]; +} + +#pragma mark Public methods. +- (void)resetUserDefaults { + [self resetInstanceUserDefaults]; +} + +#pragma mark Private methods. + +// There is a nested hierarchy for the userdefaults as follows: +// [FIRAppName][FIRNamespaceName][Key] +- (nonnull NSDictionary *)appUserDefaults { + NSString *appPath = _firebaseAppName; + NSDictionary *appDict = [_userDefaults valueForKeyPath:appPath]; + if (!appDict) { + appDict = [[NSDictionary alloc] init]; + } + return appDict; +} + +// Search for the user defaults for this (app, namespace) instance using the valueForKeyPath method. +- (nonnull NSDictionary *)instanceUserDefaults { + NSString *appNamespacePath = + [NSString stringWithFormat:@"%@.%@", _firebaseAppName, _firebaseNamespace]; + NSDictionary *appNamespaceDict = [_userDefaults valueForKeyPath:appNamespacePath]; + + if (!appNamespaceDict) { + appNamespaceDict = [[NSMutableDictionary alloc] init]; + } + return appNamespaceDict; +} + +// Update users defaults for just this (app, namespace) instance. +- (void)setInstanceUserDefaultsValue:(NSObject *)value forKey:(NSString *)key { + @synchronized(_userDefaults) { + NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy]; + NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy]; + [appNamespaceUserDefaults setObject:value forKey:key]; + [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace]; + [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName]; + // We need to synchronize to have this value updated for the extension. + [_userDefaults synchronize]; + } +} + +// Delete any existing userdefaults for this instance. +- (void)resetInstanceUserDefaults { + @synchronized(_userDefaults) { + NSMutableDictionary *appUserDefaults = [[self appUserDefaults] mutableCopy]; + NSMutableDictionary *appNamespaceUserDefaults = [[self instanceUserDefaults] mutableCopy]; + [appNamespaceUserDefaults removeAllObjects]; + [appUserDefaults setObject:appNamespaceUserDefaults forKey:_firebaseNamespace]; + [_userDefaults setObject:appUserDefaults forKey:_firebaseAppName]; + // We need to synchronize to have this value updated for the extension. + [_userDefaults synchronize]; + } +} + +@end diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Codable.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Codable.swift new file mode 100644 index 0000000..d2df8a9 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Codable.swift @@ -0,0 +1,69 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal +#endif // SWIFT_PACKAGE +import FirebaseSharedSwift + +public enum RemoteConfigValueCodableError: Error { + case unsupportedType(String) +} + +public extension RemoteConfigValue { + /// Extracts a RemoteConfigValue JSON-encoded object and decodes it to the requested type. + /// + /// - Parameter asType: The type to decode the JSON-object to + func decoded(asType: Value.Type = Value.self) throws -> Value { + if asType == Date.self { + throw RemoteConfigValueCodableError + .unsupportedType("Date type is not currently supported for " + + " Remote Config Value decoding. Please file a feature request") + } + return try FirebaseDataDecoder() + .decode(Value.self, from: FirebaseRemoteConfigValueDecoderHelper(value: self)) + } +} + +public enum RemoteConfigCodableError: Error { + case invalidSetDefaultsInput(String) +} + +public extension RemoteConfig { + /// Decodes a struct from the respective Remote Config values. + /// + /// - Parameter asType: The type to decode to. + func decoded(asType: Value.Type = Value.self) throws -> Value { + let keys = allKeys(from: RemoteConfigSource.default) + allKeys(from: RemoteConfigSource.remote) + let config = keys.reduce(into: [String: FirebaseRemoteConfigValueDecoderHelper]()) { + $0[$1] = FirebaseRemoteConfigValueDecoderHelper(value: configValue(forKey: $1)) + } + return try FirebaseDataDecoder().decode(Value.self, from: config) + } + + /// Sets config defaults from an encodable struct. + /// + /// - Parameter value: The object to use to set the defaults. + func setDefaults(from value: Value) throws { + guard let encoded = try FirebaseDataEncoder().encode(value) as? [String: NSObject] else { + throw RemoteConfigCodableError.invalidSetDefaultsInput( + "The setDefaults input: \(value), must be a Struct that encodes to a Dictionary" + ) + } + setDefaults(encoded) + } +} diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/FirebaseRemoteConfigValueDecoderHelper.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/FirebaseRemoteConfigValueDecoderHelper.swift new file mode 100644 index 0000000..f2d5654 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/FirebaseRemoteConfigValueDecoderHelper.swift @@ -0,0 +1,58 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal +#endif // SWIFT_PACKAGE +import FirebaseSharedSwift + +/// Implement the FirebaseRemoteConfigValueDecoding protocol for the shared Firebase decoder to +/// decode Remote Config Values. It returns the four different kinds of values from +/// a RemoteConfigValue object. +struct FirebaseRemoteConfigValueDecoderHelper: FirebaseRemoteConfigValueDecoding { + let value: RemoteConfigValue + + func numberValue() -> NSNumber { + return value.numberValue + } + + func boolValue() -> Bool { + return value.boolValue + } + + func stringValue() -> String { + return value.stringValue + } + + func dataValue() -> Data { + return value.dataValue + } + + func arrayValue() -> [AnyHashable]? { + guard let value = value.jsonValue as? [AnyHashable] else { + return nil + } + return value + } + + func dictionaryValue() -> [String: AnyHashable]? { + guard let value = value.jsonValue as? [String: AnyHashable] else { + return nil + } + return value + } +} diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigProperty.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigProperty.swift new file mode 100644 index 0000000..05d1df5 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigProperty.swift @@ -0,0 +1,51 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal +#endif // SWIFT_PACKAGE + +import SwiftUI + +/// A property wrapper that listens to a Remote Config value. +@available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) +@propertyWrapper +public struct RemoteConfigProperty: DynamicProperty { + @StateObject private var configValueObserver: RemoteConfigValueObservable + + /// Remote Config key name for this property + public let key: String + + public var wrappedValue: T { + configValueObserver.configValue + } + + /// Creates an instance by providing a config key. + /// + /// - Parameter key: key name + /// - Parameter fallback: The value to fall back to if the key doesn't exist in remote or default + /// configs + public init(key: String, fallback: T) { + self.key = key + + _configValueObserver = StateObject( + wrappedValue: RemoteConfigValueObservable( + key: key, + fallbackValue: fallback + ) + ) + } +} diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigValueObservable.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigValueObservable.swift new file mode 100644 index 0000000..69e521b --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/PropertyWrapper/RemoteConfigValueObservable.swift @@ -0,0 +1,75 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal +#endif // SWIFT_PACKAGE +import FirebaseCore +import SwiftUI + +extension Notification.Name { + // Listens to FirebaseRemoteConfig SDK if new configs are activated. + static let onRemoteConfigActivated = Notification.Name("FIRRemoteConfigActivateNotification") +} + +// Make sure this key is consistent with kFIRGoogleAppIDKey in FirebaseCore SDK +let FirebaseRemoteConfigAppNameKey = "FIRAppNameKey" + +@available(iOS 14.0, macOS 11.0, macCatalyst 14.0, tvOS 14.0, watchOS 7.0, *) +class RemoteConfigValueObservable: ObservableObject { + @Published var configValue: T + private let key: String + private let remoteConfig: RemoteConfig + private let fallbackValue: T + + init(key: String, fallbackValue: T) { + self.key = key + remoteConfig = RemoteConfig.remoteConfig() + self.fallbackValue = fallbackValue + // Initialize with fallback value + configValue = fallbackValue + // Check cached remote config value + do { + let configValue: RemoteConfigValue = remoteConfig[key] + if configValue.source == .remote || configValue.source == .default { + self.configValue = try remoteConfig[key].decoded() + } else { + self.configValue = fallbackValue + } + } catch { + configValue = fallbackValue + } + NotificationCenter.default.addObserver( + self, selector: #selector(configDidActivate), name: .onRemoteConfigActivated, object: nil + ) + } + + @objc func configDidActivate(notification: NSNotification) { + // This feature is only available in the default app. + let appName = notification.userInfo?[FirebaseRemoteConfigAppNameKey] as? String + if FirebaseApp.app()?.name != appName { + return + } + do { + let configValue: RemoteConfigValue = remoteConfig[key] + if configValue.source == .remote { + self.configValue = try remoteConfig[key].decoded() + } + } catch { + // Suppresses a hard failure if decoding failed. + } + } +} diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Resources/PrivacyInfo.xcprivacy b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..719a06f --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,38 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + 1C8F.1 + + + + + + diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/SPMSwiftHeaderWorkaround.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/SPMSwiftHeaderWorkaround.swift new file mode 100644 index 0000000..b83a981 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/SPMSwiftHeaderWorkaround.swift @@ -0,0 +1,30 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal + + // This is a trick to force generate a `FirebaseRemoteConfig-Swift.h` header + // that re-exports `FirebaseRemoteConfigInternal` for Objective-C clients. It + // is important for the below code to reference a Remote Config symbol defined + // in Objective-C as that will import the symbol's module + // (`FirebaseRemoteConfigInternal`) in the generated header. This allows + // Objective-C clients to import Remote Config's Objective-C API using + // `@import FirebaseRemoteConfig;`. This API is not needed for Swift clients + // and is therefore unavailable in a Swift context. + @available(*, unavailable) + @objc public extension RemoteConfig { + static var __no_op: () -> Void { {} } + } +#endif // SWIFT_PACKAGE diff --git a/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Value.swift b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Value.swift new file mode 100644 index 0000000..8a66eda --- /dev/null +++ b/Pods/FirebaseRemoteConfig/FirebaseRemoteConfig/Swift/Value.swift @@ -0,0 +1,42 @@ +/* + * Copyright 2021 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import Foundation +#if SWIFT_PACKAGE + @_exported import FirebaseRemoteConfigInternal +#endif // SWIFT_PACKAGE + +/// Implements subscript overloads to enable Remote Config values to be accessed +/// in a type-safe way directly from the current config. +public extension RemoteConfig { + /// Return a typed RemoteConfigValue for a key. + /// - Parameter key: A Remote Config key. + /// - Returns: A typed RemoteConfigValue. + subscript(decodedValue key: String) -> T? { + return try? configValue(forKey: key).decoded() + } + + /// Return a Dictionary for a RemoteConfig JSON key. + /// - Parameter key: A Remote Config key. + /// - Returns: A Dictionary representing a RemoteConfig JSON value. + subscript(jsonValue key: String) -> [String: AnyHashable]? { + guard let value = configValue(forKey: key).jsonValue as? [String: AnyHashable] else { + // nil is the historical behavior for failing to extract JSON. + return nil + } + return value + } +} diff --git a/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h new file mode 100644 index 0000000..3b49733 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInterop.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@protocol FIRAnalyticsInteropListener; + +NS_ASSUME_NONNULL_BEGIN + +/// Block typedef callback parameter to `getUserProperties(with:)`. +typedef void (^FIRAInteropUserPropertiesCallback)(NSDictionary *userProperties) + NS_SWIFT_UNAVAILABLE("Use Swift's closure syntax instead."); + +/// Connector for bridging communication between Firebase SDKs and FirebaseAnalytics APIs. +@protocol FIRAnalyticsInterop + +/// Sets user property when trigger event is logged. This API is only available in the SDK. +- (void)setConditionalUserProperty:(NSDictionary *)conditionalUserProperty; + +/// Clears user property if set. +- (void)clearConditionalUserProperty:(NSString *)userPropertyName + forOrigin:(NSString *)origin + clearEventName:(NSString *)clearEventName + clearEventParameters:(NSDictionary *)clearEventParameters; + +/// Returns currently set user properties. +- (NSArray *> *)conditionalUserProperties:(NSString *)origin + propertyNamePrefix: + (NSString *)propertyNamePrefix; + +/// Returns the maximum number of user properties. +- (NSInteger)maxUserProperties:(NSString *)origin; + +/// Returns the user properties to a callback function. +- (void)getUserPropertiesWithCallback: + (void (^)(NSDictionary *userProperties))callback; + +/// Logs events. +- (void)logEventWithOrigin:(NSString *)origin + name:(NSString *)name + parameters:(nullable NSDictionary *)parameters; + +/// Sets user property. +- (void)setUserPropertyWithOrigin:(NSString *)origin name:(NSString *)name value:(id)value; + +/// Registers an Analytics listener for the given origin. +- (void)registerAnalyticsListener:(id)listener + withOrigin:(NSString *)origin; + +/// Unregisters an Analytics listener for the given origin. +- (void)unregisterAnalyticsListenerWithOrigin:(NSString *)origin; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h new file mode 100644 index 0000000..327aefd --- /dev/null +++ b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRAnalyticsInteropListener.h @@ -0,0 +1,24 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// Handles events and messages from Analytics. +@protocol FIRAnalyticsInteropListener + +/// Triggers when an Analytics event happens for the registered origin with +/// FirebaseAnalyticsInterop`s `registerAnalyticsListener(_:withOrigin:)`. +- (void)messageTriggered:(NSString *)name parameters:(NSDictionary *)parameters; + +@end diff --git a/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h new file mode 100644 index 0000000..efc54ab --- /dev/null +++ b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropEventNames.h @@ -0,0 +1,28 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/// @file FIRInteropEventNames.h + +#import + +/// Notification open event name. +static NSString *const kFIRIEventNotificationOpen = @"_no"; + +/// Notification foreground event name. +static NSString *const kFIRIEventNotificationForeground = @"_nf"; + +/// Campaign event name. +static NSString *const kFIRIEventFirebaseCampaign = @"_cmp"; diff --git a/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h new file mode 100644 index 0000000..f640702 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/Interop/Analytics/Public/FIRInteropParameterNames.h @@ -0,0 +1,73 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/// @file FIRInteropParameterNames.h +/// +/// Predefined event parameter names used by Firebase. This file is a subset of the +/// FirebaseAnalytics FIRParameterNames.h public header. +/// +/// The origin of your traffic, such as an Ad network (for example, google) or partner (urban +/// airship). Identify the advertiser, site, publication, etc. that is sending traffic to your +/// property. Highly recommended (String). +///
+///     let params = [
+///       kFIRParameterSource : "InMobi",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterSource NS_SWIFT_NAME(AnalyticsParameterSource) = @"source"; + +/// The advertising or marketing medium, for example: cpc, banner, email, push. Highly recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterMedium : "email",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterMedium NS_SWIFT_NAME(AnalyticsParameterMedium) = @"medium"; + +/// The individual campaign name, slogan, promo code, etc. Some networks have pre-defined macro to +/// capture campaign information, otherwise can be populated by developer. Highly Recommended +/// (String). +///
+///     let params = [
+///       kFIRParameterCampaign : "winter_promotion",
+///       // ...
+///     ]
+/// 
+static NSString *const kFIRIParameterCampaign NS_SWIFT_NAME(AnalyticsParameterCampaign) = + @"campaign"; + +/// Message identifier. +static NSString *const kFIRIParameterMessageIdentifier = @"_nmid"; + +/// Message name. +static NSString *const kFIRIParameterMessageName = @"_nmn"; + +/// Message send time. +static NSString *const kFIRIParameterMessageTime = @"_nmt"; + +/// Message device time. +static NSString *const kFIRIParameterMessageDeviceTime = @"_ndt"; + +/// Topic message. +static NSString *const kFIRIParameterTopic = @"_nt"; + +/// Stores the message_id of the last notification opened by the app. +static NSString *const kFIRIUserPropertyLastNotification = @"_ln"; diff --git a/Pods/FirebaseRemoteConfig/LICENSE b/Pods/FirebaseRemoteConfig/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseRemoteConfig/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseRemoteConfig/README.md b/Pods/FirebaseRemoteConfig/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseRemoteConfig/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigConstants.swift b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigConstants.swift new file mode 100644 index 0000000..f9a10e4 --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigConstants.swift @@ -0,0 +1,21 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@objc(FIRRemoteConfigConstants) +public final class RemoteConfigConstants: NSObject { + @objc(FIRNamespaceGoogleMobilePlatform) public static let NamespaceGoogleMobilePlatform = + "firebase" +} diff --git a/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigInterop.swift b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigInterop.swift new file mode 100644 index 0000000..b7988ef --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RemoteConfigInterop.swift @@ -0,0 +1,21 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@objc(FIRRemoteConfigInterop) +public protocol RemoteConfigInterop { + func registerRolloutsStateSubscriber(_ subscriber: RolloutsStateSubscriber, + for namespace: String) +} diff --git a/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutAssignment.swift b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutAssignment.swift new file mode 100644 index 0000000..715412b --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutAssignment.swift @@ -0,0 +1,47 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@objc(FIRRolloutAssignment) +public class RolloutAssignment: NSObject { + @objc public var rolloutId: String + @objc public var variantId: String + @objc public var templateVersion: Int64 + @objc public var parameterKey: String + @objc public var parameterValue: String + + @objc public init(rolloutId: String, variantId: String, templateVersion: Int64, + parameterKey: String, + parameterValue: String) { + self.rolloutId = rolloutId + self.variantId = variantId + self.templateVersion = templateVersion + self.parameterKey = parameterKey + self.parameterValue = parameterValue + super.init() + } +} + +@objc(FIRRolloutsState) +public class RolloutsState: NSObject { + @objc public var assignments: Set = Set() + + @objc public init(assignmentList: [RolloutAssignment]) { + for assignment in assignmentList { + assignments.insert(assignment) + } + super.init() + } +} diff --git a/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutsStateSubscriber.swift b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutsStateSubscriber.swift new file mode 100644 index 0000000..88e5ba8 --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/FirebaseRemoteConfig/Interop/RolloutsStateSubscriber.swift @@ -0,0 +1,20 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@objc(FIRRolloutsStateSubscriber) +public protocol RolloutsStateSubscriber { + func rolloutsStateDidChange(_ rolloutsState: RolloutsState) +} diff --git a/Pods/FirebaseRemoteConfigInterop/LICENSE b/Pods/FirebaseRemoteConfigInterop/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseRemoteConfigInterop/README.md b/Pods/FirebaseRemoteConfigInterop/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseRemoteConfigInterop/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/ApplicationInfo.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/ApplicationInfo.swift new file mode 100644 index 0000000..cabc80d --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/ApplicationInfo.swift @@ -0,0 +1,120 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import FirebaseCore + +#if SWIFT_PACKAGE + import FirebaseSessionsObjC +#endif // SWIFT_PACKAGE + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_Environment +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// Development environment for the application. +enum DevEnvironment: String { + case prod // Prod environment + case staging // Staging environment + case autopush // Autopush environment +} + +protocol ApplicationInfoProtocol { + /// Google App ID / GMP App ID + var appID: String { get } + + /// Version of the Firebase SDK + var sdkVersion: String { get } + + /// Crashlytics-specific device / OS filter values. + var osName: String { get } + + /// Model of the device + var deviceModel: String { get } + + /// Network information for the application + var networkInfo: NetworkInfoProtocol { get } + + /// Development environment on which the application is running. + var environment: DevEnvironment { get } + + var appBuildVersion: String { get } + + var appDisplayVersion: String { get } + + var osBuildVersion: String { get } + + var osDisplayVersion: String { get } +} + +class ApplicationInfo: ApplicationInfoProtocol { + let appID: String + + private let networkInformation: NetworkInfoProtocol + private let envParams: [String: String] + private let infoDict: [String: Any]? + + init(appID: String, networkInfo: NetworkInfoProtocol = NetworkInfo(), + envParams: [String: String] = ProcessInfo.processInfo.environment, + infoDict: [String: Any]? = Bundle.main.infoDictionary) { + self.appID = appID + networkInformation = networkInfo + self.envParams = envParams + self.infoDict = infoDict + } + + var sdkVersion: String { + return FirebaseVersion() + } + + var osName: String { + return GULAppEnvironmentUtil.appleDevicePlatform() + } + + var deviceModel: String { + return GULAppEnvironmentUtil.deviceSimulatorModel() ?? "" + } + + var networkInfo: NetworkInfoProtocol { + return networkInformation + } + + var environment: DevEnvironment { + if let environment = envParams["FirebaseSessionsRunEnvironment"] { + return DevEnvironment(rawValue: environment.trimmingCharacters(in: .whitespaces).lowercased()) + ?? DevEnvironment.prod + } + return DevEnvironment.prod + } + + var appBuildVersion: String { + return infoDict?["CFBundleVersion"] as? String ?? "" + } + + var appDisplayVersion: String { + return infoDict?["CFBundleShortVersionString"] as? String ?? "" + } + + var osBuildVersion: String { + return FIRSESGetSysctlEntry("kern.osversion") ?? "" + } + + var osDisplayVersion: String { + return GULAppEnvironmentUtil.systemVersion() + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift new file mode 100644 index 0000000..488fca7 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift @@ -0,0 +1,75 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + import FirebaseSessionsObjC +#endif // SWIFT_PACKAGE + +class DevEventConsoleLogger: EventGDTLoggerProtocol { + private let commandLineArgument = "-FIRSessionsDebugEvents" + + func logEvent(event: SessionStartEvent, completion: @escaping (Result) -> Void) { + if !ProcessInfo.processInfo.arguments.contains(commandLineArgument) { + return + } + + let proto = event.encodeDecodeEvent() + prettyPrint(proto: proto) + } + + func prettyPrint(proto: firebase_appquality_sessions_SessionEvent) { + let logOutput = """ + Printing Session Event due to \"\(commandLineArgument)\" command line argument + Session Event: + event_type: \(proto.event_type) + session_data + session_id: \(proto.session_data.session_id.description) + first_session_id: \(proto.session_data.first_session_id.description) + session_index: \(proto.session_data.session_index) + event_timestamp_us: \(proto.session_data.event_timestamp_us) + firebase_installation_id: \(proto.session_data.firebase_installation_id.description) + firebase_authentication_token: + \(proto.session_data.firebase_authentication_token.description) + data_collection_status + crashlytics: \(proto.session_data.data_collection_status.crashlytics) + performance: \(proto.session_data.data_collection_status.performance) + session_sampling_rate: \(proto.session_data.data_collection_status.session_sampling_rate) + application_info + app_id: \(proto.application_info.app_id.description) + session_sdk_version: \(proto.application_info.session_sdk_version.description) + os_version: \(proto.application_info.os_version.description) + device_model: \(proto.application_info.device_model.description) + development_platform_name: \(proto.application_info.development_platform_name.description) + development_platform_version: \(proto.application_info.development_platform_version + .description) + session_sdk_version: \(proto.application_info.session_sdk_version.description) + apple_app_info + bundle_short_version: \(proto.application_info.apple_app_info.bundle_short_version + .description) + app_build_version: \(proto.application_info.apple_app_info.app_build_version.description) + network_connection_info + network_type: \(proto.application_info.apple_app_info.network_connection_info + .network_type.rawValue) + mobile_subtype: \(proto.application_info.apple_app_info.network_connection_info + .mobile_subtype.rawValue) + os_name: \(proto.application_info.apple_app_info.os_name.description) + log_environment: \(proto.application_info.log_environment) + """ + + Logger.logInfo(logOutput) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/NanoPB+CustomStringConvertible.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/NanoPB+CustomStringConvertible.swift new file mode 100644 index 0000000..331ddd3 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Development/NanoPB+CustomStringConvertible.swift @@ -0,0 +1,131 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + import FirebaseSessionsObjC +#endif // SWIFT_PACKAGE + +/// +/// These extensions allows us to console log properties of our Session Events +/// proto for development and debugging purposes without having to call decode +/// on each field manually. Instead you can read `.description`. +/// + +extension firebase_appquality_sessions_EventType: CustomStringConvertible { + public var description: String { + switch self { + case firebase_appquality_sessions_EventType_SESSION_START: + return "SESSION_START" + case firebase_appquality_sessions_EventType_EVENT_TYPE_UNKNOWN: + return "UNKNOWN" + default: + return "Unrecognized EventType. Please update the firebase_appquality_sessions_EventType CustomStringConvertible extension" + } + } +} + +extension firebase_appquality_sessions_DataCollectionState: CustomStringConvertible { + public var description: String { + switch self { + case firebase_appquality_sessions_DataCollectionState_COLLECTION_ENABLED: + return "ENABLED" + case firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED: + return "SAMPLED" + case firebase_appquality_sessions_DataCollectionState_COLLECTION_UNKNOWN: + return "UNKNOWN" + case firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED: + return "DISABLED" + case firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED_REMOTE: + return "DISABLED_REMOTE" + case firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED: + return "SDK_NOT_INSTALLED" + default: + return "Unrecognized DataCollectionState. Please update the firebase_appquality_sessions_DataCollectionState CustomStringConvertible extension" + } + } +} + +extension firebase_appquality_sessions_OsName: CustomStringConvertible { + public var description: String { + switch self { + case firebase_appquality_sessions_OsName_IOS: + return "IOS" + case firebase_appquality_sessions_OsName_IPADOS: + return "IPADOS" + case firebase_appquality_sessions_OsName_TVOS: + return "TVOS" + case firebase_appquality_sessions_OsName_IOS_ON_MAC: + return "IOS_ON_MAC" + case firebase_appquality_sessions_OsName_MACOS: + return "MACOS" + case firebase_appquality_sessions_OsName_MACCATALYST: + return "MACCATALYST" + case firebase_appquality_sessions_OsName_WATCHOS: + return "WATCHOS" + case firebase_appquality_sessions_OsName_UNKNOWN_OSNAME: + return "UNKNOWN_OSNAME" + case firebase_appquality_sessions_OsName_UNSPECIFIED: + return "UNSPECIFIED" + default: + return "Unrecognized OsName. Please update the firebase_appquality_sessions_OsName CustomStringConvertible extension" + } + } +} + +extension firebase_appquality_sessions_LogEnvironment: CustomStringConvertible { + public var description: String { + switch self { + case firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD: + return "PROD" + case firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_STAGING: + return "STAGING" + case firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_AUTOPUSH: + return "AUTOPUSH" + case firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_UNKNOWN: + return "UNKNOWN" + default: + return "Unrecognized LogEnvironment. Please update the firebase_appquality_sessions_LogEnvironment CustomStringConvertible extension" + } + } +} + +// This is written like this for Swift backwards-compatibility. +// Once we upgrade to Xcode 14, this can be written as +// UnsafeMutablePointer +extension UnsafeMutablePointer: CustomStringConvertible where Pointee == pb_bytes_array_t { + public var description: String { + let decoded = FIRSESDecodeString(self) + if decoded.count == 0 { + return "" + } + return decoded + } +} + +// For an optional field +// This is written like this for Swift backwards-compatibility. +// Once we upgrade to Xcode 14, this can be written as +// UnsafeMutablePointer? +extension Optional: CustomStringConvertible + where Wrapped == UnsafeMutablePointer { + public var description: String { + guard let this = self else { + return "" + } + return this.description + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/EventGDTLogger.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/EventGDTLogger.swift new file mode 100644 index 0000000..03dff7d --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/EventGDTLogger.swift @@ -0,0 +1,54 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import GoogleDataTransport + +protocol EventGDTLoggerProtocol { + func logEvent(event: SessionStartEvent, completion: @escaping (Result) -> Void) +} + +/// +/// EventGDTLogger is responsible for +/// 1) Creating GDT Events and logging them to the GoogleDataTransport SDK +/// 2) Handling debugging situations (eg. running in Simulator or printing the event to console) +/// +class EventGDTLogger: EventGDTLoggerProtocol { + let googleDataTransport: GoogleDataTransportProtocol + let devEventConsoleLogger: EventGDTLoggerProtocol + + init(googleDataTransport: GoogleDataTransportProtocol, + devEventConsoleLogger: EventGDTLoggerProtocol = DevEventConsoleLogger()) { + self.googleDataTransport = googleDataTransport + self.devEventConsoleLogger = devEventConsoleLogger + } + + /// Logs the event to FireLog, taking into account debugging cases such as running + /// in simulator. + func logEvent(event: SessionStartEvent, completion: @escaping (Result) -> Void) { + let gdtEvent = googleDataTransport.eventForTransport() + gdtEvent.dataObject = event + gdtEvent.qosTier = GDTCOREventQoS.qosDefault + #if targetEnvironment(simulator) + Logger.logDebug("Logging events using fast QOS due to running on a simulator") + gdtEvent.qosTier = GDTCOREventQoS.qoSFast + #endif // targetEnvironment(simulator) + + devEventConsoleLogger.logEvent(event: event) { _ in } + + googleDataTransport.logGDTEvent(event: gdtEvent, completion: completion) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessions.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessions.swift new file mode 100644 index 0000000..978d596 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessions.swift @@ -0,0 +1,283 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +// Avoids exposing internal FirebaseCore APIs to Swift users. +@_implementationOnly import FirebaseCoreExtension +@_implementationOnly import FirebaseInstallations +@_implementationOnly import GoogleDataTransport + +#if swift(>=6.0) + internal import Promises +#elseif swift(>=5.10) + import Promises +#else + @_implementationOnly import Promises +#endif + +private enum GoogleDataTransportConfig { + static let sessionsLogSource = "1974" + static let sessionsTarget = GDTCORTarget.FLL +} + +@objc(FIRSessions) final class Sessions: NSObject, Library, SessionsProvider { + // MARK: - Private Variables + + /// The Firebase App ID associated with Sessions. + private let appID: String + + /// Top-level Classes in the Sessions SDK + private let coordinator: SessionCoordinatorProtocol + private let initiator: SessionInitiator + private let sessionGenerator: SessionGenerator + private let appInfo: ApplicationInfoProtocol + private let settings: SettingsProtocol + + /// Subscribers + /// `subscribers` are used to determine the Data Collection state of the Sessions SDK. + /// If any Subscribers has Data Collection enabled, the Sessions SDK will send events + private var subscribers: [SessionsSubscriber] = [] + /// `subscriberPromises` are used to wait until all Subscribers have registered + /// themselves. Subscribers must have Data Collection state available upon registering. + private var subscriberPromises: [SessionsSubscriberName: Promise] = [:] + + /// Notifications + static let SessionIDChangedNotificationName = Notification + .Name("SessionIDChangedNotificationName") + let notificationCenter = NotificationCenter() + + // MARK: - Initializers + + // Initializes the SDK and top-level classes + required convenience init(appID: String, installations: InstallationsProtocol) { + let googleDataTransport = GDTCORTransport( + mappingID: GoogleDataTransportConfig.sessionsLogSource, + transformers: nil, + target: GoogleDataTransportConfig.sessionsTarget + ) + + let fireLogger = EventGDTLogger(googleDataTransport: googleDataTransport!) + + let appInfo = ApplicationInfo(appID: appID) + let settings = SessionsSettings( + appInfo: appInfo, + installations: installations + ) + + let sessionGenerator = SessionGenerator(collectEvents: Sessions + .shouldCollectEvents(settings: settings)) + let coordinator = SessionCoordinator( + installations: installations, + fireLogger: fireLogger + ) + + let initiator = SessionInitiator(settings: settings) + + self.init(appID: appID, + sessionGenerator: sessionGenerator, + coordinator: coordinator, + initiator: initiator, + appInfo: appInfo, + settings: settings) { result in + switch result { + case .success(()): + Logger.logInfo("Successfully logged Session Start event") + case let .failure(sessionsError): + switch sessionsError { + case let .SessionInstallationsError(error): + Logger.logError( + "Error getting Firebase Installation ID: \(error). Skipping this Session Event" + ) + case let .DataTransportError(error): + Logger + .logError( + "Error logging Session Start event to GoogleDataTransport: \(error)." + ) + case .NoDependenciesError: + Logger + .logError( + "Sessions SDK did not have any dependent SDKs register as dependencies. Events will not be sent." + ) + case .SessionSamplingError: + Logger + .logDebug( + "Sessions SDK has sampled this session" + ) + case .DisabledViaSettingsError: + Logger + .logDebug( + "Sessions SDK is disabled via Settings" + ) + case .DataCollectionError: + Logger + .logDebug( + "Data Collection is disabled for all subscribers. Skipping this Session Event" + ) + case .SessionInstallationsTimeOutError: + Logger.logError( + "Error getting Firebase Installation ID due to timeout. Skipping this Session Event" + ) + } + } + } + } + + // Initializes the SDK and begins the process of listening for lifecycle events and logging + // events + init(appID: String, sessionGenerator: SessionGenerator, coordinator: SessionCoordinatorProtocol, + initiator: SessionInitiator, appInfo: ApplicationInfoProtocol, settings: SettingsProtocol, + loggedEventCallback: @escaping (Result) -> Void) { + self.appID = appID + + self.sessionGenerator = sessionGenerator + self.coordinator = coordinator + self.initiator = initiator + self.appInfo = appInfo + self.settings = settings + + super.init() + + for subscriberName in SessionsDependencies.dependencies { + subscriberPromises[subscriberName] = Promise.pending() + } + + Logger + .logDebug( + "Version \(FirebaseVersion()). Expecting subscriptions from: \(SessionsDependencies.dependencies)" + ) + + self.initiator.beginListening { + // Generating a Session ID early is important as Subscriber + // SDKs will need to read it immediately upon registration. + let sessionInfo = self.sessionGenerator.generateNewSession() + + // Post a notification so subscriber SDKs can get an updated Session ID + self.notificationCenter.post(name: Sessions.SessionIDChangedNotificationName, + object: nil) + + let event = SessionStartEvent(sessionInfo: sessionInfo, appInfo: self.appInfo) + + // If there are no Dependencies, then the Sessions SDK can't acknowledge + // any products data collection state, so the Sessions SDK won't send events. + guard !self.subscriberPromises.isEmpty else { + loggedEventCallback(.failure(.NoDependenciesError)) + return + } + + // Wait until all subscriber promises have been fulfilled before + // doing any data collection. + all(self.subscriberPromises.values).then(on: .global(qos: .background)) { _ in + guard self.isAnyDataCollectionEnabled else { + loggedEventCallback(.failure(.DataCollectionError)) + return + } + + Logger.logDebug("Data Collection is enabled for at least one Subscriber") + + // Fetch settings if they have expired. This must happen after the check for + // data collection because it uses the network, but it must happen before the + // check for sessionsEnabled from Settings because otherwise we would permanently + // turn off the Sessions SDK when we disabled it. + self.settings.updateSettings() + + self.addSubscriberFields(event: event) + event.setSamplingRate(samplingRate: self.settings.samplingRate) + + guard sessionInfo.shouldDispatchEvents else { + loggedEventCallback(.failure(.SessionSamplingError)) + return + } + + guard self.settings.sessionsEnabled else { + loggedEventCallback(.failure(.DisabledViaSettingsError)) + return + } + + self.coordinator.attemptLoggingSessionStart(event: event) { result in + loggedEventCallback(result) + } + } + } + } + + // MARK: - Sampling + + static func shouldCollectEvents(settings: SettingsProtocol) -> Bool { + // Calculate whether we should sample events using settings data + // Sampling rate of 1 means we do not sample. + let randomValue = Double.random(in: 0 ... 1) + return randomValue <= settings.samplingRate + } + + // MARK: - Data Collection + + var isAnyDataCollectionEnabled: Bool { + for subscriber in subscribers { + if subscriber.isDataCollectionEnabled { + return true + } + } + return false + } + + func addSubscriberFields(event: SessionStartEvent) { + for subscriber in subscribers { + event.set(subscriber: subscriber.sessionsSubscriberName, + isDataCollectionEnabled: subscriber.isDataCollectionEnabled, + appInfo: appInfo) + } + } + + // MARK: - SessionsProvider + + var currentSessionDetails: SessionDetails { + return SessionDetails(sessionId: sessionGenerator.currentSession?.sessionId) + } + + func register(subscriber: SessionsSubscriber) { + Logger + .logDebug( + "Registering Sessions SDK subscriber with name: \(subscriber.sessionsSubscriberName), data collection enabled: \(subscriber.isDataCollectionEnabled)" + ) + + notificationCenter.addObserver( + forName: Sessions.SessionIDChangedNotificationName, + object: nil, + queue: nil + ) { notification in + subscriber.onSessionChanged(self.currentSessionDetails) + } + // Immediately call the callback because the Sessions SDK starts + // before subscribers, so subscribers will miss the first Notification + subscriber.onSessionChanged(currentSessionDetails) + + // Fulfil this subscriber's promise + subscribers.append(subscriber) + subscriberPromises[subscriber.sessionsSubscriberName]?.fulfill(()) + } + + // MARK: - Library conformance + + static func componentsToRegister() -> [Component] { + return [Component(SessionsProvider.self, + instantiationTiming: .alwaysEager) { container, isCacheable in + // Sessions SDK only works for the default app + guard let app = container.app, app.isDefaultApp else { return nil } + isCacheable.pointee = true + let installations = Installations.installations(app: app) + return self.init(appID: app.options.googleAppID, installations: installations) + }] + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessionsError.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessionsError.swift new file mode 100644 index 0000000..12ed1fb --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessionsError.swift @@ -0,0 +1,35 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Contains the list of errors that are localized for Firebase Sessions Library +enum FirebaseSessionsError: Error { + /// Event sampling related error + case SessionSamplingError + /// Firebase Installation ID related error + case SessionInstallationsError(Error) + /// Firebase Installation ID related timeout error + case SessionInstallationsTimeOutError + /// Error from the GoogleDataTransport SDK + case DataTransportError(Error) + /// Sessions SDK is disabled via settings error + case DisabledViaSettingsError + /// Sessions SDK is disabled because all Subscribers have their + /// data collection disabled + case DataCollectionError + /// Sessions SDK didn't have any Subscribers depend + /// on it via addDependency in SessionDependencies + case NoDependenciesError +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift new file mode 100644 index 0000000..9c04f9c --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift @@ -0,0 +1,41 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import GoogleDataTransport + +enum GoogleDataTransportProtocolErrors: Error { + case writeFailure +} + +protocol GoogleDataTransportProtocol { + func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result) -> Void) + func eventForTransport() -> GDTCOREvent +} + +extension GDTCORTransport: GoogleDataTransportProtocol { + func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result) -> Void) { + sendDataEvent(event) { wasWritten, error in + if let error { + completion(.failure(error)) + } else if !wasWritten { + completion(.failure(GoogleDataTransportProtocolErrors.writeFailure)) + } else { + completion(.success(())) + } + } + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift new file mode 100644 index 0000000..38ca1ea --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift @@ -0,0 +1,79 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import FirebaseInstallations + +protocol InstallationsProtocol { + var installationsWaitTimeInSecond: Int { get } + + /// Override Installation function for testing + func authToken(completion: @escaping (InstallationsAuthTokenResult?, Error?) -> Void) + + /// Override Installation function for testing + func installationID(completion: @escaping (String?, Error?) -> Void) + + /// Return a tuple: (installationID, authenticationToken) for success result + func installationID(completion: @escaping (Result<(String, String), Error>) -> Void) +} + +extension InstallationsProtocol { + var installationsWaitTimeInSecond: Int { + return 10 + } + + func installationID(completion: @escaping (Result<(String, String), Error>) -> Void) { + var authTokenComplete = "" + var intallationComplete: String? + var errorComplete: Error? + + let workingGroup = DispatchGroup() + + workingGroup.enter() + authToken { (authTokenResult: InstallationsAuthTokenResult?, error: Error?) in + authTokenComplete = authTokenResult?.authToken ?? "" + workingGroup.leave() + } + + workingGroup.enter() + installationID { (installationID: String?, error: Error?) in + if let installationID { + intallationComplete = installationID + } else if let error = error { + errorComplete = error + } + workingGroup.leave() + } + + // adding timeout for 10 seconds + let result = workingGroup + .wait(timeout: .now() + DispatchTimeInterval.seconds(installationsWaitTimeInSecond)) + + switch result { + case .timedOut: + completion(.failure(FirebaseSessionsError.SessionInstallationsTimeOutError)) + return + default: + if let intallationComplete { + completion(.success((intallationComplete, authTokenComplete))) + } else if let errorComplete { + completion(.failure(errorComplete)) + } + } + } +} + +extension Installations: InstallationsProtocol {} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Logger.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Logger.swift new file mode 100644 index 0000000..513a83b --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Logger.swift @@ -0,0 +1,62 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import FirebaseCoreExtension + +/// +/// Logger is responsible for printing console logs +/// +enum Logger { + private static let logServiceTag = "[FirebaseSessions]" + private static let logCode = "I-SES000000" + + static func logInfo(_ message: String) { + FirebaseLogger.log( + level: .info, + service: logServiceTag, + code: logCode, + message: message + ) + } + + static func logDebug(_ message: String) { + FirebaseLogger.log( + level: .debug, + service: logServiceTag, + code: logCode, + message: message + ) + } + + static func logWarning(_ message: String) { + FirebaseLogger.log( + level: .warning, + service: logServiceTag, + code: logCode, + message: message + ) + } + + static func logError(_ message: String) { + FirebaseLogger.log( + level: .error, + service: logServiceTag, + code: logCode, + message: message + ) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/NetworkInfo.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/NetworkInfo.swift new file mode 100644 index 0000000..a24d36e --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/NetworkInfo.swift @@ -0,0 +1,42 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + import FirebaseSessionsObjC +#endif // SWIFT_PACKAGE + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_Environment +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +protocol NetworkInfoProtocol { + var networkType: GULNetworkType { get } + + var mobileSubtype: String { get } +} + +class NetworkInfo: NetworkInfoProtocol { + var networkType: GULNetworkType { + return GULNetworkInfo.getNetworkType() + } + + var mobileSubtype: String { + return GULNetworkInfo.getNetworkRadioType() + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsDependencies.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsDependencies.swift new file mode 100644 index 0000000..078fd3c --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsDependencies.swift @@ -0,0 +1,32 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +// Sessions Dependencies determines when a dependent SDK is +// installed in the app. The Sessions SDK uses this to figure +// out which dependencies to wait for to getting the data +// collection state. +// +// This is important because the Sessions SDK starts up before +// dependent SDKs +@objc(FIRSessionsDependencies) +public class SessionsDependencies: NSObject { + static var dependencies: Set = .init() + + @objc public static func addDependency(name: SessionsSubscriberName) { + SessionsDependencies.dependencies.insert(name) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsProvider.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsProvider.swift new file mode 100644 index 0000000..ef73e18 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsProvider.swift @@ -0,0 +1,23 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +// Sessions Provider is the Session SDK's internal +// interface for other 1P SDKs to talk to. +@objc(FIRSessionsProvider) +public protocol SessionsProvider { + @objc func register(subscriber: SessionsSubscriber) +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsSubscriber.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsSubscriber.swift new file mode 100644 index 0000000..54b1b3f --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsSubscriber.swift @@ -0,0 +1,56 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Sessions Subscriber is an interface that dependent SDKs +/// must implement. +@objc(FIRSessionsSubscriber) +public protocol SessionsSubscriber { + func onSessionChanged(_ session: SessionDetails) + var isDataCollectionEnabled: Bool { get } + var sessionsSubscriberName: SessionsSubscriberName { get } +} + +/// Session Payload is a container for Session Data passed to Subscribers +/// whenever the Session changes +@objc(FIRSessionDetails) +public class SessionDetails: NSObject { + @objc public var sessionId: String? + + public init(sessionId: String?) { + self.sessionId = sessionId + super.init() + } +} + +/// Session Subscriber Names are used for identifying subscribers +@objc(FIRSessionsSubscriberName) +public enum SessionsSubscriberName: Int, CustomStringConvertible { + case Unknown + case Crashlytics + case Performance + + public var description: String { + switch self { + case .Crashlytics: + return "Crashlytics" + case .Performance: + return "Performance" + default: + return "Unknown" + } + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionCoordinator.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionCoordinator.swift new file mode 100644 index 0000000..3d4cec1 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionCoordinator.swift @@ -0,0 +1,81 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +protocol SessionCoordinatorProtocol { + func attemptLoggingSessionStart(event: SessionStartEvent, + callback: @escaping (Result) -> Void) +} + +/// +/// SessionCoordinator is responsible for coordinating the systems in this SDK +/// involved with sending a Session Start event. +/// +class SessionCoordinator: SessionCoordinatorProtocol { + let installations: InstallationsProtocol + let fireLogger: EventGDTLoggerProtocol + + init(installations: InstallationsProtocol, + fireLogger: EventGDTLoggerProtocol) { + self.installations = installations + self.fireLogger = fireLogger + } + + /// Begins the process of logging a SessionStartEvent to FireLog after + /// it has been approved for sending + func attemptLoggingSessionStart(event: SessionStartEvent, + callback: @escaping (Result) + -> Void) { + /// Order of execution + /// 1. Fetch the installations Id. Regardless of success, move to step 2 + /// 2. Log the event. If successful, all is good. Else, log the message with error. + /// 3. If there was a FireLog error, expose it to the callback. Otherwise expose the FIID + /// error if it exists. Otherwise, success. + fillInFIID(event: event) { fiidResult in + self.fireLogger.logEvent(event: event) { logResult in + switch logResult { + case .success(): + Logger.logDebug("Successfully logged Session Start event to GoogleDataTransport") + + switch fiidResult { + case .success(()): + callback(.success(())) + case let .failure(error): + callback(.failure(error)) + } + case let .failure(error): + callback(.failure(FirebaseSessionsError.DataTransportError(error))) + } + } + } + } + + private func fillInFIID(event: SessionStartEvent, + callback: @escaping (Result) + -> Void) { + installations.installationID { result in + switch result { + case let .success(installationsInfo): + event.setInstallationID(installationId: installationsInfo.0) + event.setAuthenticationToken(authenticationToken: installationsInfo.1) + callback(.success(())) + case let .failure(error): + event.setInstallationID(installationId: "") + event.setAuthenticationToken(authenticationToken: "") + callback(.failure(FirebaseSessionsError.SessionInstallationsError(error))) + } + } + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionGenerator.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionGenerator.swift new file mode 100644 index 0000000..bbd6e59 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionGenerator.swift @@ -0,0 +1,76 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import FirebaseInstallations + +struct SessionInfo { + let sessionId: String + let firstSessionId: String + let shouldDispatchEvents: Bool + let sessionIndex: Int32 + + init(sessionId: String, firstSessionId: String, dispatchEvents: Bool, sessionIndex: Int32) { + self.sessionId = sessionId + self.firstSessionId = firstSessionId + shouldDispatchEvents = dispatchEvents + self.sessionIndex = sessionIndex + } +} + +/// +/// Generator is responsible for: +/// 1) Generating the Session ID +/// 2) Persisting and reading the Session ID from the last session +/// (Maybe) 3) Persisting, reading, and incrementing an increasing index +/// +class SessionGenerator { + private var thisSession: SessionInfo? + + private var firstSessionId = "" + private var sessionIndex: Int32 + private var collectEvents: Bool + + init(collectEvents: Bool) { + // This will be incremented to 0 on the first generation + sessionIndex = -1 + + self.collectEvents = collectEvents + } + + // Generates a new Session ID. If there was already a generated Session ID + // from the last session during the app's lifecycle, it will also set the last Session ID + func generateNewSession() -> SessionInfo { + let newSessionId = UUID().uuidString.replacingOccurrences(of: "-", with: "").lowercased() + + // If firstSessionId is set, use it. Otherwise set it to the + // first generated Session ID + firstSessionId = firstSessionId.isEmpty ? newSessionId : firstSessionId + + sessionIndex += 1 + + let newSession = SessionInfo(sessionId: newSessionId, + firstSessionId: firstSessionId, + dispatchEvents: collectEvents, + sessionIndex: sessionIndex) + thisSession = newSession + return newSession + } + + var currentSession: SessionInfo? { + return thisSession + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionInitiator.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionInitiator.swift new file mode 100644 index 0000000..77cd8ee --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionInitiator.swift @@ -0,0 +1,136 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation +#if os(iOS) || os(tvOS) + import UIKit +#elseif os(macOS) + import AppKit + import Cocoa +#elseif os(watchOS) + import WatchKit +#endif // os(iOS) || os(tvOS) + +// swift(>=5.9) implies Xcode 15+ +// Need to have this Swift version check to use os(visionOS) macro, VisionOS support. +// TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above +// when Xcode 15 is the minimum supported by Firebase. +#if swift(>=5.9) + #if os(visionOS) + import UIKit + #endif // os(visionOS) +#endif // swift(>=5.9) + +/// +/// The SessionInitiator is responsible for: +/// 1) Running the initiate callback whenever a Session Start Event should +/// begin sending. This can happen at a cold start of the app, and when it +/// been in the background for a period of time (originally set at 30 mins) +/// and comes to the foreground. +/// +class SessionInitiator { + let currentTime: () -> Date + var settings: SettingsProtocol + var backgroundTime = Date.distantFuture + var initiateSessionStart: () -> Void = {} + + init(settings: SettingsProtocol, currentTimeProvider: @escaping () -> Date = Date.init) { + currentTime = currentTimeProvider + self.settings = settings + } + + func beginListening(initiateSessionStart: @escaping () -> Void) { + self.initiateSessionStart = initiateSessionStart + self.initiateSessionStart() + + let notificationCenter = NotificationCenter.default + #if os(iOS) || os(tvOS) + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) + notificationCenter.addObserver( + self, + selector: #selector(appForegrounded), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) + #elseif os(macOS) + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: NSApplication.didResignActiveNotification, + object: nil + ) + notificationCenter.addObserver( + self, + selector: #selector(appForegrounded), + name: NSApplication.didBecomeActiveNotification, + object: nil + ) + #elseif os(watchOS) + // Versions below WatchOS 7 do not support lifecycle events + if #available(watchOSApplicationExtension 7.0, *) { + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: WKExtension.applicationDidEnterBackgroundNotification, + object: nil + ) + notificationCenter.addObserver( + self, + selector: #selector(appForegrounded), + name: WKExtension.applicationDidBecomeActiveNotification, + object: nil + ) + } + #endif // os(iOS) || os(tvOS) + + // swift(>=5.9) implies Xcode 15+ + // Need to have this Swift version check to use os(visionOS) macro, VisionOS support. + // TODO: Remove this check and add `os(visionOS)` to the `os(iOS) || os(tvOS)` conditional above + // when Xcode 15 is the minimum supported by Firebase. + #if swift(>=5.9) + #if os(visionOS) + notificationCenter.addObserver( + self, + selector: #selector(appBackgrounded), + name: UIApplication.didEnterBackgroundNotification, + object: nil + ) + notificationCenter.addObserver( + self, + selector: #selector(appForegrounded), + name: UIApplication.didBecomeActiveNotification, + object: nil + ) + #endif // os(visionOS) + #endif // swift(>=5.9) + } + + @objc private func appBackgrounded() { + backgroundTime = currentTime() + } + + @objc private func appForegrounded() { + let interval = currentTime().timeIntervalSince(backgroundTime) + + // If the interval is greater the the session timeout duration, generate a new session. + if interval > settings.sessionTimeout { + initiateSessionStart() + } + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionStartEvent.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionStartEvent.swift new file mode 100644 index 0000000..eb1560a --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/SessionStartEvent.swift @@ -0,0 +1,300 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +@_implementationOnly import GoogleDataTransport + +#if SWIFT_PACKAGE + import FirebaseSessionsObjC +#endif // SWIFT_PACKAGE + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_Environment +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// +/// SessionStartEvent is responsible for: +/// 1) Writing fields to the Session proto +/// 2) Synthesizing itself for persisting to disk and logging to GoogleDataTransport +/// +class SessionStartEvent: NSObject, GDTCOREventDataObject { + var proto: firebase_appquality_sessions_SessionEvent + + init(sessionInfo: SessionInfo, appInfo: ApplicationInfoProtocol, + time: TimeProvider = Time()) { + proto = firebase_appquality_sessions_SessionEvent() + + super.init() + + // Note: If you add a proto string field here, remember to free it in the deinit. + proto.event_type = firebase_appquality_sessions_EventType_SESSION_START + proto.session_data.session_id = makeProtoString(sessionInfo.sessionId) + proto.session_data.first_session_id = makeProtoString(sessionInfo.firstSessionId) + proto.session_data.session_index = sessionInfo.sessionIndex + proto.session_data.event_timestamp_us = time.timestampUS + + proto.application_info.app_id = makeProtoString(appInfo.appID) + proto.application_info.session_sdk_version = makeProtoString(appInfo.sdkVersion) + proto.application_info.os_version = makeProtoString(appInfo.osDisplayVersion) + proto.application_info.log_environment = convertLogEnvironment(environment: appInfo.environment) + proto.application_info.device_model = makeProtoString(appInfo.deviceModel) +// proto.application_info.development_platform_name; +// proto.application_info.development_platform_version; + + // `which_platform_info` tells nanopb which oneof we're choosing to fill in for our proto + proto.application_info.which_platform_info = FIRSESGetAppleApplicationInfoTag() + proto.application_info.apple_app_info + .bundle_short_version = makeProtoString(appInfo.appDisplayVersion) + proto.application_info.apple_app_info + .app_build_version = makeProtoString(appInfo.appBuildVersion) + proto.application_info.apple_app_info.os_name = convertOSName(osName: appInfo.osName) + + // Set network info to base values but don't fill them in with the real + // value because these are only tracked when Performance is installed + proto.application_info.apple_app_info.mcc_mnc = makeProtoString("") + proto.application_info.apple_app_info.network_connection_info + .network_type = convertNetworkType(networkType: .none) + proto.application_info.apple_app_info.network_connection_info + .mobile_subtype = convertMobileSubtype(mobileSubtype: "") + + proto.session_data.data_collection_status + .crashlytics = firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED + proto.session_data.data_collection_status + .performance = firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED + } + + deinit { + let garbage: [UnsafeMutablePointer?] = [ + proto.application_info.app_id, + proto.application_info.apple_app_info.app_build_version, + proto.application_info.apple_app_info.bundle_short_version, + proto.application_info.apple_app_info.mcc_mnc, + proto.application_info.development_platform_name, + proto.application_info.development_platform_version, + proto.application_info.device_model, + proto.application_info.os_version, + proto.application_info.session_sdk_version, + proto.session_data.session_id, + proto.session_data.firebase_installation_id, + proto.session_data.firebase_authentication_token, + proto.session_data.first_session_id, + ] + for pointer in garbage { + nanopb_free(pointer) + } + } + + func setInstallationID(installationId: String) { + let oldID = proto.session_data.firebase_installation_id + proto.session_data.firebase_installation_id = makeProtoString(installationId) + nanopb_free(oldID) + } + + func setAuthenticationToken(authenticationToken: String) { + let oldToken = proto.session_data.firebase_authentication_token + proto.session_data.firebase_authentication_token = makeProtoString(authenticationToken) + nanopb_free(oldToken) + } + + func setSamplingRate(samplingRate: Double) { + proto.session_data.data_collection_status.session_sampling_rate = samplingRate + } + + func set(subscriber: SessionsSubscriberName, isDataCollectionEnabled: Bool, + appInfo: ApplicationInfoProtocol) { + let dataCollectionState = makeDataCollectionProto(isDataCollectionEnabled) + switch subscriber { + case .Crashlytics: + proto.session_data.data_collection_status.crashlytics = dataCollectionState + case .Performance: + proto.session_data.data_collection_status.performance = dataCollectionState + default: + Logger + .logWarning("Attempted to set Data Collection status for unknown Subscriber: \(subscriber)") + } + + // Only set restricted fields if Data Collection is enabled. If it's disabled, + // we're treating that as if the product isn't installed. + if isDataCollectionEnabled { + setRestrictedFields(subscriber: subscriber, + appInfo: appInfo) + } + } + + /// This method should be called for every subscribed Subscriber. This is for cases where + /// fields should only be collected if a specific SDK is installed. + private func setRestrictedFields(subscriber: SessionsSubscriberName, + appInfo: ApplicationInfoProtocol) { + switch subscriber { + case .Performance: + let oldString = proto.application_info.apple_app_info.mcc_mnc + proto.application_info.apple_app_info.mcc_mnc = makeProtoString("") + nanopb_free(oldString) + proto.application_info.apple_app_info.network_connection_info + .network_type = convertNetworkType(networkType: appInfo.networkInfo.networkType) + proto.application_info.apple_app_info.network_connection_info + .mobile_subtype = convertMobileSubtype(mobileSubtype: appInfo.networkInfo.mobileSubtype) + default: + break + } + } + + // MARK: - GDTCOREventDataObject + + func transportBytes() -> Data { + return FIRSESTransportBytes(&proto) + } + + // MARK: - Data Conversion + + func makeDataCollectionProto(_ isDataCollectionEnabled: Bool) + -> firebase_appquality_sessions_DataCollectionState { + if isDataCollectionEnabled { + return firebase_appquality_sessions_DataCollectionState_COLLECTION_ENABLED + } else { + return firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED + } + } + + private func makeProtoStringOrNil(_ string: String?) -> UnsafeMutablePointer? { + guard let string = string else { + return nil + } + return FIRSESEncodeString(string) + } + + private func makeProtoString(_ string: String) -> UnsafeMutablePointer? { + return FIRSESEncodeString(string) + } + + private func convertOSName(osName: String) -> firebase_appquality_sessions_OsName { + switch osName.lowercased() { + case "macos": + return firebase_appquality_sessions_OsName_MACOS + case "maccatalyst": + return firebase_appquality_sessions_OsName_MACCATALYST + case "ios_on_mac": + return firebase_appquality_sessions_OsName_IOS_ON_MAC + case "ios": + return firebase_appquality_sessions_OsName_IOS + case "tvos": + return firebase_appquality_sessions_OsName_TVOS + case "watchos": + return firebase_appquality_sessions_OsName_WATCHOS + case "ipados": + return firebase_appquality_sessions_OsName_IPADOS + default: + Logger.logWarning("Found unknown OSName: \"\(osName)\" while converting.") + return firebase_appquality_sessions_OsName_UNKNOWN_OSNAME + } + } + + /// Encodes the proto in this SessionStartEvent to Data, and then decodes the Data back into + /// the proto object and returns the decoded proto. This is used for validating encoding works + /// and should not be used in production code. + func encodeDecodeEvent() -> firebase_appquality_sessions_SessionEvent { + let transportBytes = self.transportBytes() + var proto = firebase_appquality_sessions_SessionEvent() + var fields = firebase_appquality_sessions_SessionEvent_fields + + let bytes = (transportBytes as NSData).bytes + var istream: pb_istream_t = pb_istream_from_buffer(bytes, transportBytes.count) + + if !pb_decode(&istream, &fields.0, &proto) { + let errorMessage = FIRSESPBGetError(istream) + if errorMessage.count > 0 { + Logger.logError("Session Event failed to decode transportBytes: \(errorMessage)") + } + } + return proto + } + + /// Converts the provided log environment to its Proto format. + private func convertLogEnvironment(environment: DevEnvironment) + -> firebase_appquality_sessions_LogEnvironment { + switch environment { + case .prod: + return firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD + case .staging: + return firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_STAGING + case .autopush: + return firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_AUTOPUSH + } + } + + private func convertNetworkType(networkType: GULNetworkType) + -> firebase_appquality_sessions_NetworkConnectionInfo_NetworkType { + switch networkType { + case .WIFI: + return firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_WIFI + case .mobile: + return firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE + case .none: + return firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_DUMMY + @unknown default: + return firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_DUMMY + } + } + + private func convertMobileSubtype(mobileSubtype: String) + -> firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype { + var subtype: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype + + #if os(iOS) && !targetEnvironment(macCatalyst) + switch mobileSubtype { + case CTRadioAccessTechnologyGPRS: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS + case CTRadioAccessTechnologyEdge: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE + case CTRadioAccessTechnologyWCDMA: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA + case CTRadioAccessTechnologyCDMA1x: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA + case CTRadioAccessTechnologyHSDPA: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA + case CTRadioAccessTechnologyHSUPA: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA + case CTRadioAccessTechnologyCDMAEVDORev0: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0 + case CTRadioAccessTechnologyCDMAEVDORevA: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A + case CTRadioAccessTechnologyCDMAEVDORevB: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B + case CTRadioAccessTechnologyeHRPD: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD + case CTRadioAccessTechnologyLTE: + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE + default: + subtype = + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE + } + + if #available(iOS 14.1, *) { + if mobileSubtype == CTRadioAccessTechnologyNRNSA || mobileSubtype == + CTRadioAccessTechnologyNR { + subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR + } + } + #else // os(iOS) && !targetEnvironment(macCatalyst) + subtype = + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE + #endif // os(iOS) && !targetEnvironment(macCatalyst) + + return subtype + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/LocalOverrideSettings.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/LocalOverrideSettings.swift new file mode 100644 index 0000000..9b92b2f --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/LocalOverrideSettings.swift @@ -0,0 +1,73 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Class that manages the local overrides configs related to the library. +class LocalOverrideSettings: SettingsProvider { + // This will disable Sessions SDK Events, but not Settings requests. + // If any apps use this flag to disable the Firebase Sessions SDK, + // keep in mind this may break metrics future features with products like + // FirePerf and Crashlytics. As a result, we would recommend apps + // use another way to disable data collection (like disabling it via + // the product public data collection APIs themselves). + // This flag is internal and may break in the future. + static let PlistKey_sessions_enabled = "FirebaseSessionsEnabled" + static let PlistKey_sessions_timeout = "FirebaseSessionsTimeout" + static let PlistKey_sessions_samplingRate = "FirebaseSessionsSampingRate" + + var sessionsEnabled: Bool? { + let session_enabled = plistValueForConfig(configName: LocalOverrideSettings + .PlistKey_sessions_enabled) as? Bool + if session_enabled != nil { + return Bool(session_enabled!) + } + return nil + } + + var sessionTimeout: TimeInterval? { + let timeout = plistValueForConfig(configName: LocalOverrideSettings + .PlistKey_sessions_timeout) as? Double + if timeout != nil { + return Double(timeout!) + } + return nil + } + + var samplingRate: Double? { + let rate = plistValueForConfig(configName: LocalOverrideSettings + .PlistKey_sessions_samplingRate) as? Double + if rate != nil { + return Double(rate!) + } + return nil + } + + private func plistValueForConfig(configName: String) -> Any? { + return Bundle.main.infoDictionary?[configName] + } +} + +typealias LocalOverrideSettingsProvider = LocalOverrideSettings +extension LocalOverrideSettingsProvider { + func updateSettings() { + // Nothing to be done since there is nothing to be updated. + } + + func isSettingsStale() -> Bool { + // Settings are never stale since all of these are local settings from Plist + return false + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/RemoteSettings.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/RemoteSettings.swift new file mode 100644 index 0000000..15dffb1 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/RemoteSettings.swift @@ -0,0 +1,134 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Extends ApplicationInfoProtocol to string-format a combined appDisplayVersion and +/// appBuildVersion +extension ApplicationInfoProtocol { + var synthesizedVersion: String { return "\(appDisplayVersion) (\(appBuildVersion))" } +} + +class RemoteSettings: SettingsProvider { + private static let cacheDurationSecondsDefault: TimeInterval = 60 * 60 + private static let flagSessionsEnabled = "sessions_enabled" + private static let flagSamplingRate = "sampling_rate" + private static let flagSessionTimeout = "session_timeout_seconds" + private static let flagCacheDuration = "cache_duration" + private static let flagSessionsCache = "app_quality" + private let appInfo: ApplicationInfoProtocol + private let downloader: SettingsDownloadClient + private var cache: SettingsCacheClient + + private var cacheDurationSeconds: TimeInterval { + guard let duration = cache.cacheContent[RemoteSettings.flagCacheDuration] as? Double else { + return RemoteSettings.cacheDurationSecondsDefault + } + return duration + } + + private var sessionsCache: [String: Any] { + return cache.cacheContent[RemoteSettings.flagSessionsCache] as? [String: Any] ?? [:] + } + + init(appInfo: ApplicationInfoProtocol, + downloader: SettingsDownloadClient, + cache: SettingsCacheClient = SettingsCache()) { + self.appInfo = appInfo + self.cache = cache + self.downloader = downloader + } + + private func fetchAndCacheSettings(currentTime: Date) { + // Only fetch if cache is expired, otherwise do nothing + guard isCacheExpired(time: currentTime) else { + Logger.logDebug("[Settings] Cache is not expired, no fetch will be made.") + return + } + + downloader.fetch { result in + switch result { + case let .success(dictionary): + // Saves all newly fetched Settings to cache + self.cache.cacheContent = dictionary + // Saves a "cache-key" which carries TTL metadata about current cache + self.cache.cacheKey = CacheKey( + createdAt: currentTime, + googleAppID: self.appInfo.appID, + appVersion: self.appInfo.synthesizedVersion + ) + case let .failure(error): + Logger.logError("[Settings] Fetching newest settings failed with error: \(error)") + } + } + } +} + +typealias RemoteSettingsConfigurations = RemoteSettings +extension RemoteSettingsConfigurations { + var sessionsEnabled: Bool? { + return sessionsCache[RemoteSettings.flagSessionsEnabled] as? Bool + } + + var samplingRate: Double? { + return sessionsCache[RemoteSettings.flagSamplingRate] as? Double + } + + var sessionTimeout: TimeInterval? { + return sessionsCache[RemoteSettings.flagSessionTimeout] as? Double + } +} + +typealias RemoteSettingsProvider = RemoteSettings +extension RemoteSettingsConfigurations { + func updateSettings(currentTime: Date) { + fetchAndCacheSettings(currentTime: currentTime) + } + + func updateSettings() { + updateSettings(currentTime: Date()) + } + + func isSettingsStale() -> Bool { + return isCacheExpired(time: Date()) + } + + private func isCacheExpired(time: Date) -> Bool { + guard !cache.cacheContent.isEmpty else { + cache.removeCache() + return true + } + guard let cacheKey = cache.cacheKey else { + Logger.logError("[Settings] Could not load settings cache key") + cache.removeCache() + return true + } + guard cacheKey.googleAppID == appInfo.appID else { + Logger + .logDebug("[Settings] Cache expired because Google App ID changed") + cache.removeCache() + return true + } + if time.timeIntervalSince(cacheKey.createdAt) > cacheDurationSeconds { + Logger.logDebug("[Settings] Cache TTL expired") + return true + } + if appInfo.synthesizedVersion != cacheKey.appVersion { + Logger.logDebug("[Settings] Cache expired because app version changed") + return true + } + return false + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SDKDefaultSettings.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SDKDefaultSettings.swift new file mode 100644 index 0000000..9c11822 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SDKDefaultSettings.swift @@ -0,0 +1,46 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Class that manages the local overrides configs related to the library. +class SDKDefaultSettings: SettingsProvider { + var sessionsEnabled: Bool? { + // Default is sessions enabled + return true + } + + var sessionTimeout: TimeInterval? { + // Default is 30 minutes + return 30 * 60 + } + + var samplingRate: Double? { + // Default is all events are dispatched + return 1.0 + } +} + +typealias SDKDefaultSettingsProvider = SDKDefaultSettings +extension SDKDefaultSettingsProvider { + func updateSettings() { + // Nothing to be done since there is nothing to be updated. + } + + func isSettingsStale() -> Bool { + // Settings are never stale since all of these are local settings from Plist + return false + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SessionsSettings.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SessionsSettings.swift new file mode 100644 index 0000000..1871eb4 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SessionsSettings.swift @@ -0,0 +1,84 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Class that manages the configs related to the settings library +class SessionsSettings: SettingsProtocol { + private let appInfo: ApplicationInfoProtocol + private let installations: InstallationsProtocol + private let sdkDefaults: SDKDefaultSettings + private let localOverrides: LocalOverrideSettings + private let remoteSettings: RemoteSettings + + convenience init(appInfo: ApplicationInfoProtocol, installations: InstallationsProtocol) { + self.init(appInfo: appInfo, + installations: installations, + sdkDefaults: SDKDefaultSettings(), + localOverrides: LocalOverrideSettings(), + remoteSettings: RemoteSettings(appInfo: appInfo, + downloader: SettingsDownloader(appInfo: appInfo, + installations: installations))) + } + + init(appInfo: ApplicationInfoProtocol, + installations: InstallationsProtocol, + sdkDefaults: SDKDefaultSettings, + localOverrides: LocalOverrideSettings, + remoteSettings: RemoteSettings) { + self.appInfo = appInfo + self.installations = installations + self.sdkDefaults = sdkDefaults + self.localOverrides = localOverrides + self.remoteSettings = remoteSettings + } + + var sessionsEnabled: Bool { + // Order of precedence LocalOverrides > Remote Settings > SDK Defaults + if let sessionEnabled = localOverrides.sessionsEnabled { + return sessionEnabled + } else if let sessionEnabled = remoteSettings.sessionsEnabled { + return sessionEnabled + } + return sdkDefaults.sessionsEnabled! + } + + var sessionTimeout: TimeInterval { + // Order of precedence LocalOverrides > Remote Settings > SDK Defaults + if let sessionTimeout = localOverrides.sessionTimeout { + return sessionTimeout + } else if let sessionTimeout = remoteSettings.sessionTimeout { + return sessionTimeout + } + return sdkDefaults.sessionTimeout! + } + + var samplingRate: Double { + // Order of precedence LocalOverrides > Remote Settings > SDK Defaults + if let samplingRate = localOverrides.samplingRate { + return samplingRate + } else if let samplingRate = remoteSettings.samplingRate { + return samplingRate + } + return sdkDefaults.samplingRate! + } + + func updateSettings() { + // Update the settings for all the settings providers + sdkDefaults.updateSettings() + remoteSettings.updateSettings() + localOverrides.updateSettings() + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift new file mode 100644 index 0000000..f02b4dd --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift @@ -0,0 +1,95 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_UserDefaults +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +/// CacheKey is like a "key" to a "safe". It provides necessary metadata about the current cache to +/// know if it should be expired. +struct CacheKey: Codable { + var createdAt: Date + var googleAppID: String + var appVersion: String +} + +/// SettingsCacheClient is responsible for accessing the cache that Settings are stored in. +protocol SettingsCacheClient { + /// Returns in-memory cache content in O(1) time. Returns empty dictionary if it does not exist in + /// cache. + var cacheContent: [String: Any] { get set } + /// Returns in-memory cache-key, no performance guarantee because type-casting depends on size of + /// CacheKey + var cacheKey: CacheKey? { get set } + /// Removes all cache content and cache-key + func removeCache() +} + +/// SettingsCache uses UserDefaults to store Settings on-disk, but also directly query UserDefaults +/// when accessing Settings values during run-time. This is because UserDefaults encapsulates both +/// in-memory and persisted-on-disk storage, allowing fast synchronous access in-app while hiding +/// away the complexity of managing persistence asynchronously. +class SettingsCache: SettingsCacheClient { + private static let settingsVersion: Int = 1 + private enum UserDefaultsKeys { + static let forContent = "firebase-sessions-settings" + static let forCacheKey = "firebase-sessions-cache-key" + } + + /// UserDefaults holds values in memory, making access O(1) and synchronous within the app, while + /// abstracting away async disk IO. + private let cache: GULUserDefaults = .standard() + + /// Converting to dictionary is O(1) because object conversion is O(1) + var cacheContent: [String: Any] { + get { + return (cache.object(forKey: UserDefaultsKeys.forContent) as? [String: Any]) ?? [:] + } + set { + cache.setObject(newValue, forKey: UserDefaultsKeys.forContent) + } + } + + /// Casting to Codable from Data is O(n) + var cacheKey: CacheKey? { + get { + if let data = cache.object(forKey: UserDefaultsKeys.forCacheKey) as? Data { + do { + return try JSONDecoder().decode(CacheKey.self, from: data) + } catch { + Logger.logError("[Settings] Decoding CacheKey failed with error: \(error)") + } + } + return nil + } + set { + do { + try cache.setObject(JSONEncoder().encode(newValue), forKey: UserDefaultsKeys.forCacheKey) + } catch { + Logger.logError("[Settings] Encoding CacheKey failed with error: \(error)") + } + } + } + + /// Removes stored cache + func removeCache() { + cache.setObject(nil, forKey: UserDefaultsKeys.forContent) + cache.setObject(nil, forKey: UserDefaultsKeys.forCacheKey) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift new file mode 100644 index 0000000..66cda8d --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift @@ -0,0 +1,107 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +#if SWIFT_PACKAGE + @_implementationOnly import GoogleUtilities_Environment +#else + @_implementationOnly import GoogleUtilities +#endif // SWIFT_PACKAGE + +protocol SettingsDownloadClient { + func fetch(completion: @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void) +} + +enum SettingsDownloaderError: Error { + /// Error constructing the URL + case URLError(String) + /// Error from the URLSession task + case URLSessionError(String) + /// Error parsing the JSON response from Settings + case JSONParseError(String) + /// Error getting the Installation ID + case InstallationIDError(String) +} + +class SettingsDownloader: SettingsDownloadClient { + private let appInfo: ApplicationInfoProtocol + private let installations: InstallationsProtocol + + init(appInfo: ApplicationInfoProtocol, installations: InstallationsProtocol) { + self.appInfo = appInfo + self.installations = installations + } + + func fetch(completion: @escaping (Result<[String: Any], SettingsDownloaderError>) -> Void) { + guard let validURL = url else { + completion(.failure(.URLError("Invalid URL"))) + return + } + + installations.installationID { result in + switch result { + case let .success(installationsInfo): + let request = self.buildRequest(url: validURL, fiid: installationsInfo.0) + let task = URLSession.shared.dataTask(with: request) { data, response, error in + if let data { + if let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any] { + completion(.success(dict)) + } else { + completion(.failure( + .JSONParseError("Failed to parse JSON to dictionary") + )) + } + } else if let error { + completion(.failure(.URLSessionError(error.localizedDescription))) + } + } + // Start the task that sends the network request + task.resume() + case let .failure(error): + completion(.failure(.InstallationIDError(error.localizedDescription))) + } + } + } + + private var url: URL? { + var components = URLComponents() + components.scheme = "https" + components.host = "firebase-settings.crashlytics.com" + components.path = "/spi/v2/platforms/\(appInfo.osName)/gmp/\(appInfo.appID)/settings" + components.queryItems = [ + URLQueryItem(name: "build_version", value: appInfo.appBuildVersion), + URLQueryItem(name: "display_version", value: appInfo.appDisplayVersion), + ] + return components.url + } + + private func buildRequest(url: URL, fiid: String) -> URLRequest { + var request = URLRequest(url: url) + request.setValue("application/json", forHTTPHeaderField: "Accept") + request.setValue(fiid, forHTTPHeaderField: "X-Crashlytics-Installation-ID") + request.setValue(appInfo.deviceModel, forHTTPHeaderField: "X-Crashlytics-Device-Model") + request.setValue( + appInfo.osBuildVersion, + forHTTPHeaderField: "X-Crashlytics-OS-Build-Version" + ) + request.setValue( + appInfo.osDisplayVersion, + forHTTPHeaderField: "X-Crashlytics-OS-Display-Version" + ) + request.setValue(appInfo.sdkVersion, forHTTPHeaderField: "X-Crashlytics-API-Client-Version") + return request + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProtocol.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProtocol.swift new file mode 100644 index 0000000..ab145ec --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProtocol.swift @@ -0,0 +1,31 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Provides the APIs to access Settings and their configuration values +protocol SettingsProtocol { + // Update the settings for all the settings providers + func updateSettings() + + // Config to show if sessions is enabled + var sessionsEnabled: Bool { get } + + // Config showing the sampling rate for sessions + var samplingRate: Double { get } + + // Background timeout config value before which a new session is generated + var sessionTimeout: TimeInterval { get } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProvider.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProvider.swift new file mode 100644 index 0000000..15ab257 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProvider.swift @@ -0,0 +1,35 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// APIs that needs to be implemented by any settings provider +protocol SettingsProvider { + // API to update the settings + func updateSettings() + + // API to check if the settings are stale + func isSettingsStale() -> Bool + + // Config to show if sessions is enabled + var sessionsEnabled: Bool? { get } + + // Config showing the sampling rate for sessions + + var samplingRate: Double? { get } + + // Background timeout config value before which a new session is generated + var sessionTimeout: TimeInterval? { get } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/Sources/Time.swift b/Pods/FirebaseSessions/FirebaseSessions/Sources/Time.swift new file mode 100644 index 0000000..24305e8 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/Sources/Time.swift @@ -0,0 +1,31 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +protocol TimeProvider { + var timestampUS: Int64 { get } +} + +/// +/// Time is provides timestamp values in different formats to classes in the Sessions SDK. It mainly +/// exists for testing purposes. +/// +class Time: TimeProvider { + // Returns the current time as a timestamp in microseconds + var timestampUS: Int64 { + return Int64(UInt64(Date().timeIntervalSince1970) * USEC_PER_SEC) + } +} diff --git a/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h new file mode 100644 index 0000000..e07f0e3 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h @@ -0,0 +1,99 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef FIRSESNanoPBHelpers_h +#define FIRSESNanoPBHelpers_h + +#import + +#import +#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \ + !TARGET_OS_OSX && !TARGET_OS_TV +#define TARGET_HAS_MOBILE_CONNECTIVITY +#import +#import +#endif + +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Deinitializes a nanopb struct. Rewritten here to expose to Swift, since `pb_free` is a macro. +void nanopb_free(void* _Nullable); + +/// Returns an error associated with the istream. Written in Objective-C because Swift does not +/// support C language macros +NSString* FIRSESPBGetError(pb_istream_t istream); + +// It seems impossible to specify the nullability of the `fields` parameter below, +// yet the compiler complains that it's missing a nullability specifier. Google +// yields no results at this time. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" +NSData* _Nullable FIRSESEncodeProto(const pb_field_t fields[], + const void* _Nonnull proto, + NSError** error); +#pragma clang diagnostic pop + +/// Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. +/// @note Memory needs to be freed manually, through pb_free or pb_release. +/// @param data The data to copy into the new bytes array. +pb_bytes_array_t* _Nullable FIRSESEncodeData(NSData* _Nullable data); + +/// Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. +/// @note Memory needs to be freed manually, through pb_free or pb_release. +/// @param string The string to encode as pb_bytes. +pb_bytes_array_t* _Nullable FIRSESEncodeString(NSString* _Nullable string); + +/// Decodes an array of nanopb bytes into an NSData object +/// @param pbData nanopb data +NSData* FIRSESDecodeData(pb_bytes_array_t* pbData); + +/// Decodes an array of nanopb bytes into an NSString object +/// @param pbData nanopb data +NSString* FIRSESDecodeString(pb_bytes_array_t* pbData); + +/// Checks if 2 nanopb arrays are equal +/// @param array array to check +/// @param expected expected value of the array +BOOL FIRSESIsPBArrayEqual(pb_bytes_array_t* _Nullable array, pb_bytes_array_t* _Nullable expected); + +/// Checks if a nanopb string is equal to an NSString +/// @param pbString nanopb string to check +/// @param str NSString that's expected +BOOL FIRSESIsPBStringEqual(pb_bytes_array_t* _Nullable pbString, NSString* _Nullable str); + +/// Checks if a nanopb array is equal to NSData +/// @param pbArray nanopb array to check +/// @param data NSData that's expected +BOOL FIRSESIsPBDataEqual(pb_bytes_array_t* _Nullable pbArray, NSData* _Nullable data); + +/// Returns the protobuf tag number. Use this to specify which oneof message type we are +/// using for the platform\_info field. This function is required to be in Objective-C because +/// Swift does not support c-style macros. +pb_size_t FIRSESGetAppleApplicationInfoTag(void); + +/// Returns sysctl entry, useful for obtaining OS build version from the kernel. Copied from a +/// private method in GULAppEnvironmentUtil. +NSString* _Nullable FIRSESGetSysctlEntry(const char* sysctlKey); + +/// C function to bridge from Swift to do nanopb bytes transfer. +NSData* FIRSESTransportBytes(const void* _Nonnull proto); + +NS_ASSUME_NONNULL_END + +#endif /* FIRSESNanoPBHelpers_h */ diff --git a/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m new file mode 100644 index 0000000..6440ec4 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m @@ -0,0 +1,205 @@ +// +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import + +#import "FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h" + +#import "FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h" + +@import FirebaseCoreExtension; + +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +void nanopb_free(void *_Nullable ptr) { + pb_free(ptr); +} + +NSError *FIRSESMakeEncodeError(NSString *description) { + return [NSError errorWithDomain:@"FIRSESEncodeError" + code:-1 + userInfo:@{@"NSLocalizedDescriptionKey" : description}]; +} + +NSString *FIRSESPBGetError(pb_istream_t istream) { + return [NSString stringWithCString:PB_GET_ERROR(&istream) encoding:NSASCIIStringEncoding]; +} + +// It seems impossible to specify the nullability of the `fields` parameter below, +// yet the compiler complains that it's missing a nullability specifier. Google +// yields no results at this time. +// +// Note 4/17/2023: The warning seems to be spurious (pb_field_t is a non-pointer +// type) and is not present on Xcode 14+. This pragma can be removed after the +// minimum supported Xcode version is above 14. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullability-completeness" +NSData *_Nullable FIRSESEncodeProto(const pb_field_t fields[], + const void *_Nonnull proto, + NSError **error) { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, fields, proto)) { + NSString *errorString = [NSString + stringWithFormat:@"Error in nanopb encoding to get size: %s", PB_GET_ERROR(&sizestream)]; + if (error != NULL) { + *error = FIRSESMakeEncodeError(errorString); + } + return nil; + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, fields, proto)) { + NSString *errorString = + [NSString stringWithFormat:@"Error in nanopb encoding: %s", PB_GET_ERROR(&sizestream)]; + if (error != NULL) { + *error = FIRSESMakeEncodeError(errorString); + } + CFBridgingRelease(dataRef); + return nil; + } + + return CFBridgingRelease(dataRef); +} +#pragma clang diagnostic pop + +/** Mallocs a pb_bytes_array and copies the given NSData bytes into the bytes array. + * @note Memory needs to be free manually, through pb_free or pb_release. + * @param data The data to copy into the new bytes array. + */ +pb_bytes_array_t *_Nullable FIRSESEncodeData(NSData *_Nullable data) { + pb_bytes_array_t *pbBytes = malloc(PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytes == NULL) { + return NULL; + } + [data getBytes:pbBytes->bytes length:data.length]; + pbBytes->size = (pb_size_t)data.length; + return pbBytes; +} + +/** Mallocs a pb_bytes_array and copies the given NSString's bytes into the bytes array. + * @note Memory needs to be freed manually, through pb_free or pb_release. + * @param string The string to encode as pb_bytes. + */ +pb_bytes_array_t *_Nullable FIRSESEncodeString(NSString *_Nullable string) { + if ([string isMemberOfClass:[NSNull class]]) { + string = nil; + } + NSString *stringToEncode = string ? string : @""; + NSData *stringBytes = [stringToEncode dataUsingEncoding:NSUTF8StringEncoding]; + return FIRSESEncodeData(stringBytes); +} + +NSData *FIRSESDecodeData(pb_bytes_array_t *pbData) { + NSData *data = [NSData dataWithBytes:&(pbData->bytes) length:pbData->size]; + return data; +} + +NSString *FIRSESDecodeString(pb_bytes_array_t *pbData) { + if (pbData->size == 0) { + return @""; + } + NSData *data = FIRSESDecodeData(pbData); + // There was a bug where length 32 strings were sometimes null after encoding + // and decoding. We found that this was due to the null terminator sometimes not + // being included in the decoded code. Using stringWithCString assumes the string + // is null terminated, so we switched to initWithBytes because it takes a length. + return [[NSString alloc] initWithBytes:data.bytes + length:data.length + encoding:NSUTF8StringEncoding]; +} + +BOOL FIRSESIsPBArrayEqual(pb_bytes_array_t *_Nullable array, pb_bytes_array_t *_Nullable expected) { + // Treat the empty string as the same as a missing field + if (array == nil) { + return expected->size == 0; + } + + if (array->size != expected->size) { + return false; + } + + for (int i = 0; i < array->size; i++) { + if (expected->bytes[i] != array->bytes[i]) { + return false; + } + } + + return true; +} + +BOOL FIRSESIsPBStringEqual(pb_bytes_array_t *_Nullable pbString, NSString *_Nullable str) { + pb_bytes_array_t *expected = FIRSESEncodeString(str); + return FIRSESIsPBArrayEqual(pbString, expected); +} + +BOOL FIRSESIsPBDataEqual(pb_bytes_array_t *_Nullable pbArray, NSData *_Nullable data) { + pb_bytes_array_t *expected = FIRSESEncodeData(data); + BOOL equal = FIRSESIsPBArrayEqual(pbArray, expected); + free(expected); + return equal; +} + +pb_size_t FIRSESGetAppleApplicationInfoTag(void) { + return firebase_appquality_sessions_ApplicationInfo_apple_app_info_tag; +} + +/// Copied from a private method in GULAppEnvironmentUtil. +NSString *_Nullable FIRSESGetSysctlEntry(const char *sysctlKey) { + static NSString *entryValue; + size_t size; + sysctlbyname(sysctlKey, NULL, &size, NULL, 0); + if (size > 0) { + char *entryValueCStr = malloc(size); + sysctlbyname(sysctlKey, entryValueCStr, &size, NULL, 0); + entryValue = [NSString stringWithCString:entryValueCStr encoding:NSUTF8StringEncoding]; + free(entryValueCStr); + return entryValue; + } else { + return nil; + } +} + +NSData *FIRSESTransportBytes(const void *_Nonnull proto) { + const pb_field_t *fields = firebase_appquality_sessions_SessionEvent_fields; + NSError *error; + NSData *data = FIRSESEncodeProto(fields, proto, &error); + if (error != nil) { + FIRLogError( + @"FirebaseSessions", @"I-SES000001", @"%@", + [NSString stringWithFormat:@"Session Event failed to encode as proto with error: %@", + error.debugDescription]); + } + if (data == nil) { + data = [NSData data]; + FIRLogError(@"FirebaseSessions", @"I-SES000002", + @"Session Event generated nil transportBytes. Returning empty data."); + } + return data; +} + +NS_ASSUME_NONNULL_END diff --git a/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.c b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.c new file mode 100644 index 0000000..f89596a --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.c @@ -0,0 +1,125 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t firebase_appquality_sessions_SessionEvent_fields[4] = { + PB_FIELD( 1, UENUM , SINGULAR, STATIC , FIRST, firebase_appquality_sessions_SessionEvent, event_type, event_type, 0), + PB_FIELD( 2, MESSAGE , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_SessionEvent, session_data, event_type, &firebase_appquality_sessions_SessionInfo_fields), + PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_SessionEvent, application_info, session_data, &firebase_appquality_sessions_ApplicationInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_NetworkConnectionInfo_fields[3] = { + PB_FIELD( 1, UENUM , SINGULAR, STATIC , FIRST, firebase_appquality_sessions_NetworkConnectionInfo, network_type, network_type, 0), + PB_FIELD( 2, UENUM , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_NetworkConnectionInfo, mobile_subtype, network_type, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_SessionInfo_fields[8] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_SessionInfo, session_id, session_id, 0), + PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_SessionInfo, firebase_installation_id, session_id, 0), + PB_FIELD( 4, INT64 , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_SessionInfo, event_timestamp_us, firebase_installation_id, 0), + PB_FIELD( 6, MESSAGE , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_SessionInfo, data_collection_status, event_timestamp_us, &firebase_appquality_sessions_DataCollectionStatus_fields), + PB_FIELD( 7, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_SessionInfo, first_session_id, data_collection_status, 0), + PB_FIELD( 8, INT32 , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_SessionInfo, session_index, first_session_id, 0), + PB_FIELD( 9, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_SessionInfo, firebase_authentication_token, session_index, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_DataCollectionStatus_fields[4] = { + PB_FIELD( 1, UENUM , SINGULAR, STATIC , FIRST, firebase_appquality_sessions_DataCollectionStatus, performance, performance, 0), + PB_FIELD( 2, UENUM , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_DataCollectionStatus, crashlytics, performance, 0), + PB_FIELD( 3, DOUBLE , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_DataCollectionStatus, session_sampling_rate, crashlytics, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_ApplicationInfo_fields[10] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_ApplicationInfo, app_id, app_id, 0), + PB_FIELD( 2, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, device_model, app_id, 0), + PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, development_platform_name, device_model, 0), + PB_FIELD( 4, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, development_platform_version, development_platform_name, 0), + PB_ANONYMOUS_ONEOF_FIELD(platform_info, 5, MESSAGE , ONEOF, STATIC , OTHER, firebase_appquality_sessions_ApplicationInfo, android_app_info, development_platform_version, &firebase_appquality_sessions_AndroidApplicationInfo_fields), + PB_ANONYMOUS_ONEOF_FIELD(platform_info, 6, MESSAGE , ONEOF, STATIC , UNION, firebase_appquality_sessions_ApplicationInfo, apple_app_info, development_platform_version, &firebase_appquality_sessions_AppleApplicationInfo_fields), + PB_FIELD( 7, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, session_sdk_version, apple_app_info, 0), + PB_FIELD( 8, UENUM , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_ApplicationInfo, log_environment, session_sdk_version, 0), + PB_FIELD( 9, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_ApplicationInfo, os_version, log_environment, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_AndroidApplicationInfo_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_AndroidApplicationInfo, package_name, package_name, 0), + PB_FIELD( 3, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AndroidApplicationInfo, version_name, package_name, 0), + PB_LAST_FIELD +}; + +const pb_field_t firebase_appquality_sessions_AppleApplicationInfo_fields[6] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, firebase_appquality_sessions_AppleApplicationInfo, bundle_short_version, bundle_short_version, 0), + PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_AppleApplicationInfo, network_connection_info, bundle_short_version, &firebase_appquality_sessions_NetworkConnectionInfo_fields), + PB_FIELD( 4, UENUM , SINGULAR, STATIC , OTHER, firebase_appquality_sessions_AppleApplicationInfo, os_name, network_connection_info, 0), + PB_FIELD( 5, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AppleApplicationInfo, mcc_mnc, os_name, 0), + PB_FIELD( 6, BYTES , SINGULAR, POINTER , OTHER, firebase_appquality_sessions_AppleApplicationInfo, app_build_version, mcc_mnc, 0), + PB_LAST_FIELD +}; + + + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(firebase_appquality_sessions_SessionEvent, session_data) < 65536 && pb_membersize(firebase_appquality_sessions_SessionEvent, application_info) < 65536 && pb_membersize(firebase_appquality_sessions_SessionInfo, data_collection_status) < 65536 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, android_app_info) < 65536 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, apple_app_info) < 65536 && pb_membersize(firebase_appquality_sessions_AppleApplicationInfo, network_connection_info) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_firebase_appquality_sessions_SessionEvent_firebase_appquality_sessions_NetworkConnectionInfo_firebase_appquality_sessions_SessionInfo_firebase_appquality_sessions_DataCollectionStatus_firebase_appquality_sessions_ApplicationInfo_firebase_appquality_sessions_AndroidApplicationInfo_firebase_appquality_sessions_AppleApplicationInfo) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(firebase_appquality_sessions_SessionEvent, session_data) < 256 && pb_membersize(firebase_appquality_sessions_SessionEvent, application_info) < 256 && pb_membersize(firebase_appquality_sessions_SessionInfo, data_collection_status) < 256 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, android_app_info) < 256 && pb_membersize(firebase_appquality_sessions_ApplicationInfo, apple_app_info) < 256 && pb_membersize(firebase_appquality_sessions_AppleApplicationInfo, network_connection_info) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_firebase_appquality_sessions_SessionEvent_firebase_appquality_sessions_NetworkConnectionInfo_firebase_appquality_sessions_SessionInfo_firebase_appquality_sessions_DataCollectionStatus_firebase_appquality_sessions_ApplicationInfo_firebase_appquality_sessions_AndroidApplicationInfo_firebase_appquality_sessions_AppleApplicationInfo) +#endif + + +/* On some platforms (such as AVR), double is really float. + * These are not directly supported by nanopb, but see example_avr_double. + * To get rid of this error, remove any double fields from your .proto. + */ +PB_STATIC_ASSERT(sizeof(double) == 8, DOUBLE_MUST_BE_8_BYTES) + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h new file mode 100644 index 0000000..5b604e9 --- /dev/null +++ b/Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h @@ -0,0 +1,270 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_FIREBASE_APPQUALITY_SESSIONS_SESSIONS_NANOPB_H_INCLUDED +#define PB_FIREBASE_APPQUALITY_SESSIONS_SESSIONS_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _firebase_appquality_sessions_EventType { + firebase_appquality_sessions_EventType_EVENT_TYPE_UNKNOWN = 0, + firebase_appquality_sessions_EventType_SESSION_START = 1 +} firebase_appquality_sessions_EventType; +#define _firebase_appquality_sessions_EventType_MIN firebase_appquality_sessions_EventType_EVENT_TYPE_UNKNOWN +#define _firebase_appquality_sessions_EventType_MAX firebase_appquality_sessions_EventType_SESSION_START +#define _firebase_appquality_sessions_EventType_ARRAYSIZE ((firebase_appquality_sessions_EventType)(firebase_appquality_sessions_EventType_SESSION_START+1)) + +typedef enum _firebase_appquality_sessions_DataCollectionState { + firebase_appquality_sessions_DataCollectionState_COLLECTION_UNKNOWN = 0, + firebase_appquality_sessions_DataCollectionState_COLLECTION_SDK_NOT_INSTALLED = 1, + firebase_appquality_sessions_DataCollectionState_COLLECTION_ENABLED = 2, + firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED = 3, + firebase_appquality_sessions_DataCollectionState_COLLECTION_DISABLED_REMOTE = 4, + firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED = 5 +} firebase_appquality_sessions_DataCollectionState; +#define _firebase_appquality_sessions_DataCollectionState_MIN firebase_appquality_sessions_DataCollectionState_COLLECTION_UNKNOWN +#define _firebase_appquality_sessions_DataCollectionState_MAX firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED +#define _firebase_appquality_sessions_DataCollectionState_ARRAYSIZE ((firebase_appquality_sessions_DataCollectionState)(firebase_appquality_sessions_DataCollectionState_COLLECTION_SAMPLED+1)) + +typedef enum _firebase_appquality_sessions_OsName { + firebase_appquality_sessions_OsName_UNKNOWN_OSNAME = 0, + firebase_appquality_sessions_OsName_MACOS = 1, + firebase_appquality_sessions_OsName_MACCATALYST = 2, + firebase_appquality_sessions_OsName_IOS_ON_MAC = 3, + firebase_appquality_sessions_OsName_IOS = 4, + firebase_appquality_sessions_OsName_TVOS = 5, + firebase_appquality_sessions_OsName_WATCHOS = 6, + firebase_appquality_sessions_OsName_IPADOS = 7, + firebase_appquality_sessions_OsName_UNSPECIFIED = 8 +} firebase_appquality_sessions_OsName; +#define _firebase_appquality_sessions_OsName_MIN firebase_appquality_sessions_OsName_UNKNOWN_OSNAME +#define _firebase_appquality_sessions_OsName_MAX firebase_appquality_sessions_OsName_UNSPECIFIED +#define _firebase_appquality_sessions_OsName_ARRAYSIZE ((firebase_appquality_sessions_OsName)(firebase_appquality_sessions_OsName_UNSPECIFIED+1)) + +typedef enum _firebase_appquality_sessions_LogEnvironment { + firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_UNKNOWN = 0, + firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_AUTOPUSH = 1, + firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_STAGING = 2, + firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD = 3 +} firebase_appquality_sessions_LogEnvironment; +#define _firebase_appquality_sessions_LogEnvironment_MIN firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_UNKNOWN +#define _firebase_appquality_sessions_LogEnvironment_MAX firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD +#define _firebase_appquality_sessions_LogEnvironment_ARRAYSIZE ((firebase_appquality_sessions_LogEnvironment)(firebase_appquality_sessions_LogEnvironment_LOG_ENVIRONMENT_PROD+1)) + +typedef enum _firebase_appquality_sessions_NetworkConnectionInfo_NetworkType { + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE = 0, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_WIFI = 1, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_WIMAX = 6, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_DUMMY = 8, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_ETHERNET = 9, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_PROXY = 16, + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_VPN = 17 +} firebase_appquality_sessions_NetworkConnectionInfo_NetworkType; +#define _firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MIN firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MOBILE +#define _firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MAX firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_VPN +#define _firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((firebase_appquality_sessions_NetworkConnectionInfo_NetworkType)(firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_VPN+1)) + +typedef enum _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype { + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS = 1, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE = 2, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UMTS = 3, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA = 4, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_RTT = 7, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA = 8, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA = 9, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSPA = 10, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_IDEN = 11, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE = 13, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD = 14, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSPAP = 15, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GSM = 16, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_IWLAN = 18, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR = 20, + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_COMBINED = 100 +} firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype; +#define _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_MIN firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE +#define _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_MAX firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_COMBINED +#define _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype)(firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_COMBINED+1)) + +/* Struct definitions */ +typedef struct _firebase_appquality_sessions_AndroidApplicationInfo { + pb_bytes_array_t *package_name; + pb_bytes_array_t *version_name; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_AndroidApplicationInfo) */ +} firebase_appquality_sessions_AndroidApplicationInfo; + +typedef struct _firebase_appquality_sessions_DataCollectionStatus { + firebase_appquality_sessions_DataCollectionState performance; + firebase_appquality_sessions_DataCollectionState crashlytics; + double session_sampling_rate; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_DataCollectionStatus) */ +} firebase_appquality_sessions_DataCollectionStatus; + +typedef struct _firebase_appquality_sessions_NetworkConnectionInfo { + firebase_appquality_sessions_NetworkConnectionInfo_NetworkType network_type; + firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype mobile_subtype; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_NetworkConnectionInfo) */ +} firebase_appquality_sessions_NetworkConnectionInfo; + +typedef struct _firebase_appquality_sessions_AppleApplicationInfo { + pb_bytes_array_t *bundle_short_version; + firebase_appquality_sessions_NetworkConnectionInfo network_connection_info; + firebase_appquality_sessions_OsName os_name; + pb_bytes_array_t *mcc_mnc; + pb_bytes_array_t *app_build_version; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_AppleApplicationInfo) */ +} firebase_appquality_sessions_AppleApplicationInfo; + +typedef struct _firebase_appquality_sessions_SessionInfo { + pb_bytes_array_t *session_id; + pb_bytes_array_t *firebase_installation_id; + int64_t event_timestamp_us; + firebase_appquality_sessions_DataCollectionStatus data_collection_status; + pb_bytes_array_t *first_session_id; + int32_t session_index; + pb_bytes_array_t *firebase_authentication_token; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_SessionInfo) */ +} firebase_appquality_sessions_SessionInfo; + +typedef struct _firebase_appquality_sessions_ApplicationInfo { + pb_bytes_array_t *app_id; + pb_bytes_array_t *device_model; + pb_bytes_array_t *development_platform_name; + pb_bytes_array_t *development_platform_version; + pb_size_t which_platform_info; + union { + firebase_appquality_sessions_AndroidApplicationInfo android_app_info; + firebase_appquality_sessions_AppleApplicationInfo apple_app_info; + }; + pb_bytes_array_t *session_sdk_version; + firebase_appquality_sessions_LogEnvironment log_environment; + pb_bytes_array_t *os_version; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_ApplicationInfo) */ +} firebase_appquality_sessions_ApplicationInfo; + +typedef struct _firebase_appquality_sessions_SessionEvent { + firebase_appquality_sessions_EventType event_type; + firebase_appquality_sessions_SessionInfo session_data; + firebase_appquality_sessions_ApplicationInfo application_info; +/* @@protoc_insertion_point(struct:firebase_appquality_sessions_SessionEvent) */ +} firebase_appquality_sessions_SessionEvent; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define firebase_appquality_sessions_SessionEvent_init_default {_firebase_appquality_sessions_EventType_MIN, firebase_appquality_sessions_SessionInfo_init_default, firebase_appquality_sessions_ApplicationInfo_init_default} +#define firebase_appquality_sessions_NetworkConnectionInfo_init_default {_firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MIN, _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_MIN} +#define firebase_appquality_sessions_SessionInfo_init_default {NULL, NULL, 0, firebase_appquality_sessions_DataCollectionStatus_init_default, NULL, 0} +#define firebase_appquality_sessions_DataCollectionStatus_init_default {_firebase_appquality_sessions_DataCollectionState_MIN, _firebase_appquality_sessions_DataCollectionState_MIN, 0} +#define firebase_appquality_sessions_ApplicationInfo_init_default {NULL, NULL, NULL, NULL, 0, {firebase_appquality_sessions_AndroidApplicationInfo_init_default}, NULL, _firebase_appquality_sessions_LogEnvironment_MIN, NULL} +#define firebase_appquality_sessions_AndroidApplicationInfo_init_default {NULL, NULL} +#define firebase_appquality_sessions_AppleApplicationInfo_init_default {NULL, firebase_appquality_sessions_NetworkConnectionInfo_init_default, _firebase_appquality_sessions_OsName_MIN, NULL, NULL} +#define firebase_appquality_sessions_SessionEvent_init_zero {_firebase_appquality_sessions_EventType_MIN, firebase_appquality_sessions_SessionInfo_init_zero, firebase_appquality_sessions_ApplicationInfo_init_zero} +#define firebase_appquality_sessions_NetworkConnectionInfo_init_zero {_firebase_appquality_sessions_NetworkConnectionInfo_NetworkType_MIN, _firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_MIN} +#define firebase_appquality_sessions_SessionInfo_init_zero {NULL, NULL, 0, firebase_appquality_sessions_DataCollectionStatus_init_zero, NULL, 0} +#define firebase_appquality_sessions_DataCollectionStatus_init_zero {_firebase_appquality_sessions_DataCollectionState_MIN, _firebase_appquality_sessions_DataCollectionState_MIN, 0} +#define firebase_appquality_sessions_ApplicationInfo_init_zero {NULL, NULL, NULL, NULL, 0, {firebase_appquality_sessions_AndroidApplicationInfo_init_zero}, NULL, _firebase_appquality_sessions_LogEnvironment_MIN, NULL} +#define firebase_appquality_sessions_AndroidApplicationInfo_init_zero {NULL, NULL} +#define firebase_appquality_sessions_AppleApplicationInfo_init_zero {NULL, firebase_appquality_sessions_NetworkConnectionInfo_init_zero, _firebase_appquality_sessions_OsName_MIN, NULL, NULL} + +/* Field tags (for use in manual encoding/decoding) */ +#define firebase_appquality_sessions_AndroidApplicationInfo_package_name_tag 1 +#define firebase_appquality_sessions_AndroidApplicationInfo_version_name_tag 3 +#define firebase_appquality_sessions_DataCollectionStatus_performance_tag 1 +#define firebase_appquality_sessions_DataCollectionStatus_crashlytics_tag 2 +#define firebase_appquality_sessions_DataCollectionStatus_session_sampling_rate_tag 3 +#define firebase_appquality_sessions_NetworkConnectionInfo_network_type_tag 1 +#define firebase_appquality_sessions_NetworkConnectionInfo_mobile_subtype_tag 2 +#define firebase_appquality_sessions_AppleApplicationInfo_bundle_short_version_tag 1 +#define firebase_appquality_sessions_AppleApplicationInfo_app_build_version_tag 6 +#define firebase_appquality_sessions_AppleApplicationInfo_network_connection_info_tag 3 +#define firebase_appquality_sessions_AppleApplicationInfo_os_name_tag 4 +#define firebase_appquality_sessions_AppleApplicationInfo_mcc_mnc_tag 5 +#define firebase_appquality_sessions_SessionInfo_session_id_tag 1 +#define firebase_appquality_sessions_SessionInfo_first_session_id_tag 7 +#define firebase_appquality_sessions_SessionInfo_session_index_tag 8 +#define firebase_appquality_sessions_SessionInfo_firebase_installation_id_tag 3 +#define firebase_appquality_sessions_SessionInfo_event_timestamp_us_tag 4 +#define firebase_appquality_sessions_SessionInfo_data_collection_status_tag 6 +#define firebase_appquality_sessions_SessionInfo_firebase_authentication_token_tag 9 +#define firebase_appquality_sessions_ApplicationInfo_android_app_info_tag 5 +#define firebase_appquality_sessions_ApplicationInfo_apple_app_info_tag 6 +#define firebase_appquality_sessions_ApplicationInfo_app_id_tag 1 +#define firebase_appquality_sessions_ApplicationInfo_device_model_tag 2 +#define firebase_appquality_sessions_ApplicationInfo_development_platform_name_tag 3 +#define firebase_appquality_sessions_ApplicationInfo_development_platform_version_tag 4 +#define firebase_appquality_sessions_ApplicationInfo_session_sdk_version_tag 7 +#define firebase_appquality_sessions_ApplicationInfo_os_version_tag 9 +#define firebase_appquality_sessions_ApplicationInfo_log_environment_tag 8 +#define firebase_appquality_sessions_SessionEvent_event_type_tag 1 +#define firebase_appquality_sessions_SessionEvent_session_data_tag 2 +#define firebase_appquality_sessions_SessionEvent_application_info_tag 3 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t firebase_appquality_sessions_SessionEvent_fields[4]; +extern const pb_field_t firebase_appquality_sessions_NetworkConnectionInfo_fields[3]; +extern const pb_field_t firebase_appquality_sessions_SessionInfo_fields[8]; +extern const pb_field_t firebase_appquality_sessions_DataCollectionStatus_fields[4]; +extern const pb_field_t firebase_appquality_sessions_ApplicationInfo_fields[10]; +extern const pb_field_t firebase_appquality_sessions_AndroidApplicationInfo_fields[3]; +extern const pb_field_t firebase_appquality_sessions_AppleApplicationInfo_fields[6]; + +/* Maximum encoded size of messages (where known) */ +/* firebase_appquality_sessions_SessionEvent_size depends on runtime parameters */ +#define firebase_appquality_sessions_NetworkConnectionInfo_size 4 +/* firebase_appquality_sessions_SessionInfo_size depends on runtime parameters */ +#define firebase_appquality_sessions_DataCollectionStatus_size 13 +/* firebase_appquality_sessions_ApplicationInfo_size depends on runtime parameters */ +/* firebase_appquality_sessions_AndroidApplicationInfo_size depends on runtime parameters */ +/* firebase_appquality_sessions_AppleApplicationInfo_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define SESSIONS_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/FirebaseSessions/LICENSE b/Pods/FirebaseSessions/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/FirebaseSessions/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseSessions/README.md b/Pods/FirebaseSessions/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseSessions/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/FirebaseSharedSwift/FirebaseSharedSwift/LICENSE b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/LICENSE new file mode 100644 index 0000000..a1c8b37 --- /dev/null +++ b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/LICENSE @@ -0,0 +1,412 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + ## Runtime Library Exception to the Apache 2.0 License: ## + + + As an exception, if you use this Software to compile your source code and + portions of this Software are embedded into the binary product as a result, + you may redistribute such product without providing attribution as would + otherwise be required by Sections 4(a), 4(b) and 4(d) of the License. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/FirebaseRemoteConfigValueDecoding.swift b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/FirebaseRemoteConfigValueDecoding.swift new file mode 100644 index 0000000..39482c0 --- /dev/null +++ b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/FirebaseRemoteConfigValueDecoding.swift @@ -0,0 +1,26 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Conform to this protocol for the Firebase Decoder to extract values as from a RemoteConfigValue +/// object. +public protocol FirebaseRemoteConfigValueDecoding { + func numberValue() -> NSNumber + func boolValue() -> Bool + func stringValue() -> String + func dataValue() -> Data + func arrayValue() -> [AnyHashable]? + func dictionaryValue() -> [String: AnyHashable]? +} diff --git a/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift new file mode 100644 index 0000000..76bea35 --- /dev/null +++ b/Pods/FirebaseSharedSwift/FirebaseSharedSwift/Sources/third_party/FirebaseDataEncoder/FirebaseDataEncoder.swift @@ -0,0 +1,2644 @@ +// This file is derived from swift/stdlib/public/Darwin/Foundation/JSONEncoder.swift + +//===----------------------------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import Foundation + +public protocol StructureCodingPassthroughTypeResolver { + static func isPassthroughType(_ t: T) -> Bool +} + +private struct NoPassthroughTypes: StructureCodingPassthroughTypeResolver { + static func isPassthroughType(_ t: T) -> Bool { + return false + } +} + +public protocol StructureCodingUncodedUnkeyed {} + +extension DecodingError { + /// Returns a `.typeMismatch` error describing the expected type. + /// + /// - parameter path: The path of `CodingKey`s taken to decode a value of this type. + /// - parameter expectation: The type expected to be encountered. + /// - parameter reality: The value that was encountered instead of the expected type. + /// - returns: A `DecodingError` with the appropriate path and debug description. + internal static func _typeMismatch(at path: [CodingKey], expectation: Any.Type, reality: Any) -> DecodingError { + let description = "Expected to decode \(expectation) but found \(_typeDescription(of: reality)) instead." + return .typeMismatch(expectation, Context(codingPath: path, debugDescription: description)) + } + + /// Returns a description of the type of `value` appropriate for an error message. + /// + /// - parameter value: The value whose type to describe. + /// - returns: A string describing `value`. + /// - precondition: `value` is one of the types below. + fileprivate static func _typeDescription(of value: Any) -> String { + if value is NSNull { + return "a null value" + } else if value is NSNumber /* FIXME: If swift-corelibs-foundation isn't updated to use NSNumber, this check will be necessary: || value is Int || value is Double */ { + return "a number" + } else if value is String { + return "a string/data" + } else if value is [Any] { + return "an array" + } else if value is [String : Any] { + return "a dictionary" + } else { + return "\(type(of: value))" + } + } +} + + +/// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary` +/// containing `Encodable` values (in which case it should be exempt from key conversion strategies). +/// +/// NOTE: The architecture and environment check is due to a bug in the current (2018-08-08) Swift 4.2 +/// runtime when running on i386 simulator. The issue is tracked in https://bugs.swift.org/browse/SR-8276 +/// Making the protocol `internal` instead of `fileprivate` works around this issue. +/// Once SR-8276 is fixed, this check can be removed and the protocol always be made fileprivate. +#if arch(i386) || arch(arm) +internal protocol _JSONStringDictionaryEncodableMarker { } +#else +fileprivate protocol _JSONStringDictionaryEncodableMarker { } +#endif + +extension Dictionary : _JSONStringDictionaryEncodableMarker where Key == String, Value: Encodable { } + +/// A marker protocol used to determine whether a value is a `String`-keyed `Dictionary` +/// containing `Decodable` values (in which case it should be exempt from key conversion strategies). +/// +/// The marker protocol also provides access to the type of the `Decodable` values, +/// which is needed for the implementation of the key conversion strategy exemption. +/// +/// NOTE: Please see comment above regarding SR-8276 +#if arch(i386) || arch(arm) +internal protocol _JSONStringDictionaryDecodableMarker { + static var elementType: Decodable.Type { get } +} +#else +fileprivate protocol _JSONStringDictionaryDecodableMarker { + static var elementType: Decodable.Type { get } +} +#endif + +extension Dictionary : _JSONStringDictionaryDecodableMarker where Key == String, Value: Decodable { + static var elementType: Decodable.Type { return Value.self } +} + +//===----------------------------------------------------------------------===// +// JSON Encoder +//===----------------------------------------------------------------------===// + +/// `JSONEncoder` facilitates the encoding of `Encodable` values into JSON. +// NOTE: older overlays had Foundation.JSONEncoder as the ObjC name. +// The two must coexist, so it was renamed. The old name must not be +// used in the new runtime. _TtC10Foundation13__JSONEncoder is the +// mangled name for Foundation.__JSONEncoder. + +public class FirebaseDataEncoder { + // MARK: Options + + /// The strategy to use for encoding `Date` values. + public enum DateEncodingStrategy { + /// Defer to `Date` for choosing an encoding. This is the default strategy. + case deferredToDate + + /// Encode the `Date` as a UNIX timestamp (as a JSON number). + case secondsSince1970 + + /// Encode the `Date` as UNIX millisecond timestamp (as a JSON number). + case millisecondsSince1970 + + /// Encode the `Date` as an ISO-8601-formatted string (in RFC 3339 format). + case iso8601 + + /// Encode the `Date` as a string formatted by the given formatter. + case formatted(DateFormatter) + + /// Encode the `Date` as a custom value encoded by the given closure. + /// + /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. + case custom((Date, Swift.Encoder) throws -> Void) + } + + /// The strategy to use for encoding `Data` values. + public enum DataEncodingStrategy { + /// Defer to `Data` for choosing an encoding. + case deferredToData + + /// Encode the `Data` as a Base64-encoded string. This is the default strategy. + case base64 + + /// Encode the `Data` as an `NSData` blob. + case blob + + /// Encode the `Data` as a custom value encoded by the given closure. + /// + /// If the closure fails to encode a value into the given encoder, the encoder will encode an empty automatic container in its place. + case custom((Data, Swift.Encoder) throws -> Void) + } + + /// The strategy to use for non-JSON-conforming floating-point values (IEEE 754 infinity and NaN). + public enum NonConformingFloatEncodingStrategy { + /// Throw upon encountering non-conforming values. This is the default strategy. + case `throw` + + /// Encode the values using the given representation strings. + case convertToString(positiveInfinity: String, negativeInfinity: String, nan: String) + } + + /// The strategy to use for automatically changing the value of keys before encoding. + public enum KeyEncodingStrategy { + /// Use the keys specified by each type. This is the default strategy. + case useDefaultKeys + + /// Convert from "camelCaseKeys" to "snake_case_keys" before writing a key to JSON payload. + /// + /// Capital characters are determined by testing membership in `CharacterSet.uppercaseLetters` and `CharacterSet.lowercaseLetters` (Unicode General Categories Lu and Lt). + /// The conversion to lower case uses `Locale.system`, also known as the ICU "root" locale. This means the result is consistent regardless of the current user's locale and language preferences. + /// + /// Converting from camel case to snake case: + /// 1. Splits words at the boundary of lower-case to upper-case + /// 2. Inserts `_` between words + /// 3. Lowercases the entire string + /// 4. Preserves starting and ending `_`. + /// + /// For example, `oneTwoThree` becomes `one_two_three`. `_oneTwoThree_` becomes `_one_two_three_`. + /// + /// - Note: Using a key encoding strategy has a nominal performance cost, as each string key has to be converted. + case convertToSnakeCase + + /// Provide a custom conversion to the key in the encoded JSON from the keys specified by the encoded types. + /// The full path to the current encoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before encoding. + /// If the result of the conversion is a duplicate key, then only one value will be present in the result. + case custom((_ codingPath: [CodingKey]) -> CodingKey) + + fileprivate static func _convertToSnakeCase(_ stringKey: String) -> String { + guard !stringKey.isEmpty else { return stringKey } + + var words : [Range] = [] + // The general idea of this algorithm is to split words on transition from lower to upper case, then on transition of >1 upper case characters to lowercase + // + // myProperty -> my_property + // myURLProperty -> my_url_property + // + // We assume, per Swift naming conventions, that the first character of the key is lowercase. + var wordStart = stringKey.startIndex + var searchRange = stringKey.index(after: wordStart)..1 capital letters. Turn those into a word, stopping at the capital before the lower case character. + let beforeLowerIndex = stringKey.index(before: lowerCaseRange.lowerBound) + words.append(upperCaseRange.lowerBound..(_ value: T) throws -> Any { + let encoder = __JSONEncoder(options: self.options) + + guard let topLevel = try encoder.box_(value) else { + throw Swift.EncodingError.invalidValue(value, + Swift.EncodingError.Context(codingPath: [], debugDescription: "Top-level \(T.self) did not encode any values.")) + } + return topLevel + } +} + +// MARK: - __JSONEncoder + +// NOTE: older overlays called this class _JSONEncoder. +// The two must coexist without a conflicting ObjC class name, so it +// was renamed. The old name must not be used in the new runtime. +fileprivate class __JSONEncoder : Encoder { + // MARK: Properties + + /// The encoder's storage. + fileprivate var storage: _JSONEncodingStorage + + /// Options set on the top-level encoder. + fileprivate let options: FirebaseDataEncoder._Options + + /// The path to the current point in encoding. + public var codingPath: [CodingKey] + + /// Contextual user-provided information for use during encoding. + public var userInfo: [CodingUserInfoKey : Any] { + return self.options.userInfo + } + + // MARK: - Initialization + + /// Initializes `self` with the given top-level encoder options. + fileprivate init(options: FirebaseDataEncoder._Options, codingPath: [CodingKey] = []) { + self.options = options + self.storage = _JSONEncodingStorage() + self.codingPath = codingPath + } + + /// Returns whether a new element can be encoded at this coding path. + /// + /// `true` if an element has not yet been encoded at this coding path; `false` otherwise. + fileprivate var canEncodeNewValue: Bool { + // Every time a new value gets encoded, the key it's encoded for is pushed onto the coding path (even if it's a nil key from an unkeyed container). + // At the same time, every time a container is requested, a new value gets pushed onto the storage stack. + // If there are more values on the storage stack than on the coding path, it means the value is requesting more than one container, which violates the precondition. + // + // This means that anytime something that can request a new container goes onto the stack, we MUST push a key onto the coding path. + // Things which will not request containers do not need to have the coding path extended for them (but it doesn't matter if it is, because they will not reach here). + return self.storage.count == self.codingPath.count + } + + // MARK: - Encoder Methods + public func container(keyedBy: Key.Type) -> KeyedEncodingContainer { + // If an existing keyed container was already requested, return that one. + let topContainer: NSMutableDictionary + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushKeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableDictionary else { + preconditionFailure("Attempt to push new keyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + + let container = _JSONKeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + return KeyedEncodingContainer(container) + } + + public func unkeyedContainer() -> UnkeyedEncodingContainer { + // If an existing unkeyed container was already requested, return that one. + let topContainer: NSMutableArray + if self.canEncodeNewValue { + // We haven't yet pushed a container at this level; do so here. + topContainer = self.storage.pushUnkeyedContainer() + } else { + guard let container = self.storage.containers.last as? NSMutableArray else { + preconditionFailure("Attempt to push new unkeyed encoding container when already previously encoded at this path.") + } + + topContainer = container + } + + return _JSONUnkeyedEncodingContainer(referencing: self, codingPath: self.codingPath, wrapping: topContainer) + } + + public func singleValueContainer() -> SingleValueEncodingContainer { + return self + } +} + +// MARK: - Encoding Storage and Containers + +fileprivate struct _JSONEncodingStorage { + // MARK: Properties + + /// The container stack. + /// Elements may be any one of the JSON types (NSNull, NSNumber, NSString, NSArray, NSDictionary). + private(set) fileprivate var containers: [NSObject] = [] + + // MARK: - Initialization + + /// Initializes `self` with no containers. + fileprivate init() {} + + // MARK: - Modifying the Stack + + fileprivate var count: Int { + return self.containers.count + } + + fileprivate mutating func pushKeyedContainer() -> NSMutableDictionary { + let dictionary = NSMutableDictionary() + self.containers.append(dictionary) + return dictionary + } + + fileprivate mutating func pushUnkeyedContainer() -> NSMutableArray { + let array = NSMutableArray() + self.containers.append(array) + return array + } + + fileprivate mutating func push(container: __owned NSObject) { + self.containers.append(container) + } + + fileprivate mutating func popContainer() -> NSObject { + precondition(!self.containers.isEmpty, "Empty container stack.") + return self.containers.popLast()! + } +} + +// MARK: - Encoding Containers + +fileprivate struct _JSONKeyedEncodingContainer : KeyedEncodingContainerProtocol { + typealias Key = K + + // MARK: Properties + + /// A reference to the encoder we're writing to. + private let encoder: __JSONEncoder + + /// A reference to the container we're writing to. + private let container: NSMutableDictionary + + /// The path of coding keys taken to get to this point in encoding. + private(set) public var codingPath: [CodingKey] + + // MARK: - Initialization + + /// Initializes `self` with the given references. + fileprivate init(referencing encoder: __JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableDictionary) { + self.encoder = encoder + self.codingPath = codingPath + self.container = container + } + + // MARK: - Coding Path Operations + + private func _converted(_ key: CodingKey) -> CodingKey { + switch encoder.options.keyEncodingStrategy { + case .useDefaultKeys: + return key + case .convertToSnakeCase: + let newKeyString = FirebaseDataEncoder.KeyEncodingStrategy._convertToSnakeCase(key.stringValue) + return _JSONKey(stringValue: newKeyString, intValue: key.intValue) + case .custom(let converter): + return converter(codingPath + [key]) + } + } + + // MARK: - KeyedEncodingContainerProtocol Methods + + public mutating func encodeNil(forKey key: Key) throws { + self.container[_converted(key).stringValue] = NSNull() + } + public mutating func encode(_ value: Bool, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: Int, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: Int8, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: Int16, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: Int32, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: Int64, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: UInt, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: UInt8, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: UInt16, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: UInt32, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: UInt64, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + public mutating func encode(_ value: String, forKey key: Key) throws { + self.container[_converted(key).stringValue] = self.encoder.box(value) + } + + public mutating func encode(_ value: Float, forKey key: Key) throws { + // Since the float may be invalid and throw, the coding path needs to contain this key. + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[_converted(key).stringValue] = try self.encoder.box(value) + } + + public mutating func encode(_ value: Double, forKey key: Key) throws { + // Since the double may be invalid and throw, the coding path needs to contain this key. + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[_converted(key).stringValue] = try self.encoder.box(value) + } + + public mutating func encode(_ value: T, forKey key: Key) throws { + if T.self is StructureCodingUncodedUnkeyed.Type { return } + self.encoder.codingPath.append(key) + defer { self.encoder.codingPath.removeLast() } + self.container[_converted(key).stringValue] = try self.encoder.box(value) + } + + public mutating func nestedContainer(keyedBy keyType: NestedKey.Type, forKey key: Key) -> KeyedEncodingContainer { + let containerKey = _converted(key).stringValue + let dictionary: NSMutableDictionary + if let existingContainer = self.container[containerKey] { + precondition( + existingContainer is NSMutableDictionary, + "Attempt to re-encode into nested KeyedEncodingContainer<\(Key.self)> for key \"\(containerKey)\" is invalid: non-keyed container already encoded for this key" + ) + dictionary = existingContainer as! NSMutableDictionary + } else { + dictionary = NSMutableDictionary() + self.container[containerKey] = dictionary + } + + self.codingPath.append(key) + defer { self.codingPath.removeLast() } + + let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + return KeyedEncodingContainer(container) + } + + public mutating func nestedUnkeyedContainer(forKey key: Key) -> UnkeyedEncodingContainer { + let containerKey = _converted(key).stringValue + let array: NSMutableArray + if let existingContainer = self.container[containerKey] { + precondition( + existingContainer is NSMutableArray, + "Attempt to re-encode into nested UnkeyedEncodingContainer for key \"\(containerKey)\" is invalid: keyed container/single value already encoded for this key" + ) + array = existingContainer as! NSMutableArray + } else { + array = NSMutableArray() + self.container[containerKey] = array + } + + self.codingPath.append(key) + defer { self.codingPath.removeLast() } + return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + } + + public mutating func superEncoder() -> Encoder { + return __JSONReferencingEncoder(referencing: self.encoder, key: _JSONKey.super, convertedKey: _converted(_JSONKey.super), wrapping: self.container) + } + + public mutating func superEncoder(forKey key: Key) -> Encoder { + return __JSONReferencingEncoder(referencing: self.encoder, key: key, convertedKey: _converted(key), wrapping: self.container) + } +} + +fileprivate struct _JSONUnkeyedEncodingContainer : UnkeyedEncodingContainer { + // MARK: Properties + + /// A reference to the encoder we're writing to. + private let encoder: __JSONEncoder + + /// A reference to the container we're writing to. + private let container: NSMutableArray + + /// The path of coding keys taken to get to this point in encoding. + private(set) public var codingPath: [CodingKey] + + /// The number of elements encoded into the container. + public var count: Int { + return self.container.count + } + + // MARK: - Initialization + + /// Initializes `self` with the given references. + fileprivate init(referencing encoder: __JSONEncoder, codingPath: [CodingKey], wrapping container: NSMutableArray) { + self.encoder = encoder + self.codingPath = codingPath + self.container = container + } + + // MARK: - UnkeyedEncodingContainer Methods + + public mutating func encodeNil() throws { self.container.add(NSNull()) } + public mutating func encode(_ value: Bool) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int16) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int32) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: Int64) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt8) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt16) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt32) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: UInt64) throws { self.container.add(self.encoder.box(value)) } + public mutating func encode(_ value: String) throws { self.container.add(self.encoder.box(value)) } + + public mutating func encode(_ value: Float) throws { + // Since the float may be invalid and throw, the coding path needs to contain this key. + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) + } + + public mutating func encode(_ value: Double) throws { + // Since the double may be invalid and throw, the coding path needs to contain this key. + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) + } + + public mutating func encode(_ value: T) throws { + self.encoder.codingPath.append(_JSONKey(index: self.count)) + defer { self.encoder.codingPath.removeLast() } + self.container.add(try self.encoder.box(value)) + } + + public mutating func nestedContainer(keyedBy keyType: NestedKey.Type) -> KeyedEncodingContainer { + self.codingPath.append(_JSONKey(index: self.count)) + defer { self.codingPath.removeLast() } + + let dictionary = NSMutableDictionary() + self.container.add(dictionary) + + let container = _JSONKeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: dictionary) + return KeyedEncodingContainer(container) + } + + public mutating func nestedUnkeyedContainer() -> UnkeyedEncodingContainer { + self.codingPath.append(_JSONKey(index: self.count)) + defer { self.codingPath.removeLast() } + + let array = NSMutableArray() + self.container.add(array) + return _JSONUnkeyedEncodingContainer(referencing: self.encoder, codingPath: self.codingPath, wrapping: array) + } + + public mutating func superEncoder() -> Encoder { + return __JSONReferencingEncoder(referencing: self.encoder, at: self.container.count, wrapping: self.container) + } +} + +extension __JSONEncoder : SingleValueEncodingContainer { + // MARK: - SingleValueEncodingContainer Methods + + fileprivate func assertCanEncodeNewValue() { + precondition(self.canEncodeNewValue, "Attempt to encode value through single value container when previously value already encoded.") + } + + public func encodeNil() throws { + assertCanEncodeNewValue() + self.storage.push(container: NSNull()) + } + + public func encode(_ value: Bool) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Int) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Int8) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Int16) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Int32) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Int64) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: UInt) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: UInt8) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: UInt16) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: UInt32) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: UInt64) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: String) throws { + assertCanEncodeNewValue() + self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Float) throws { + assertCanEncodeNewValue() + try self.storage.push(container: self.box(value)) + } + + public func encode(_ value: Double) throws { + assertCanEncodeNewValue() + try self.storage.push(container: self.box(value)) + } + + public func encode(_ value: T) throws { + assertCanEncodeNewValue() + try self.storage.push(container: self.box(value)) + } +} + +// MARK: - Concrete Value Representations + +extension __JSONEncoder { + /// Returns the given value boxed in a container appropriate for pushing onto the container stack. + fileprivate func box(_ value: Bool) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: Int64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt8) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt16) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt32) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: UInt64) -> NSObject { return NSNumber(value: value) } + fileprivate func box(_ value: String) -> NSObject { return NSString(string: value) } + + fileprivate func box(_ float: Float) throws -> NSObject { + guard !float.isInfinite && !float.isNaN else { + guard case let .convertToString(positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(float, at: codingPath) + } + + if float == Float.infinity { + return NSString(string: posInfString) + } else if float == -Float.infinity { + return NSString(string: negInfString) + } else { + return NSString(string: nanString) + } + } + + return NSNumber(value: float) + } + + fileprivate func box(_ double: Double) throws -> NSObject { + guard !double.isInfinite && !double.isNaN else { + guard case let .convertToString(positiveInfinity: posInfString, + negativeInfinity: negInfString, + nan: nanString) = self.options.nonConformingFloatEncodingStrategy else { + throw EncodingError._invalidFloatingPointValue(double, at: codingPath) + } + + if double == Double.infinity { + return NSString(string: posInfString) + } else if double == -Double.infinity { + return NSString(string: negInfString) + } else { + return NSString(string: nanString) + } + } + + return NSNumber(value: double) + } + + fileprivate func box(_ date: Date) throws -> NSObject { + switch self.options.dateEncodingStrategy { + case .deferredToDate: + // Must be called with a surrounding with(pushedKey:) call. + // Dates encode as single-value objects; this can't both throw and push a container, so no need to catch the error. + try date.encode(to: self) + return self.storage.popContainer() + + case .secondsSince1970: + return NSNumber(value: date.timeIntervalSince1970) + + case .millisecondsSince1970: + return NSNumber(value: 1000.0 * date.timeIntervalSince1970) + + case .iso8601: + return NSString(string: _iso8601Formatter.string(from: date)) + + case .formatted(let formatter): + return NSString(string: formatter.string(from: date)) + + case .custom(let closure): + let depth = self.storage.count + do { + try closure(date, self) + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popContainer() + } + + throw error + } + + guard self.storage.count > depth else { + // The closure didn't encode anything. Return the default keyed container. + return NSDictionary() + } + + // We can pop because the closure encoded something. + return self.storage.popContainer() + } + } + + fileprivate func box(_ data: Data) throws -> NSObject { + switch self.options.dataEncodingStrategy { + case .deferredToData: + // Must be called with a surrounding with(pushedKey:) call. + let depth = self.storage.count + do { + try data.encode(to: self) + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + // This shouldn't be possible for Data (which encodes as an array of bytes), but it can't hurt to catch a failure. + if self.storage.count > depth { + let _ = self.storage.popContainer() + } + + throw error + } + + return self.storage.popContainer() + + case .base64: + return NSString(string: data.base64EncodedString()) + + case .blob: + return data as NSData + + case .custom(let closure): + let depth = self.storage.count + do { + try closure(data, self) + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popContainer() + } + + throw error + } + + guard self.storage.count > depth else { + // The closure didn't encode anything. Return the default keyed container. + return NSDictionary() + } + + // We can pop because the closure encoded something. + return self.storage.popContainer() + } + } + + fileprivate func box(_ dict: [String : Encodable]) throws -> NSObject? { + let depth = self.storage.count + let result = self.storage.pushKeyedContainer() + do { + for (key, value) in dict { + self.codingPath.append(_JSONKey(stringValue: key, intValue: nil)) + defer { self.codingPath.removeLast() } + result[key] = try box(value) + } + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popContainer() + } + + throw error + } + + // The top container should be a new container. + guard self.storage.count > depth else { + return nil + } + + return self.storage.popContainer() + } + + fileprivate func box(_ value: Encodable) throws -> NSObject { + return try self.box_(value) ?? NSDictionary() + } + + // This method is called "box_" instead of "box" to disambiguate it from the overloads. Because the return type here is different from all of the "box" overloads (and is more general), any "box" calls in here would call back into "box" recursively instead of calling the appropriate overload, which is not what we want. + fileprivate func box_(_ value: Encodable) throws -> NSObject? { + // Disambiguation between variable and function is required due to + // issue tracked at: https://bugs.swift.org/browse/SR-1846 + let type = Swift.type(of: value) + if type == Date.self || type == NSDate.self { + // Respect Date encoding strategy + return try self.box((value as! Date)) + } else if type == Data.self || type == NSData.self { + // Respect Data encoding strategy + return try self.box((value as! Data)) + } else if type == URL.self || type == NSURL.self { + // Encode URLs as single strings. + return self.box((value as! URL).absoluteString) + } else if type == Decimal.self || type == NSDecimalNumber.self { + // JSONSerialization can natively handle NSDecimalNumber. + return (value as! NSDecimalNumber) + } else if value is _JSONStringDictionaryEncodableMarker { + return try self.box(value as! [String : Encodable]) + } else if let object = value as? NSObject, self.options.passthroughTypeResolver.isPassthroughType(value) { + return object + } + + // The value should request a container from the __JSONEncoder. + let depth = self.storage.count + do { + try value.encode(to: self) + } catch { + // If the value pushed a container before throwing, pop it back off to restore state. + if self.storage.count > depth { + let _ = self.storage.popContainer() + } + + throw error + } + + // The top container should be a new container. + guard self.storage.count > depth else { + return nil + } + + return self.storage.popContainer() + } +} + +// MARK: - __JSONReferencingEncoder + +/// __JSONReferencingEncoder is a special subclass of __JSONEncoder which has its own storage, but references the contents of a different encoder. +/// It's used in superEncoder(), which returns a new encoder for encoding a superclass -- the lifetime of the encoder should not escape the scope it's created in, but it doesn't necessarily know when it's done being used (to write to the original container). +// NOTE: older overlays called this class _JSONReferencingEncoder. +// The two must coexist without a conflicting ObjC class name, so it +// was renamed. The old name must not be used in the new runtime. +fileprivate class __JSONReferencingEncoder : __JSONEncoder { + // MARK: Reference types. + + /// The type of container we're referencing. + private enum Reference { + /// Referencing a specific index in an array container. + case array(NSMutableArray, Int) + + /// Referencing a specific key in a dictionary container. + case dictionary(NSMutableDictionary, String) + } + + // MARK: - Properties + + /// The encoder we're referencing. + fileprivate let encoder: __JSONEncoder + + /// The container reference itself. + private let reference: Reference + + // MARK: - Initialization + + /// Initializes `self` by referencing the given array container in the given encoder. + fileprivate init(referencing encoder: __JSONEncoder, at index: Int, wrapping array: NSMutableArray) { + self.encoder = encoder + self.reference = .array(array, index) + super.init(options: encoder.options, codingPath: encoder.codingPath) + + self.codingPath.append(_JSONKey(index: index)) + } + + /// Initializes `self` by referencing the given dictionary container in the given encoder. + fileprivate init(referencing encoder: __JSONEncoder, + key: CodingKey, convertedKey: __shared CodingKey, wrapping dictionary: NSMutableDictionary) { + self.encoder = encoder + self.reference = .dictionary(dictionary, convertedKey.stringValue) + super.init(options: encoder.options, codingPath: encoder.codingPath) + + self.codingPath.append(key) + } + + // MARK: - Coding Path Operations + + fileprivate override var canEncodeNewValue: Bool { + // With a regular encoder, the storage and coding path grow together. + // A referencing encoder, however, inherits its parents coding path, as well as the key it was created for. + // We have to take this into account. + return self.storage.count == self.codingPath.count - self.encoder.codingPath.count - 1 + } + + // MARK: - Deinitialization + + // Finalizes `self` by writing the contents of our storage to the referenced encoder's storage. + deinit { + let value: Any + switch self.storage.count { + case 0: value = NSDictionary() + case 1: value = self.storage.popContainer() + default: fatalError("Referencing encoder deallocated with multiple containers on stack.") + } + + switch self.reference { + case .array(let array, let index): + array.insert(value, at: index) + + case .dictionary(let dictionary, let key): + dictionary[NSString(string: key)] = value + } + } +} + +//===----------------------------------------------------------------------===// +// JSON Decoder +//===----------------------------------------------------------------------===// + +/// `JSONDecoder` facilitates the decoding of JSON into semantic `Decodable` types. +// NOTE: older overlays had Foundation.JSONDecoder as the ObjC name. +// The two must coexist, so it was renamed. The old name must not be +// used in the new runtime. _TtC10Foundation13__JSONDecoder is the +// mangled name for Foundation.__JSONDecoder. +public class FirebaseDataDecoder { + // MARK: Options + + /// The strategy to use for decoding `Date` values. + public enum DateDecodingStrategy { + /// Defer to `Date` for decoding. This is the default strategy. + case deferredToDate + + /// Decode the `Date` as a UNIX timestamp from a JSON number. + case secondsSince1970 + + /// Decode the `Date` as UNIX millisecond timestamp from a JSON number. + case millisecondsSince1970 + + /// Decode the `Date` as an ISO-8601-formatted string (in RFC 3339 format). + case iso8601 + + /// Decode the `Date` as a string parsed by the given formatter. + case formatted(DateFormatter) + + /// Decode the `Date` as a custom value decoded by the given closure. + case custom((_ decoder: Swift.Decoder) throws -> Date) + } + + /// The strategy to use for decoding `Data` values. + public enum DataDecodingStrategy { + /// Defer to `Data` for decoding. + case deferredToData + + /// Decode the `Data` from a Base64-encoded string. This is the default strategy. + case base64 + + /// Decode the `Data` as an `NSData` blob. + case blob + + /// Decode the `Data` as a custom value decoded by the given closure. + case custom((_ decoder: Swift.Decoder) throws -> Data) + } + + /// The strategy to use for non-JSON-conforming floating-point values (IEEE 754 infinity and NaN). + public enum NonConformingFloatDecodingStrategy { + /// Throw upon encountering non-conforming values. This is the default strategy. + case `throw` + + /// Decode the values from the given representation strings. + case convertFromString(positiveInfinity: String, negativeInfinity: String, nan: String) + } + + /// The strategy to use for automatically changing the value of keys before decoding. + public enum KeyDecodingStrategy { + /// Use the keys specified by each type. This is the default strategy. + case useDefaultKeys + + /// Convert from "snake_case_keys" to "camelCaseKeys" before attempting to match a key with the one specified by each type. + /// + /// The conversion to upper case uses `Locale.system`, also known as the ICU "root" locale. This means the result is consistent regardless of the current user's locale and language preferences. + /// + /// Converting from snake case to camel case: + /// 1. Capitalizes the word starting after each `_` + /// 2. Removes all `_` + /// 3. Preserves starting and ending `_` (as these are often used to indicate private variables or other metadata). + /// For example, `one_two_three` becomes `oneTwoThree`. `_one_two_three_` becomes `_oneTwoThree_`. + /// + /// - Note: Using a key decoding strategy has a nominal performance cost, as each string key has to be inspected for the `_` character. + case convertFromSnakeCase + + /// Provide a custom conversion from the key in the encoded JSON to the keys specified by the decoded types. + /// The full path to the current decoding position is provided for context (in case you need to locate this key within the payload). The returned key is used in place of the last component in the coding path before decoding. + /// If the result of the conversion is a duplicate key, then only one value will be present in the container for the type to decode from. + case custom((_ codingPath: [CodingKey]) -> CodingKey) + + fileprivate static func _convertFromSnakeCase(_ stringKey: String) -> String { + guard !stringKey.isEmpty else { return stringKey } + + // Find the first non-underscore character + guard let firstNonUnderscore = stringKey.firstIndex(where: { $0 != "_" }) else { + // Reached the end without finding an _ + return stringKey + } + + // Find the last non-underscore character + var lastNonUnderscore = stringKey.index(before: stringKey.endIndex) + while lastNonUnderscore > firstNonUnderscore && stringKey[lastNonUnderscore] == "_" { + stringKey.formIndex(before: &lastNonUnderscore) + } + + let keyRange = firstNonUnderscore...lastNonUnderscore + let leadingUnderscoreRange = stringKey.startIndex..(_ type: T.Type, from structure: Any) throws -> T { + let decoder = __JSONDecoder(referencing: structure, options: self.options) + guard let value = try decoder.unbox(structure, as: type) else { + throw Swift.DecodingError.valueNotFound(type, Swift.DecodingError.Context(codingPath: [], debugDescription: "The given data did not contain a top-level value.")) + } + + return value + } +} + +// MARK: - __JSONDecoder + +// NOTE: older overlays called this class _JSONDecoder. The two must +// coexist without a conflicting ObjC class name, so it was renamed. +// The old name must not be used in the new runtime. +fileprivate class __JSONDecoder : Decoder { + // MARK: Properties + + /// The decoder's storage. + fileprivate var storage: _JSONDecodingStorage + + /// Options set on the top-level decoder. + fileprivate let options: FirebaseDataDecoder._Options + + /// The path to the current point in encoding. + fileprivate(set) public var codingPath: [CodingKey] + + /// Contextual user-provided information for use during encoding. + public var userInfo: [CodingUserInfoKey : Any] { + return self.options.userInfo + } + + // MARK: - Initialization + + /// Initializes `self` with the given top-level container and options. + fileprivate init(referencing container: Any, at codingPath: [CodingKey] = [], options: FirebaseDataDecoder._Options) { + self.storage = _JSONDecodingStorage() + self.storage.push(container: container) + self.codingPath = codingPath + self.options = options + } + + // MARK: - Decoder Methods + + public func container(keyedBy type: Key.Type) throws -> KeyedDecodingContainer { + guard !(self.storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + } + var topContainer : [String : Any] + if let rcValue = self.storage.topContainer as? FirebaseRemoteConfigValueDecoding { + guard let top = rcValue.dictionaryValue() else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, + reality: rcValue) + } + topContainer = top + } else { + guard let top = self.storage.topContainer as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: self.storage.topContainer) + } + topContainer = top + } + + let container = _JSONKeyedDecodingContainer(referencing: self, wrapping: topContainer) + return KeyedDecodingContainer(container) + } + + public func unkeyedContainer() throws -> UnkeyedDecodingContainer { + guard !(self.storage.topContainer is NSNull) else { + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get unkeyed decoding container -- found null value instead.")) + } + + if let rcValue = self.storage.topContainer as? FirebaseRemoteConfigValueDecoding { + guard let arrayValue = rcValue.arrayValue() else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: rcValue) + } + return _JSONUnkeyedDecodingContainer(referencing: self, wrapping: arrayValue ) + } + + guard let topContainer = self.storage.topContainer as? [Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: self.storage.topContainer) + } + + return _JSONUnkeyedDecodingContainer(referencing: self, wrapping: topContainer) + } + + public func singleValueContainer() throws -> SingleValueDecodingContainer { + return self + } +} + +// MARK: - Decoding Storage + +fileprivate struct _JSONDecodingStorage { + // MARK: Properties + + /// The container stack. + /// Elements may be any one of the JSON types (NSNull, NSNumber, String, Array, [String : Any]). + private(set) fileprivate var containers: [Any] = [] + + // MARK: - Initialization + + /// Initializes `self` with no containers. + fileprivate init() {} + + // MARK: - Modifying the Stack + + fileprivate var count: Int { + return self.containers.count + } + + fileprivate var topContainer: Any { + precondition(!self.containers.isEmpty, "Empty container stack.") + return self.containers.last! + } + + fileprivate mutating func push(container: __owned Any) { + self.containers.append(container) + } + + fileprivate mutating func popContainer() { + precondition(!self.containers.isEmpty, "Empty container stack.") + self.containers.removeLast() + } +} + +// MARK: Decoding Containers + +fileprivate struct _JSONKeyedDecodingContainer : KeyedDecodingContainerProtocol { + typealias Key = K + + // MARK: Properties + + /// A reference to the decoder we're reading from. + private let decoder: __JSONDecoder + + /// A reference to the container we're reading from. + private let container: [String : Any] + + /// The path of coding keys taken to get to this point in decoding. + private(set) public var codingPath: [CodingKey] + + // MARK: - Initialization + + /// Initializes `self` by referencing the given decoder and container. + fileprivate init(referencing decoder: __JSONDecoder, wrapping container: [String : Any]) { + self.decoder = decoder + switch decoder.options.keyDecodingStrategy { + case .useDefaultKeys: + self.container = container + case .convertFromSnakeCase: + // Convert the snake case keys in the container to camel case. + // If we hit a duplicate key after conversion, then we'll use the first one we saw. Effectively an undefined behavior with JSON dictionaries. + self.container = Dictionary(container.map { + key, value in (FirebaseDataDecoder.KeyDecodingStrategy._convertFromSnakeCase(key), value) + }, uniquingKeysWith: { (first, _) in first }) + case .custom(let converter): + self.container = Dictionary(container.map { + key, value in (converter(decoder.codingPath + [_JSONKey(stringValue: key, intValue: nil)]).stringValue, value) + }, uniquingKeysWith: { (first, _) in first }) + } + self.codingPath = decoder.codingPath + } + + // MARK: - KeyedDecodingContainerProtocol Methods + + public var allKeys: [Key] { + return self.container.keys.compactMap { Key(stringValue: $0) } + } + + public func contains(_ key: Key) -> Bool { + return self.container[key.stringValue] != nil + } + + private func _errorDescription(of key: CodingKey) -> String { + switch decoder.options.keyDecodingStrategy { + case .convertFromSnakeCase: + // In this case we can attempt to recover the original value by reversing the transform + let original = key.stringValue + let converted = FirebaseDataEncoder.KeyEncodingStrategy._convertToSnakeCase(original) + let roundtrip = FirebaseDataDecoder.KeyDecodingStrategy._convertFromSnakeCase(converted) + if converted == original { + return "\(key) (\"\(original)\")" + } else if roundtrip == original { + return "\(key) (\"\(original)\"), converted to \(converted)" + } else { + return "\(key) (\"\(original)\"), with divergent representation \(roundtrip), converted to \(converted)" + } + default: + // Otherwise, just report the converted string + return "\(key) (\"\(key.stringValue)\")" + } + } + + public func decodeNil(forKey key: Key) throws -> Bool { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + return entry is NSNull + } + + public func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Bool.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Int.Type, forKey key: Key) throws -> Int { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Int.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Int8.Type, forKey key: Key) throws -> Int8 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Int8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Int16.Type, forKey key: Key) throws -> Int16 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Int16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Int32.Type, forKey key: Key) throws -> Int32 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Int32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Int64.Type, forKey key: Key) throws -> Int64 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Int64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: UInt.Type, forKey key: Key) throws -> UInt { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: UInt.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: UInt8.Type, forKey key: Key) throws -> UInt8 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: UInt8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: UInt16.Type, forKey key: Key) throws -> UInt16 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: UInt16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: UInt32.Type, forKey key: Key) throws -> UInt32 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: UInt32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: UInt64.Type, forKey key: Key) throws -> UInt64 { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: UInt64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Float.Type, forKey key: Key) throws -> Float { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Float.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: Double.Type, forKey key: Key) throws -> Double { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: Double.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: String.Type, forKey key: Key) throws -> String { + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: String.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func decode(_ type: T.Type, forKey key: Key) throws -> T { + if type is StructureCodingUncodedUnkeyed.Type { + // Note: not pushing and popping key to codingPath since the key is + // not part of the decoded structure. + return try T.init(from: self.decoder) + } + guard let entry = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "No value associated with key \(_errorDescription(of: key)).")) + } + + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = try self.decoder.unbox(entry, as: type) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath, debugDescription: "Expected \(type) value but found null instead.")) + } + + return value + } + + public func nestedContainer(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer { + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get \(KeyedDecodingContainer.self) -- no value found for key \(_errorDescription(of: key))")) + } + + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + } + + let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + return KeyedDecodingContainer(container) + } + + public func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer { + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + guard let value = self.container[key.stringValue] else { + throw DecodingError.keyNotFound(key, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(_errorDescription(of: key))")) + } + + guard let array = value as? [Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + } + + return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + } + + private func _superDecoder(forKey key: __owned CodingKey) throws -> Decoder { + self.decoder.codingPath.append(key) + defer { self.decoder.codingPath.removeLast() } + + let value: Any = self.container[key.stringValue] ?? NSNull() + return __JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + } + + public func superDecoder() throws -> Decoder { + return try _superDecoder(forKey: _JSONKey.super) + } + + public func superDecoder(forKey key: Key) throws -> Decoder { + return try _superDecoder(forKey: key) + } +} + +fileprivate struct _JSONUnkeyedDecodingContainer : UnkeyedDecodingContainer { + // MARK: Properties + + /// A reference to the decoder we're reading from. + private let decoder: __JSONDecoder + + /// A reference to the container we're reading from. + private let container: [Any] + + /// The path of coding keys taken to get to this point in decoding. + private(set) public var codingPath: [CodingKey] + + /// The index of the element we're about to decode. + private(set) public var currentIndex: Int + + // MARK: - Initialization + + /// Initializes `self` by referencing the given decoder and container. + fileprivate init(referencing decoder: __JSONDecoder, wrapping container: [Any]) { + self.decoder = decoder + self.container = container + self.codingPath = decoder.codingPath + self.currentIndex = 0 + } + + // MARK: - UnkeyedDecodingContainer Methods + + public var count: Int? { + return self.container.count + } + + public var isAtEnd: Bool { + return self.currentIndex >= self.count! + } + + public mutating func decodeNil() throws -> Bool { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(Any?.self, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + if self.container[self.currentIndex] is NSNull { + self.currentIndex += 1 + return true + } else { + return false + } + } + + public mutating func decode(_ type: Bool.Type) throws -> Bool { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Bool.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Int.Type) throws -> Int { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Int8.Type) throws -> Int8 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Int16.Type) throws -> Int16 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Int32.Type) throws -> Int32 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Int64.Type) throws -> Int64 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Int64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: UInt.Type) throws -> UInt { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: UInt8.Type) throws -> UInt8 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt8.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: UInt16.Type) throws -> UInt16 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt16.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: UInt32.Type) throws -> UInt32 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt32.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: UInt64.Type) throws -> UInt64 { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: UInt64.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Float.Type) throws -> Float { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Float.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: Double.Type) throws -> Double { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: Double.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: String.Type) throws -> String { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: String.self) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func decode(_ type: T.Type) throws -> T { + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Unkeyed container is at end.")) + } + + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard let decoded = try self.decoder.unbox(self.container[self.currentIndex], as: type) else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.decoder.codingPath + [_JSONKey(index: self.currentIndex)], debugDescription: "Expected \(type) but found null instead.")) + } + + self.currentIndex += 1 + return decoded + } + + public mutating func nestedContainer(keyedBy type: NestedKey.Type) throws -> KeyedDecodingContainer { + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + } + + let value = self.container[self.currentIndex] + guard !(value is NSNull) else { + throw DecodingError.valueNotFound(KeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + } + + guard let dictionary = value as? [String : Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [String : Any].self, reality: value) + } + + self.currentIndex += 1 + let container = _JSONKeyedDecodingContainer(referencing: self.decoder, wrapping: dictionary) + return KeyedDecodingContainer(container) + } + + public mutating func nestedUnkeyedContainer() throws -> UnkeyedDecodingContainer { + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get nested keyed container -- unkeyed container is at end.")) + } + + let value = self.container[self.currentIndex] + guard !(value is NSNull) else { + throw DecodingError.valueNotFound(UnkeyedDecodingContainer.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get keyed decoding container -- found null value instead.")) + } + + guard let array = value as? [Any] else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: [Any].self, reality: value) + } + + self.currentIndex += 1 + return _JSONUnkeyedDecodingContainer(referencing: self.decoder, wrapping: array) + } + + public mutating func superDecoder() throws -> Decoder { + self.decoder.codingPath.append(_JSONKey(index: self.currentIndex)) + defer { self.decoder.codingPath.removeLast() } + + guard !self.isAtEnd else { + throw DecodingError.valueNotFound(Decoder.self, + DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Cannot get superDecoder() -- unkeyed container is at end.")) + } + + let value = self.container[self.currentIndex] + self.currentIndex += 1 + return __JSONDecoder(referencing: value, at: self.decoder.codingPath, options: self.decoder.options) + } +} + +extension __JSONDecoder : SingleValueDecodingContainer { + // MARK: SingleValueDecodingContainer Methods + + private func expectNonNull(_ type: T.Type) throws { + guard !self.decodeNil() else { + throw DecodingError.valueNotFound(type, DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected \(type) but found null value instead.")) + } + } + + public func decodeNil() -> Bool { + return self.storage.topContainer is NSNull + } + + public func decode(_ type: Bool.Type) throws -> Bool { + try expectNonNull(Bool.self) + return try self.unbox(self.storage.topContainer, as: Bool.self)! + } + + public func decode(_ type: Int.Type) throws -> Int { + try expectNonNull(Int.self) + return try self.unbox(self.storage.topContainer, as: Int.self)! + } + + public func decode(_ type: Int8.Type) throws -> Int8 { + try expectNonNull(Int8.self) + return try self.unbox(self.storage.topContainer, as: Int8.self)! + } + + public func decode(_ type: Int16.Type) throws -> Int16 { + try expectNonNull(Int16.self) + return try self.unbox(self.storage.topContainer, as: Int16.self)! + } + + public func decode(_ type: Int32.Type) throws -> Int32 { + try expectNonNull(Int32.self) + return try self.unbox(self.storage.topContainer, as: Int32.self)! + } + + public func decode(_ type: Int64.Type) throws -> Int64 { + try expectNonNull(Int64.self) + return try self.unbox(self.storage.topContainer, as: Int64.self)! + } + + public func decode(_ type: UInt.Type) throws -> UInt { + try expectNonNull(UInt.self) + return try self.unbox(self.storage.topContainer, as: UInt.self)! + } + + public func decode(_ type: UInt8.Type) throws -> UInt8 { + try expectNonNull(UInt8.self) + return try self.unbox(self.storage.topContainer, as: UInt8.self)! + } + + public func decode(_ type: UInt16.Type) throws -> UInt16 { + try expectNonNull(UInt16.self) + return try self.unbox(self.storage.topContainer, as: UInt16.self)! + } + + public func decode(_ type: UInt32.Type) throws -> UInt32 { + try expectNonNull(UInt32.self) + return try self.unbox(self.storage.topContainer, as: UInt32.self)! + } + + public func decode(_ type: UInt64.Type) throws -> UInt64 { + try expectNonNull(UInt64.self) + return try self.unbox(self.storage.topContainer, as: UInt64.self)! + } + + public func decode(_ type: Float.Type) throws -> Float { + try expectNonNull(Float.self) + return try self.unbox(self.storage.topContainer, as: Float.self)! + } + + public func decode(_ type: Double.Type) throws -> Double { + try expectNonNull(Double.self) + return try self.unbox(self.storage.topContainer, as: Double.self)! + } + + public func decode(_ type: String.Type) throws -> String { + try expectNonNull(String.self) + return try self.unbox(self.storage.topContainer, as: String.self)! + } + + public func decode(_ type: T.Type) throws -> T { + try expectNonNull(type) + return try self.unbox(self.storage.topContainer, as: type)! + } +} + +// MARK: - Concrete Value Representations + +extension __JSONDecoder { + /// Returns the given value unboxed from a container. + fileprivate func unbox(_ value: Any, as type: Bool.Type) throws -> Bool? { + guard !(value is NSNull) else { return nil } + + if let rcValue = value as? FirebaseRemoteConfigValueDecoding { + return rcValue.boolValue() + } + if let number = value as? NSNumber { + // TODO: Add a flag to coerce non-boolean numbers into Bools? + if number === kCFBooleanTrue as NSNumber { + return true + } else if number === kCFBooleanFalse as NSNumber { + return false + } + + /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: + } else if let bool = value as? Bool { + return bool + */ + + } + + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + + fileprivate func rcValNumberAdaptor(_ value: Any) -> Any { + if let rcValue = value as? FirebaseRemoteConfigValueDecoding { + return rcValue.numberValue() + } + return value + } + + fileprivate func getNumber(_ value: Any, as type: Any.Type) throws -> NSNumber { + let val = rcValNumberAdaptor(value) + guard let number = val as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: val) + } + return number + } + + fileprivate func unbox(_ value: Any, as type: Int.Type) throws -> Int? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let int = number.intValue + guard NSNumber(value: int) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return int + } + + fileprivate func unbox(_ value: Any, as type: Int8.Type) throws -> Int8? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let int8 = number.int8Value + guard NSNumber(value: int8) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return int8 + } + + fileprivate func unbox(_ value: Any, as type: Int16.Type) throws -> Int16? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let int16 = number.int16Value + guard NSNumber(value: int16) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return int16 + } + + fileprivate func unbox(_ value: Any, as type: Int32.Type) throws -> Int32? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let int32 = number.int32Value + guard NSNumber(value: int32) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return int32 + } + + fileprivate func unbox(_ value: Any, as type: Int64.Type) throws -> Int64? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let int64 = number.int64Value + guard NSNumber(value: int64) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return int64 + } + + fileprivate func unbox(_ value: Any, as type: UInt.Type) throws -> UInt? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let uint = number.uintValue + guard NSNumber(value: uint) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return uint + } + + fileprivate func unbox(_ value: Any, as type: UInt8.Type) throws -> UInt8? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let uint8 = number.uint8Value + guard NSNumber(value: uint8) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return uint8 + } + + fileprivate func unbox(_ value: Any, as type: UInt16.Type) throws -> UInt16? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let uint16 = number.uint16Value + guard NSNumber(value: uint16) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return uint16 + } + + fileprivate func unbox(_ value: Any, as type: UInt32.Type) throws -> UInt32? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let uint32 = number.uint32Value + guard NSNumber(value: uint32) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return uint32 + } + + fileprivate func unbox(_ value: Any, as type: UInt64.Type) throws -> UInt64? { + guard !(value is NSNull) else { return nil } + + let number = try getNumber(value, as: type) + let uint64 = number.uint64Value + guard NSNumber(value: uint64) == number else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number <\(number)> does not fit in \(type).")) + } + + return uint64 + } + + fileprivate func unbox(_ value: Any, as type: Float.Type) throws -> Float? { + guard !(value is NSNull) else { return nil } + + let val = rcValNumberAdaptor(value) + if let number = val as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { + // We are willing to return a Float by losing precision: + // * If the original value was integral, + // * and the integral value was > Float.greatestFiniteMagnitude, we will fail + // * and the integral value was <= Float.greatestFiniteMagnitude, we are willing to lose precision past 2^24 + // * If it was a Float, you will get back the precise value + // * If it was a Double or Decimal, you will get back the nearest approximation if it will fit + let double = number.doubleValue + guard abs(double) <= Double(Float.greatestFiniteMagnitude) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Parsed JSON number \(number) does not fit in \(type).")) + } + + return Float(double) + + /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: + } else if let double = value as? Double { + if abs(double) <= Double(Float.max) { + return Float(double) + } + + overflow = true + } else if let int = value as? Int { + if let float = Float(exactly: int) { + return float + } + + overflow = true + */ + + } else if let string = val as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + if string == posInfString { + return Float.infinity + } else if string == negInfString { + return -Float.infinity + } else if string == nanString { + return Float.nan + } + } + + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + + fileprivate func unbox(_ value: Any, as type: Double.Type) throws -> Double? { + guard !(value is NSNull) else { return nil } + + let val = rcValNumberAdaptor(value) + if let number = val as? NSNumber, number !== kCFBooleanTrue, number !== kCFBooleanFalse { + // We are always willing to return the number as a Double: + // * If the original value was integral, it is guaranteed to fit in a Double; we are willing to lose precision past 2^53 if you encoded a UInt64 but requested a Double + // * If it was a Float or Double, you will get back the precise value + // * If it was Decimal, you will get back the nearest approximation + return number.doubleValue + + /* FIXME: If swift-corelibs-foundation doesn't change to use NSNumber, this code path will need to be included and tested: + } else if let double = value as? Double { + return double + } else if let int = value as? Int { + if let double = Double(exactly: int) { + return double + } + + overflow = true + */ + + } else if let string = val as? String, + case .convertFromString(let posInfString, let negInfString, let nanString) = self.options.nonConformingFloatDecodingStrategy { + if string == posInfString { + return Double.infinity + } else if string == negInfString { + return -Double.infinity + } else if string == nanString { + return Double.nan + } + } + + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + + fileprivate func unbox(_ value: Any, as type: String.Type) throws -> String? { + guard !(value is NSNull) else { return nil } + + if let rcValue = value as? FirebaseRemoteConfigValueDecoding { + return rcValue.stringValue() + } + guard let string = value as? String else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + + return string + } + + fileprivate func unbox(_ value: Any, as type: Date.Type) throws -> Date? { + guard !(value is NSNull) else { return nil } + + switch self.options.dateDecodingStrategy { + case .deferredToDate: + self.storage.push(container: value) + defer { self.storage.popContainer() } + return try Date(from: self) + + case .secondsSince1970: + let double = try self.unbox(value, as: Double.self)! + return Date(timeIntervalSince1970: double) + + case .millisecondsSince1970: + let double = try self.unbox(value, as: Double.self)! + return Date(timeIntervalSince1970: double / 1000.0) + + case .iso8601: + let string = try self.unbox(value, as: String.self)! + guard let date = _iso8601Formatter.date(from: string) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Expected date string to be ISO8601-formatted.")) + } + + return date + + case .formatted(let formatter): + let string = try self.unbox(value, as: String.self)! + guard let date = formatter.date(from: string) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Date string does not match format expected by formatter.")) + } + + return date + + case .custom(let closure): + self.storage.push(container: value) + defer { self.storage.popContainer() } + return try closure(self) + } + } + + fileprivate func unbox(_ value: Any, as type: Data.Type) throws -> Data? { + guard !(value is NSNull) else { return nil } + + if let rcValue = value as? FirebaseRemoteConfigValueDecoding { + return rcValue.dataValue() + } + + switch self.options.dataDecodingStrategy { + case .deferredToData: + self.storage.push(container: value) + defer { self.storage.popContainer() } + return try Data(from: self) + + case .base64: + guard let string = value as? String else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + + guard let data = Data(base64Encoded: string) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, debugDescription: "Encountered Data is not valid Base64.")) + } + + return data + + case .blob: + if let data = value as? Data { + return data + } else if let string = value as? String, let data = Data(base64Encoded: string) { + // Support implicit migration of data that was written with .base64 (String type) using + // Firestore 10.0 through 10.3. + return data + } + + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + + case .custom(let closure): + self.storage.push(container: value) + defer { self.storage.popContainer() } + return try closure(self) + } + } + + fileprivate func unbox(_ value: Any, as type: Decimal.Type) throws -> Decimal? { + guard !(value is NSNull) else { return nil } + + let val = rcValNumberAdaptor(value) + + // Attempt to bridge from NSDecimalNumber. + if let decimal = val as? Decimal { + return decimal + } else { + let doubleValue = try self.unbox(val, as: Double.self)! + return Decimal(doubleValue) + } + } + + fileprivate func unbox(_ value: Any, as type: _JSONStringDictionaryDecodableMarker.Type) throws -> T? { + guard !(value is NSNull) else { return nil } + + if let rcValue = value as? FirebaseRemoteConfigValueDecoding { + guard let dictionaryValue = rcValue.dictionaryValue() else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: rcValue) + } + return dictionaryValue as? T + } + + var result = [String : Any]() + guard let dict = value as? NSDictionary else { + throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value) + } + let elementType = type.elementType + for (key, value) in dict { + let key = key as! String + self.codingPath.append(_JSONKey(stringValue: key, intValue: nil)) + defer { self.codingPath.removeLast() } + + result[key] = try unbox_(value, as: elementType) + } + + return result as? T + } + + fileprivate func unbox(_ value: Any, as type: T.Type) throws -> T? { + return try unbox_(value, as: type) as? T + } + + fileprivate func unbox_(_ value: Any, as _type: Decodable.Type) throws -> Any? { + if _type == Date.self || _type == NSDate.self { + return try self.unbox(value, as: Date.self) + } else if _type == Data.self || _type == NSData.self { + return try self.unbox(value, as: Data.self) + } else if _type == URL.self || _type == NSURL.self { + guard let urlString = try self.unbox(value, as: String.self) else { + return nil + } + + guard let url = URL(string: urlString) else { + throw DecodingError.dataCorrupted(DecodingError.Context(codingPath: self.codingPath, + debugDescription: "Invalid URL string.")) + } + return url + } else if _type == Decimal.self || _type == NSDecimalNumber.self { + return try self.unbox(value, as: Decimal.self) + } else if let stringKeyedDictType = _type as? _JSONStringDictionaryDecodableMarker.Type { + return try self.unbox(value, as: stringKeyedDictType) + } else { + self.storage.push(container: value) + defer { self.storage.popContainer() } + if self.options.passthroughTypeResolver.isPassthroughType(value) && type(of: value) == _type { + return value + } + return try _type.init(from: self) + } + } +} + +//===----------------------------------------------------------------------===// +// Shared Key Types +//===----------------------------------------------------------------------===// + +fileprivate struct _JSONKey : CodingKey { + public var stringValue: String + public var intValue: Int? + + public init?(stringValue: String) { + self.stringValue = stringValue + self.intValue = nil + } + + public init?(intValue: Int) { + self.stringValue = "\(intValue)" + self.intValue = intValue + } + + public init(stringValue: String, intValue: Int?) { + self.stringValue = stringValue + self.intValue = intValue + } + + fileprivate init(index: Int) { + self.stringValue = "Index \(index)" + self.intValue = index + } + + fileprivate static let `super` = _JSONKey(stringValue: "super")! +} + +//===----------------------------------------------------------------------===// +// Shared ISO8601 Date Formatter +//===----------------------------------------------------------------------===// + +// NOTE: This value is implicitly lazy and _must_ be lazy. We're compiled against the latest SDK (w/ ISO8601DateFormatter), but linked against whichever Foundation the user has. ISO8601DateFormatter might not exist, so we better not hit this code path on an older OS. +fileprivate var _iso8601Formatter: ISO8601DateFormatter = { + let formatter = ISO8601DateFormatter() + formatter.formatOptions = .withInternetDateTime + return formatter +}() + +//===----------------------------------------------------------------------===// +// Error Utilities +//===----------------------------------------------------------------------===// + +extension EncodingError { + /// Returns a `.invalidValue` error describing the given invalid floating-point value. + /// + /// + /// - parameter value: The value that was invalid to encode. + /// - parameter path: The path of `CodingKey`s taken to encode this value. + /// - returns: An `EncodingError` with the appropriate path and debug description. + fileprivate static func _invalidFloatingPointValue(_ value: T, at codingPath: [CodingKey]) -> EncodingError { + let valueDescription: String + if value == T.infinity { + valueDescription = "\(T.self).infinity" + } else if value == -T.infinity { + valueDescription = "-\(T.self).infinity" + } else { + valueDescription = "\(T.self).nan" + } + + let debugDescription = "Unable to encode \(valueDescription) directly in JSON. Use JSONEncoder.NonConformingFloatEncodingStrategy.convertToString to specify how the value should be encoded." + return .invalidValue(value, EncodingError.Context(codingPath: codingPath, debugDescription: debugDescription)) + } +} diff --git a/Pods/FirebaseSharedSwift/README.md b/Pods/FirebaseSharedSwift/README.md new file mode 100644 index 0000000..665e16c --- /dev/null +++ b/Pods/FirebaseSharedSwift/README.md @@ -0,0 +1,302 @@ +

+ + + + + + + + +
+ + + + + + +

+ +# Firebase Apple Open Source Development + +This repository contains the source code for all Apple platform Firebase SDKs except FirebaseAnalytics. + +Firebase is an app development platform with tools to help you build, grow, and +monetize your app. More information about Firebase can be found on the +[official Firebase website](https://firebase.google.com). + +## Installation + +See the subsections below for details about the different installation methods. Where +available, it's recommended to install any libraries with a `Swift` suffix to get the +best experience when writing your app in Swift. + +1. [Standard pod install](#standard-pod-install) +2. [Swift Package Manager](#swift-package-manager) +3. [Installing from the GitHub repo](#installing-from-github) +4. [Experimental Carthage](#carthage-ios-only) + +### Standard pod install + +For instructions on the standard pod install, visit: +[https://firebase.google.com/docs/ios/setup](https://firebase.google.com/docs/ios/setup). + +### Swift Package Manager + +Instructions for [Swift Package Manager](https://swift.org/package-manager/) support can be +found in the [SwiftPackageManager.md](SwiftPackageManager.md) Markdown file. + +### Installing from GitHub + +These instructions can be used to access the Firebase repo at other branches, +tags, or commits. + +#### Background + +See [the Podfile Syntax Reference](https://guides.cocoapods.org/syntax/podfile.html#pod) +for instructions and options about overriding pod source locations. + +#### Accessing Firebase Source Snapshots + +All official releases are tagged in this repo and available via CocoaPods. To access a local +source snapshot or unreleased branch, use Podfile directives like the following: + +To access FirebaseFirestore via a branch: +```ruby +pod 'FirebaseCore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +pod 'FirebaseFirestore', :git => 'https://github.com/firebase/firebase-ios-sdk.git', :branch => 'main' +``` + +To access FirebaseMessaging via a checked-out version of the firebase-ios-sdk repo: +```ruby +pod 'FirebaseCore', :path => '/path/to/firebase-ios-sdk' +pod 'FirebaseMessaging', :path => '/path/to/firebase-ios-sdk' +``` + +### Carthage (iOS only) + +Instructions for the experimental Carthage distribution can be found at +[Carthage.md](Carthage.md). + +### Using Firebase from a Framework or a library + +For details on using Firebase from a Framework or a library, refer to [firebase_in_libraries.md](docs/firebase_in_libraries.md). + +## Development + +To develop Firebase software in this repository, ensure that you have at least +the following software: + +* Xcode 15.2 (or later) + +CocoaPods is still the canonical way to develop, but much of the repo now supports +development with Swift Package Manager. + +### CocoaPods + +Install the following: +* CocoaPods 1.12.0 (or later) +* [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +```ruby +pod gen Firebase{name here}.podspec --local-sources=./ --auto-open --platforms=ios +``` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +Firestore has a self-contained Xcode project. See +[Firestore/README](Firestore/README.md) Markdown file. + +#### Development for Catalyst +* `pod gen {name here}.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively, disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Swift Package Manager +* To enable test schemes: `./scripts/setup_spm_tests.sh` +* `open Package.swift` or double click `Package.swift` in Finder. +* Xcode will open the project + * Choose a scheme for a library to build or test suite to run + * Choose a target platform by selecting the run destination along with the scheme + +### Adding a New Firebase Pod + +Refer to [AddNewPod](AddNewPod.md) Markdown file for details. + +### Managing Headers and Imports + +For information about managing headers and imports, see [HeadersImports](HeadersImports.md) Markdown file. + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a pull request (PR). + +GitHub Actions will verify that any code changes are done in a style-compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +### Running Sample Apps +To run the sample apps and integration tests, you'll need a valid +`GoogleService-Info.plist +` file. The Firebase Xcode project contains dummy plist +files without real values, but they can be replaced with real plist files. To get your own +`GoogleService-Info.plist` files: + +1. Go to the [Firebase Console](https://console.firebase.google.com/) +2. Create a new Firebase project, if you don't already have one +3. For each sample app you want to test, create a new Firebase app with the sample app's bundle +identifier (e.g., `com.google.Database-Example`) +4. Download the resulting `GoogleService-Info.plist` and add it to the Xcode project. + +### Coverage Report Generation + +For coverage report generation instructions, see [scripts/code_coverage_report/README](scripts/code_coverage_report/README.md) Markdown file. + +## Specific Component Instructions +See the sections below for any special instructions for those components. + +### Firebase Auth + +For specific Firebase Auth development, refer to the [Auth Sample README](FirebaseAuth/Tests/Sample/README.md) for instructions about +building and running the FirebaseAuth pod along with various samples and tests. + +### Firebase Database + +The Firebase Database Integration tests can be run against a locally running Database Emulator +or against a production instance. + +To run against a local emulator instance, invoke `./scripts/run_database_emulator.sh start` before +running the integration test. + +To run against a production instance, provide a valid `GoogleServices-Info.plist` and copy it to +`FirebaseDatabase/Tests/Resources/GoogleService-Info.plist`. Your Security Rule must be set to +[public](https://firebase.google.com/docs/database/security/quickstart) while your tests are +running. + +### Firebase Dynamic Links + +Firebase Dynamic Links is **deprecated** and should not be used in new projects. The service will shut down on August 25, 2025. + +Please see our [Dynamic Links Deprecation FAQ documentation](https://firebase.google.com/support/dynamic-links-faq) for more guidance. + +### Firebase Performance Monitoring + +For specific Firebase Performance Monitoring development, see +[the Performance README](FirebasePerformance/README.md) for instructions about building the SDK +and [the Performance TestApp README](FirebasePerformance/Tests/TestApp/README.md) for instructions about +integrating Performance with the dev test App. + +### Firebase Storage + +To run the Storage Integration tests, follow the instructions in +[StorageIntegration.swift](FirebaseStorage/Tests/Integration/StorageIntegration.swift). + +#### Push Notifications + +Push notifications can only be delivered to specially provisioned App IDs in the developer portal. +In order to test receiving push notifications, you will need to: + +1. Change the bundle identifier of the sample app to something you own in your Apple Developer +account and enable that App ID for push notifications. +2. You'll also need to +[upload your APNs Provider Authentication Key or certificate to the +Firebase Console](https://firebase.google.com/docs/cloud-messaging/ios/certs) +at **Project Settings > Cloud Messaging > [Your Firebase App]**. +3. Ensure your iOS device is added to your Apple Developer portal as a test device. + +#### iOS Simulator + +The iOS Simulator cannot register for remote notifications and will not receive push notifications. +To receive push notifications, follow the steps above and run the app on a physical device. + +### Vertex AI for Firebase + +See the [Vertex AI for Firebase README](FirebaseVertexAI#development) for +instructions about building and testing the SDK. + +## Building with Firebase on Apple platforms + +Firebase provides official beta support for macOS, Catalyst, and tvOS. visionOS and watchOS +are community supported. Thanks to community contributions for many of the multi-platform PRs. + +At this time, most of Firebase's products are available across Apple platforms. There are still +a few gaps, especially on visionOS and watchOS. For details about the current support matrix, see +[this chart](https://firebase.google.com/docs/ios/learn-more#firebase_library_support_by_platform) +in Firebase's documentation. + +### visionOS + +Where supported, visionOS works as expected with the exception of Firestore via Swift Package +Manager where it is required to use the source distribution. + +To enable the Firestore source distribution, quit Xcode and open the desired +project from the command line with the `FIREBASE_SOURCE_FIRESTORE` environment +variable: `open --env FIREBASE_SOURCE_FIRESTORE /path/to/project.xcodeproj`. +To go back to using the binary distribution of Firestore, quit Xcode and open +Xcode like normal, without the environment variable. + +### watchOS +Thanks to contributions from the community, many of Firebase SDKs now compile, run unit tests, and +work on watchOS. See the [Independent Watch App Sample](Example/watchOSSample). + +Keep in mind that watchOS is not officially supported by Firebase. While we can catch basic unit +test issues with GitHub Actions, there may be some changes where the SDK no longer works as expected +on watchOS. If you encounter this, please +[file an issue](https://github.com/firebase/firebase-ios-sdk/issues). + +During app setup in the console, you may get to a step that mentions something like "Checking if the +app has communicated with our servers". This relies on Analytics and will not work on watchOS. +**It's safe to ignore the message and continue**, the rest of the SDKs will work as expected. + +#### Additional Crashlytics Notes +* watchOS has limited support. Due to watchOS restrictions, mach exceptions and signal crashes are +not recorded. (Crashes in SwiftUI are generated as mach exceptions, so will not be recorded) + +## Combine +Thanks to contributions from the community, _FirebaseCombineSwift_ contains support for Apple's Combine +framework. This module is currently under development and not yet supported for use in production +environments. For more details, please refer to the [docs](FirebaseCombineSwift/README.md). + +## Roadmap + +See [Roadmap](ROADMAP.md) for more about the Firebase Apple SDK Open Source +plans and directions. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +Apple SDK. + +## License + +The contents of this repository are licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +Your use of Firebase is governed by the +[Terms of Service for Firebase Services](https://firebase.google.com/terms/). diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist new file mode 100644 index 0000000..9d935d1 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/Info.plist @@ -0,0 +1,107 @@ + + + + + AvailableLibraries + + + BinaryPath + GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + BinaryPath + GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + BinaryPath + GoogleAppMeasurement.framework/GoogleAppMeasurement + LibraryIdentifier + ios-arm64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + BinaryPath + GoogleAppMeasurement.framework/GoogleAppMeasurement + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + BinaryPath + GoogleAppMeasurement.framework/GoogleAppMeasurement + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + BinaryPath + GoogleAppMeasurement.framework/GoogleAppMeasurement + LibraryIdentifier + tvos-arm64 + LibraryPath + GoogleAppMeasurement.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeDirectory b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeDirectory new file mode 100644 index 0000000..426d6c8 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeDirectory differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements new file mode 100644 index 0000000..001f5af Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements-1 b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements-1 new file mode 100644 index 0000000..c05b28e Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeRequirements-1 differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeResources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeResources new file mode 100644 index 0000000..220e03b --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeResources @@ -0,0 +1,408 @@ + + + + + files + + ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement + + RhwOnDgavPI0zzRA0WB6EWR67xE= + + ios-arm64/GoogleAppMeasurement.framework/Info.plist + + TohHMyxskUGDOjkXbJi0itb5D9U= + + ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + + wdhEOCyyKr4lZWM3dxKCl8QfRA4= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist + + z1EuM9KThmsjsoFiyOvRpDiVtqE= + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement + + c2UR8YXU8HyZa+0RkRxLqmrdzJw= + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist + + /M81j4oqJeDqrhP9iEqnTal1ihM= + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + + 4i2iwJQn8lCCe4+SXuHYN5bW1fs= + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist + + EIdUhDAwIJU2sWgyuI0ahJQMp6U= + + tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement + + QWUAHXGhl0l1xRtTRylpXYpa34Q= + + tvos-arm64/GoogleAppMeasurement.framework/Info.plist + + joXl/6bsmOnp1E9e9aW+BX/rhMY= + + tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement + + KrQJsA2fmpy5usLPXaZD8W8gsvU= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist + + M8duF9DAJJ//vbRxTm/6UMQcZyo= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + + files2 + + ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement + + hash + + RhwOnDgavPI0zzRA0WB6EWR67xE= + + hash2 + + zYeOjtixNWS5bpe7xjl/ytCdbt+/ZYidvHsnqaGTkMs= + + + ios-arm64/GoogleAppMeasurement.framework/Info.plist + + hash + + TohHMyxskUGDOjkXbJi0itb5D9U= + + hash2 + + REaKna8zIK92XFv2PJlt+jA2tK44gO9c8n/udDmpZ0Q= + + + ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement + + symlink + Versions/Current/GoogleAppMeasurement + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules + + symlink + Versions/Current/Modules + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Resources + + symlink + Versions/Current/Resources + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + + hash + + wdhEOCyyKr4lZWM3dxKCl8QfRA4= + + hash2 + + wC1JQnsxDHo+Kzu4wkghxKqzKRnhrHrAFNGPRjeDF8E= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist + + hash + + z1EuM9KThmsjsoFiyOvRpDiVtqE= + + hash2 + + 0h3aZwqICpfwliOo8JosbEUX48v4TfEgLpdTaaZPAXk= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/Current + + symlink + A + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement + + hash + + c2UR8YXU8HyZa+0RkRxLqmrdzJw= + + hash2 + + ty8sBd/t7Qi6xWfk3vbFmo+EosuPqE+0q77XONgbdWs= + + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist + + hash + + /M81j4oqJeDqrhP9iEqnTal1ihM= + + hash2 + + unKbLbtCTs9txHR0V1s1plgcGXLCCtWn88KI4DV/DKs= + + + ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement + + symlink + Versions/Current/GoogleAppMeasurement + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules + + symlink + Versions/Current/Modules + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Resources + + symlink + Versions/Current/Resources + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement + + hash + + 4i2iwJQn8lCCe4+SXuHYN5bW1fs= + + hash2 + + L/dl84bL/cLlnxW//k3SFtypAdc/OwYuiRWKLP4GX/0= + + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist + + hash + + EIdUhDAwIJU2sWgyuI0ahJQMp6U= + + hash2 + + vzMy1QnhlwBa6EHftCo6LSR8kHdARzWQneh6KZ975Mc= + + + macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/Current + + symlink + A + + tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement + + hash + + QWUAHXGhl0l1xRtTRylpXYpa34Q= + + hash2 + + sChbVVaQfLlS3eOUUi6oouL2/ezcnETulzHiRd2bjM4= + + + tvos-arm64/GoogleAppMeasurement.framework/Info.plist + + hash + + joXl/6bsmOnp1E9e9aW+BX/rhMY= + + hash2 + + 98drm5iKDtABG2vmZs1x1ILVi0pUDTTqEMXti1Pmnec= + + + tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement + + hash + + KrQJsA2fmpy5usLPXaZD8W8gsvU= + + hash2 + + kV1x9fGtJdV9/k/53dwA7jqL35trIXl38N5fsRyZfcY= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist + + hash + + M8duF9DAJJ//vbRxTm/6UMQcZyo= + + hash2 + + piSEYn0SIJcbjzha9NYnSpPCYjmuIG43gXfGpP/FOu0= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap + + hash + + on1mkulwTtm+ufPJ4eClavLWAuQ= + + hash2 + + gd8e5hMrJihnXu8TQ0xecVPl3Z71GpsKaYxiLbmHezw= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeSignature b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeSignature new file mode 100644 index 0000000..3cff680 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/_CodeSignature/CodeSignature differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..ffb7b8e Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..d2333ae --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,57 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphoneos + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphoneos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 120000 index 0000000..5a946b2 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/GoogleAppMeasurement @@ -0,0 +1 @@ +Versions/Current/GoogleAppMeasurement \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Resources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement new file mode 100644 index 0000000..1f731c7 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..456c316 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,54 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + UIDeviceFamily + + 2 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/Current b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurement.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..531d36e Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..2fc78fa --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,53 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphonesimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphonesimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 120000 index 0000000..5a946b2 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/GoogleAppMeasurement @@ -0,0 +1 @@ +Versions/Current/GoogleAppMeasurement \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Resources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement new file mode 100644 index 0000000..9989bb2 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..4adc113 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,50 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/Current b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/macos-arm64_x86_64/GoogleAppMeasurement.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..0c6c9cc Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..ae67516 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvos + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement new file mode 100644 index 0000000..56ebd4c Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/GoogleAppMeasurement differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist new file mode 100644 index 0000000..d3cefae --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurement + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurement + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurement + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvsimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvsimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap new file mode 100644 index 0000000..d3499f0 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurement.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module GoogleAppMeasurement { +umbrella header "GoogleAppMeasurement-umbrella.h" +export * +module * { export * } + link framework "Security" + link framework "SystemConfiguration" + link "c++" + link "sqlite3" + link "z" +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist new file mode 100644 index 0000000..4a9e39d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/Info.plist @@ -0,0 +1,107 @@ + + + + + AvailableLibraries + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + ios-arm64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + ios + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + macos-arm64_x86_64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + macos + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + tvos-arm64 + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + + SupportedPlatform + tvos + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + tvos-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + tvos + SupportedPlatformVariant + simulator + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + ios-arm64_x86_64-simulator + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + simulator + + + BinaryPath + GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + LibraryIdentifier + ios-arm64_x86_64-maccatalyst + LibraryPath + GoogleAppMeasurementIdentitySupport.framework + SupportedArchitectures + + arm64 + x86_64 + + SupportedPlatform + ios + SupportedPlatformVariant + maccatalyst + + + CFBundlePackageType + XFWK + XCFrameworkFormatVersion + 1.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeDirectory b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeDirectory new file mode 100644 index 0000000..8bd9896 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeDirectory differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements new file mode 100644 index 0000000..b2a6e3a Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements-1 b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements-1 new file mode 100644 index 0000000..78409ac Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeRequirements-1 differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeResources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeResources new file mode 100644 index 0000000..a053f39 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeResources @@ -0,0 +1,408 @@ + + + + + files + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + KXJZtjKaR8+YFsmFIJgmCBAi61k= + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + fj1aEQuyhDwGv/WF74p6q70sxCc= + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + + qjEEWBYUsYmWP/dGYGqk6H0XtCc= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist + + 4w7ZZN02ldypYlogPRfzjvZ6sGQ= + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + Y0csxyURm/Vw+EjN6Vs8F4OYyD0= + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + mfY6DQXP3dOX3W3PiF5qyUrK9kI= + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + + SGutHPksaT+14CgfJDiEGr9l0IA= + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist + + m7cWZduxfnTYJxTlDBim5LALViA= + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + faJon13KEa7exKXSm0k3ONIu1BM= + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + JkqjOPcsblSN7qvAOxG3mUNy/Jo= + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + RoKwMHmW5ksPuLfswh3w2eHBEU4= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + 2Ar+emR67oINTNDmtL2omd9eW3k= + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + + files2 + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + hash + + KXJZtjKaR8+YFsmFIJgmCBAi61k= + + hash2 + + SSBwUA5LG1rznKuV90TjTTBKvsrPOTlLIXroVyKCCso= + + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + hash + + fj1aEQuyhDwGv/WF74p6q70sxCc= + + hash2 + + rBrrvNSz1OmBNSUUv5FrQ53st98UvJ48c0CloB3/ysw= + + + ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + symlink + Versions/Current/GoogleAppMeasurementIdentitySupport + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules + + symlink + Versions/Current/Modules + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Resources + + symlink + Versions/Current/Resources + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + + hash + + qjEEWBYUsYmWP/dGYGqk6H0XtCc= + + hash2 + + y0WmxTyqtT5MXs2kylo+inVKWcvbAZgu72qvvDs8gDU= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist + + hash + + 4w7ZZN02ldypYlogPRfzjvZ6sGQ= + + hash2 + + zNUL4kfQTZZOp8qXFVovcngjxbKFxCEzxjSZmX/V8fI= + + + ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/Current + + symlink + A + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + hash + + Y0csxyURm/Vw+EjN6Vs8F4OYyD0= + + hash2 + + v0KVW0rp5DREsHYrxC2KN52zrBir04ScktCmxbBeJ9Y= + + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + hash + + mfY6DQXP3dOX3W3PiF5qyUrK9kI= + + hash2 + + UgOwFuG38NwHVEWRPMYb5v4149os/ah0ybL09I4JnLY= + + + ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + symlink + Versions/Current/GoogleAppMeasurementIdentitySupport + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules + + symlink + Versions/Current/Modules + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Resources + + symlink + Versions/Current/Resources + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport + + hash + + SGutHPksaT+14CgfJDiEGr9l0IA= + + hash2 + + 3/KTDnax/a4lkIpOY51sPDPXrgIjkWqjC8Mo99OjoOI= + + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist + + hash + + m7cWZduxfnTYJxTlDBim5LALViA= + + hash2 + + i3AZrQxVi9A15l6bnbzv4VD+VvtvWV9zWdZEB8q2Wu0= + + + macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/Current + + symlink + A + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + hash + + faJon13KEa7exKXSm0k3ONIu1BM= + + hash2 + + pZRyALHO66+MYJ/QmPT1mnN13JC1vKURRe/N0KZ/yNs= + + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + hash + + JkqjOPcsblSN7qvAOxG3mUNy/Jo= + + hash2 + + 4CMorB6K34sO9IiRwqFj+tHPoHadGMwt7Vc4owEjQ5Q= + + + tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport + + hash + + RoKwMHmW5ksPuLfswh3w2eHBEU4= + + hash2 + + jPxlTfTZN9FNClyN7c/JaqNjogJLtzvqoVLKw60g11o= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist + + hash + + 2Ar+emR67oINTNDmtL2omd9eW3k= + + hash2 + + QYupJjtFdSYajwRad4l5fUYuR7u0oNPaWZNGEtdY5gY= + + + tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap + + hash + + ZCuUZzVZ47W3gsydCwK/7TEMjVw= + + hash2 + + UGhX/JwInh1Ja0+DYSnYvdaBKLCWcOy/3nH/ZRnTP7I= + + + + rules + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^.* + + ^.*\.lproj/ + + optional + + weight + 1000 + + ^.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Base\.lproj/ + + weight + 1010 + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeSignature b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeSignature new file mode 100644 index 0000000..9b1eeaf Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/_CodeSignature/CodeSignature differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..cce82b7 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..20e50df --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,57 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphoneos + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphoneos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + UIRequiredDeviceCapabilities + + arm64 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 120000 index 0000000..f029390 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport @@ -0,0 +1 @@ +Versions/Current/GoogleAppMeasurementIdentitySupport \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Resources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..1282189 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..77d69e3 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,54 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + UIDeviceFamily + + 2 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/Current b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst/GoogleAppMeasurementIdentitySupport.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..0403f34 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..209e261 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,53 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + iPhoneSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21C52 + DTPlatformName + iphonesimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21C52 + DTSDKName + iphonesimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 1 + 2 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 120000 index 0000000..f029390 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport @@ -0,0 +1 @@ +Versions/Current/GoogleAppMeasurementIdentitySupport \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Resources b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..7439350 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..d93cf57 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,50 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 14.2 + DTSDKBuild + 23C53 + DTSDKName + macosx14.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + LSMinimumSystemVersion + 10.15 + MinimumOSVersion + 100.0 + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/Current b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64/GoogleAppMeasurementIdentitySupport.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..0c548e2 Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..fdf7d09 --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVOS + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvos + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvos17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport new file mode 100644 index 0000000..1abddca Binary files /dev/null and b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/GoogleAppMeasurementIdentitySupport differ diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist new file mode 100644 index 0000000..6954c6a --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Info.plist @@ -0,0 +1,52 @@ + + + + + BuildMachineOSBuild + 23G93 + CFBundleDevelopmentRegion + en + CFBundleExecutable + GoogleAppMeasurementIdentitySupport + CFBundleIdentifier + org.cocoapods.GoogleAppMeasurementIdentitySupport + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + GoogleAppMeasurementIdentitySupport + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + AppleTVSimulator + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 21K354 + DTPlatformName + appletvsimulator + DTPlatformVersion + 17.2 + DTSDKBuild + 21K354 + DTSDKName + appletvsimulator17.2 + DTXcode + 1520 + DTXcodeBuild + 15C500b + MinimumOSVersion + 100.0 + UIDeviceFamily + + 3 + + + diff --git a/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap new file mode 100644 index 0000000..4a42c5d --- /dev/null +++ b/Pods/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator/GoogleAppMeasurementIdentitySupport.framework/Modules/module.modulemap @@ -0,0 +1,5 @@ +framework module GoogleAppMeasurementIdentitySupport { +umbrella header "GoogleAppMeasurementIdentitySupport-umbrella.h" +export * +module * { export * } +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m new file mode 100644 index 0000000..11d849e --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTCompressionHelper.m @@ -0,0 +1,95 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" + +#import + +@implementation GDTCCTCompressionHelper + ++ (nullable NSData *)gzippedData:(NSData *)data { +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (data.length > UINT_MAX) { + return nil; + } +#endif + + enum { kChunkSize = 1024 }; + + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if (deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, Z_DEFAULT_STRATEGY) != Z_OK) { + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + ++ (BOOL)isGzipped:(NSData *)data { + const UInt8 *bytes = (const UInt8 *)data.bytes; + return (data.length >= 2 && bytes[0] == 0x1f && bytes[1] == 0x8b); +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m new file mode 100644 index 0000000..450fda8 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTNanopbHelpers.m @@ -0,0 +1,322 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#pragma mark - General purpose encoders + +pb_bytes_array_t *GDTCCTEncodeString(NSString *string) { + NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding]; + return GDTCCTEncodeData(stringBytes); +} + +pb_bytes_array_t *GDTCCTEncodeData(NSData *data) { + pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length)); + if (pbBytesArray != NULL) { + [data getBytes:pbBytesArray->bytes length:data.length]; + pbBytesArray->size = (pb_size_t)data.length; + } + return pbBytesArray; +} + +#pragma mark - CCT object constructors + +NSData *_Nullable GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest) { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + // Encode 1 time to determine the size. + if (!pb_encode(&sizestream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizestream)); + } + + // Encode a 2nd time to actually get the bytes from it. + size_t bufferSize = sizestream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, gdt_cct_BatchedLogRequest_fields, batchedLogRequest)) { + GDTCORLogError(GDTCORMCEGeneralError, @"Error in nanopb encoding for bytes: %s", + PB_GET_ERROR(&ostream)); + } + + return CFBridgingRelease(dataRef); +} + +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet) { + gdt_cct_BatchedLogRequest batchedLogRequest = gdt_cct_BatchedLogRequest_init_default; + NSUInteger numberOfLogRequests = logMappingIDToLogSet.count; + gdt_cct_LogRequest *logRequests = calloc(numberOfLogRequests, sizeof(gdt_cct_LogRequest)); + if (logRequests == NULL) { + return batchedLogRequest; + } + + __block int i = 0; + [logMappingIDToLogSet enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull logMappingID, + NSSet *_Nonnull logSet, + BOOL *_Nonnull stop) { + int32_t logSource = [logMappingID intValue]; + gdt_cct_LogRequest logRequest = GDTCCTConstructLogRequest(logSource, logSet); + logRequests[i] = logRequest; + i++; + }]; + + batchedLogRequest.log_request = logRequests; + batchedLogRequest.log_request_count = (pb_size_t)numberOfLogRequests; + return batchedLogRequest; +} + +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, + NSSet *_Nonnull logSet) { + if (logSet.count == 0) { + GDTCORLogError(GDTCORMCEGeneralError, @"%@", + @"An empty event set can't be serialized to proto."); + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + return logRequest; + } + gdt_cct_LogRequest logRequest = gdt_cct_LogRequest_init_default; + logRequest.log_source = logSource; + logRequest.has_log_source = 1; + logRequest.client_info = GDTCCTConstructClientInfo(); + logRequest.has_client_info = 1; + logRequest.log_event = calloc(logSet.count, sizeof(gdt_cct_LogEvent)); + if (logRequest.log_event == NULL) { + return logRequest; + } + int i = 0; + for (GDTCOREvent *log in logSet) { + gdt_cct_LogEvent logEvent = GDTCCTConstructLogEvent(log); + logRequest.log_event[i] = logEvent; + i++; + } + logRequest.log_event_count = (pb_size_t)logSet.count; + + GDTCORClock *currentTime = [GDTCORClock snapshot]; + logRequest.request_time_ms = currentTime.timeMillis; + logRequest.has_request_time_ms = 1; + logRequest.request_uptime_ms = [currentTime uptimeMilliseconds]; + logRequest.has_request_uptime_ms = 1; + + return logRequest; +} + +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event) { + gdt_cct_LogEvent logEvent = gdt_cct_LogEvent_init_default; + logEvent.event_time_ms = event.clockSnapshot.timeMillis; + logEvent.has_event_time_ms = 1; + logEvent.event_uptime_ms = [event.clockSnapshot uptimeMilliseconds]; + logEvent.has_event_uptime_ms = 1; + logEvent.timezone_offset_seconds = event.clockSnapshot.timezoneOffsetSeconds; + logEvent.has_timezone_offset_seconds = 1; + if (event.customBytes) { + NSData *networkConnectionInfoData = event.networkConnectionInfoData; + if (networkConnectionInfoData) { + [networkConnectionInfoData getBytes:&logEvent.network_connection_info + length:networkConnectionInfoData.length]; + logEvent.has_network_connection_info = 1; + } + NSNumber *eventCode = event.eventCode; + if (eventCode != nil) { + logEvent.has_event_code = 1; + logEvent.event_code = [eventCode intValue]; + } + } + NSError *error; + NSData *extensionBytes; + extensionBytes = event.serializedDataObjectBytes; + if (error) { + GDTCORLogWarning(GDTCORMCWFileReadError, + @"There was an error reading extension bytes from disk: %@", error); + return logEvent; + } + logEvent.source_extension = GDTCCTEncodeData(extensionBytes); // read bytes from the file. + if (event.productData) { + logEvent.compliance_data = GDTCCTConstructComplianceData(event.productData); + logEvent.has_compliance_data = 1; + } + return logEvent; +} + +gdt_cct_ComplianceData GDTCCTConstructComplianceData(GDTCORProductData *productData) { + privacy_context_external_ExternalPRequestContext prequest = + privacy_context_external_ExternalPRequestContext_init_default; + prequest.origin_associated_product_id = productData.productID; + prequest.has_origin_associated_product_id = 1; + + privacy_context_external_ExternalPrivacyContext privacy_context = + privacy_context_external_ExternalPrivacyContext_init_default; + privacy_context.prequest = prequest; + privacy_context.has_prequest = 1; + + gdt_cct_ComplianceData complianceData = gdt_cct_ComplianceData_init_default; + complianceData.privacy_context = privacy_context; + complianceData.has_privacy_context = 1; + complianceData.product_id_origin = gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE; + complianceData.has_product_id_origin = 1; + return complianceData; +} + +gdt_cct_ClientInfo GDTCCTConstructClientInfo(void) { + gdt_cct_ClientInfo clientInfo = gdt_cct_ClientInfo_init_default; + clientInfo.client_type = gdt_cct_ClientInfo_ClientType_IOS_FIREBASE; + clientInfo.has_client_type = 1; +#if TARGET_OS_IOS || TARGET_OS_TV + clientInfo.ios_client_info = GDTCCTConstructiOSClientInfo(); + clientInfo.has_ios_client_info = 1; +#elif TARGET_OS_OSX + clientInfo.mac_client_info = GDTCCTConstructMacClientInfo(); + clientInfo.has_mac_client_info = 1; +#endif + return clientInfo; +} + +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void) { + gdt_cct_IosClientInfo iOSClientInfo = gdt_cct_IosClientInfo_init_default; +#if TARGET_OS_IOS || TARGET_OS_TV + UIDevice *device = [UIDevice currentDevice]; + NSBundle *bundle = [NSBundle mainBundle]; + NSLocale *locale = [NSLocale currentLocale]; + iOSClientInfo.os_full_version = GDTCCTEncodeString(device.systemVersion); + NSArray *versionComponents = [device.systemVersion componentsSeparatedByString:@"."]; + iOSClientInfo.os_major_version = GDTCCTEncodeString(versionComponents[0]); + NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (version) { + iOSClientInfo.application_build = GDTCCTEncodeString(version); + } + NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; + if (countryCode) { + iOSClientInfo.country = GDTCCTEncodeString([locale objectForKey:NSLocaleCountryCode]); + } + iOSClientInfo.model = GDTCCTEncodeString(GDTCORDeviceModel()); + NSString *languageCode = bundle.preferredLocalizations.firstObject; + iOSClientInfo.language_code = + languageCode ? GDTCCTEncodeString(languageCode) : GDTCCTEncodeString(@"en"); + iOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundle.bundleIdentifier); +#endif + return iOSClientInfo; +} + +gdt_cct_MacClientInfo GDTCCTConstructMacClientInfo(void) { + gdt_cct_MacClientInfo macOSClientInfo = gdt_cct_MacClientInfo_init_default; + + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSString *majorVersion = [@(osVersion.majorVersion) stringValue]; + NSString *minorVersion = [@(osVersion.minorVersion) stringValue]; + NSString *majorAndMinorString = [NSString stringWithFormat:@"%@.%@", majorVersion, minorVersion]; + macOSClientInfo.os_major_version = GDTCCTEncodeString(majorAndMinorString); + + NSString *patchVersion = [@(osVersion.patchVersion) stringValue]; + NSString *majorMinorPatchString = + [NSString stringWithFormat:@"%@.%@", majorAndMinorString, patchVersion]; + macOSClientInfo.os_full_version = GDTCCTEncodeString(majorMinorPatchString); + + NSBundle *bundle = [NSBundle mainBundle]; + NSString *version = [bundle objectForInfoDictionaryKey:(NSString *)kCFBundleVersionKey]; + if (version) { + macOSClientInfo.application_build = GDTCCTEncodeString(version); + } + + NSString *bundleID = bundle.bundleIdentifier; + if (bundleID) { + macOSClientInfo.application_bundle_id = GDTCCTEncodeString(bundleID); + } + + return macOSClientInfo; +} + +NSData *GDTCCTConstructNetworkConnectionInfoData(void) { + gdt_cct_NetworkConnectionInfo networkConnectionInfo = gdt_cct_NetworkConnectionInfo_init_default; + NSInteger currentNetworkType = GDTCORNetworkTypeMessage(); + if (currentNetworkType) { + networkConnectionInfo.has_network_type = 1; + if (currentNetworkType == GDTCORNetworkTypeMobile) { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE; + networkConnectionInfo.mobile_subtype = GDTCCTNetworkConnectionInfoNetworkMobileSubtype(); + if (networkConnectionInfo.mobile_subtype != + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE) { + networkConnectionInfo.has_mobile_subtype = 1; + } + } else { + networkConnectionInfo.network_type = gdt_cct_NetworkConnectionInfo_NetworkType_WIFI; + } + } + NSData *networkConnectionInfoData = [NSData dataWithBytes:&networkConnectionInfo + length:sizeof(networkConnectionInfo)]; + return networkConnectionInfoData; +} + +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype(void) { + NSNumber *networkMobileSubtypeMessage = @(GDTCORNetworkMobileSubTypeMessage()); + if (!networkMobileSubtypeMessage.intValue) { + return gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; + } + static NSDictionary *MessageToNetworkSubTypeMessage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + MessageToNetworkSubTypeMessage = @{ + @(GDTCORNetworkMobileSubtypeGPRS) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS), + @(GDTCORNetworkMobileSubtypeEdge) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE), + @(GDTCORNetworkMobileSubtypeWCDMA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE), + @(GDTCORNetworkMobileSubtypeHSDPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA), + @(GDTCORNetworkMobileSubtypeHSUPA) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA), + @(GDTCORNetworkMobileSubtypeCDMA1x) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA), + @(GDTCORNetworkMobileSubtypeCDMAEVDORev0) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevA) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A), + @(GDTCORNetworkMobileSubtypeCDMAEVDORevB) : + @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B), + @(GDTCORNetworkMobileSubtypeHRPD) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD), + @(GDTCORNetworkMobileSubtypeLTE) : @(gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE), + }; + }); + NSNumber *networkMobileSubtype = MessageToNetworkSubTypeMessage[networkMobileSubtypeMessage]; + return networkMobileSubtype.intValue; +} + +#pragma mark - CCT Object decoders + +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error) { + gdt_cct_LogResponse response = gdt_cct_LogResponse_init_default; + pb_istream_t istream = pb_istream_from_buffer([data bytes], [data length]); + if (!pb_decode(&istream, gdt_cct_LogResponse_fields, &response)) { + NSString *nanopb_error = [NSString stringWithFormat:@"%s", PB_GET_ERROR(&istream)]; + NSDictionary *userInfo = @{@"nanopb error:" : nanopb_error}; + if (error != NULL) { + *error = [NSError errorWithDomain:NSURLErrorDomain code:-1 userInfo:userInfo]; + } + response = (gdt_cct_LogResponse)gdt_cct_LogResponse_init_default; + } + return response; +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m new file mode 100644 index 0000000..669e93f --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTURLSessionDataResponse.m @@ -0,0 +1,28 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h" + +@implementation GDTCCTURLSessionDataResponse + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(NSData *)body { + self = [super init]; + if (self) { + _HTTPResponse = response; + _HTTPBody = body; + } + return self; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m new file mode 100644 index 0000000..354d14c --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploadOperation.m @@ -0,0 +1,668 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h" +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +static NSString *const kGDTCCTSupportSDKVersion = @STR(GDTCOR_VERSION); +#else +static NSString *const kGDTCCTSupportSDKVersion = @"UNKNOWN"; +#endif // GDTCOR_VERSION + +typedef void (^GDTCCTUploaderURLTaskCompletion)(NSNumber *batchID, + NSSet *_Nullable events, + NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error); + +typedef void (^GDTCCTUploaderEventBatchBlock)(NSNumber *_Nullable batchID, + NSSet *_Nullable events); + +@interface GDTCCTUploadOperation () + +/// The properties to store parameters passed in the initializer. See the initialized docs for +/// details. +@property(nonatomic, readonly) GDTCORTarget target; +@property(nonatomic, readonly) GDTCORUploadConditions conditions; +@property(nonatomic, readonly) NSURL *uploadURL; +@property(nonatomic, readonly) id storage; +@property(nonatomic, readonly) id metadataProvider; +@property(nonatomic, readonly, nullable) id metricsController; + +/** The URL session that will attempt upload. */ +@property(nonatomic, nullable) NSURLSession *uploaderSession; + +/// The metrics being uploaded by the operation. These metrics are fetched and included as an event +/// in the upload batch as part of the upload process. +/// +/// Metrics being uploaded are retained so they can be re-stored if upload is not successful. +@property(nonatomic, nullable) GDTCORMetrics *currentMetrics; + +/// NSOperation state properties implementation. +@property(nonatomic, readwrite, getter=isExecuting) BOOL executing; +@property(nonatomic, readwrite, getter=isFinished) BOOL finished; + +@property(nonatomic, readwrite) BOOL uploadAttempted; + +@end + +@implementation GDTCCTUploadOperation + +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider + metricsController:(nullable id)metricsController { + self = [super init]; + if (self) { + _uploaderQueue = queue; + _target = target; + _conditions = conditions; + _uploadURL = uploadURL; + _storage = storage; + _metadataProvider = metadataProvider; + _metricsController = metricsController; + } + return self; +} + +- (NSURLSession *)uploaderSessionCreateIfNeeded { + if (_uploaderSession == nil) { + NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; + _uploaderSession = [NSURLSession sessionWithConfiguration:config + delegate:self + delegateQueue:nil]; + } + return _uploaderSession; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + __block GDTCORBackgroundIdentifier backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + + dispatch_block_t backgroundTaskCompletion = ^{ + // End the background task if there was one. + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + [[GDTCORApplication sharedApplication] endBackgroundTask:backgroundTaskID]; + backgroundTaskID = GDTCORBackgroundIdentifierInvalid; + } + }; + + backgroundTaskID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTCCTUploader-upload" + expirationHandler:^{ + if (backgroundTaskID != GDTCORBackgroundIdentifierInvalid) { + // Cancel the upload and complete delivery. + [self.currentTask cancel]; + + // End the background task. + backgroundTaskCompletion(); + } else { + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelWarnings, + @"Attempted to cancel invalid background task in " + "GDTCCTUploadOperation."); + } + }]; + + id storage = self.storage; + + // 1. Check if the conditions for the target are suitable. + [self isReadyToUploadTarget:target conditions:conditions] + .validateOn(self.uploaderQueue, + ^BOOL(NSNull *__unused _) { + // 2. Stop the operation if it has been cancelled. + return !self.isCancelled; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNull *result) { + // 3. Remove previously attempted batches. + return [storage removeAllBatchesForTarget:target deleteEvents:NO]; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNull *__unused _) { + // There may be a big amount of events stored, so creating a batch may be an + // expensive operation. + + // 4. Do a lightweight check if there are any events for the target first to + // finish early if there are none. + return [storage hasEventsForTarget:target]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(NSNumber *hasEvents) { + // 5. Stop operation if there are no events to upload. + return hasEvents.boolValue; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSNumber *__unused _) { + // 6. Fetch events to upload. + GDTCORStorageEventSelector *eventSelector = [self eventSelectorTarget:target + withConditions:conditions]; + return [storage batchWithEventSelector:eventSelector + batchExpiration:[NSDate dateWithTimeIntervalSinceNow:600]]; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCORUploadBatch *batch) { + // 7. Add metrics to the batch if the target has a + // corresponding metrics controller. + if (!self.metricsController) { + return [FBLPromise resolvedWith:batch]; + } + + return [self batchByAddingMetricsEventToBatch:batch forTarget:target]; + }) + .validateOn(self.uploaderQueue, + ^BOOL(GDTCORUploadBatch *__unused _) { + // 8. Stop the operation if it has been cancelled. + return !self.isCancelled; + }) + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCORUploadBatch *batch) { + // A non-empty batch has been created, consider it as an upload attempt. + self.uploadAttempted = YES; + + // 9. Perform upload. + return [self uploadBatch:batch toTarget:target storage:storage]; + }) + .catchOn(self.uploaderQueue, + ^(NSError *error){ + // TODO: Consider reporting the error to the client. + }) + .alwaysOn(self.uploaderQueue, ^{ + // 10. Finish operation. + [self finishOperation]; + backgroundTaskCompletion(); + }); +} + +#pragma mark - Upload implementation details + +/** Uploads a given batch from storage to a target. */ +- (FBLPromise *)uploadBatch:(GDTCORUploadBatch *)batch + toTarget:(GDTCORTarget)target + storage:(id)storage { + // 1. Send URL request. + return [self sendURLRequestWithBatch:batch target:target] + .thenOn(self.uploaderQueue, + ^FBLPromise *(GDTCCTURLSessionDataResponse *response) { + // 2. Update the next upload time and process response. + [self updateNextUploadTimeWithResponse:response forTarget:target]; + + return [self processResponse:response forBatch:batch storage:storage]; + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // If a network error occurred, move the events back to the main + // storage so they can attempt to be uploaded in the next attempt. + // Additionally, if metrics were added to the batch, place them back + // in storage. + if (self.currentMetrics) { + [self.metricsController offerMetrics:self.currentMetrics]; + } + return [storage removeBatchWithID:batch.batchID deleteEvents:NO]; + }); +} + +/** Processes a URL session response for a given batch from storage. */ +- (FBLPromise *)processResponse:(GDTCCTURLSessionDataResponse *)response + forBatch:(GDTCORUploadBatch *)batch + storage:(id)storage { + // Cleanup batch based on the response's status code. + NSInteger statusCode = response.HTTPResponse.statusCode; + BOOL isSuccess = statusCode >= 200 && statusCode < 300; + // Transient errors include "too many requests" (429) and server errors (5xx). + BOOL isTransientError = + statusCode == 429 || statusCode == 404 || (statusCode >= 500 && statusCode < 600); + + BOOL shouldDeleteEvents = isSuccess || !isTransientError; + + // If the batch included metrics and the upload failed, place metrics back + // in storage. + GDTCORMetrics *uploadedMetrics = [self currentMetrics]; + if (uploadedMetrics && !isSuccess) { + [self.metricsController offerMetrics:uploadedMetrics]; + } + + if (isSuccess) { + GDTCORLogDebug(@"CCT: batch %@ uploaded. Batch will be deleted.", batch.batchID); + + } else if (isTransientError) { + GDTCORLogDebug(@"CCT: batch %@ upload failed. Batch will attempt to be uploaded later.", + batch.batchID); + + } else { + GDTCORLogDebug(@"CCT: batch %@ upload failed. Batch will be deleted.", batch.batchID); + + if (/* isInvalidPayloadError */ statusCode == 400) { + // Log events that will be dropped due to the upload error. + [self.metricsController logEventsDroppedForReason:GDTCOREventDropReasonInvalidPayload + events:batch.events]; + } + } + + return [storage removeBatchWithID:batch.batchID deleteEvents:shouldDeleteEvents]; +} + +/** Composes and sends URL request. */ +- (FBLPromise *)sendURLRequestWithBatch:(GDTCORUploadBatch *)batch + target:(GDTCORTarget)target { + return [FBLPromise + onQueue:self.uploaderQueue + do:^NSURLRequest * { + // 1. Prepare URL request. + NSData *requestProtoData = [self constructRequestProtoWithEvents:batch.events]; + NSData *gzippedData = [GDTCCTCompressionHelper gzippedData:requestProtoData]; + BOOL usingGzipData = + gzippedData != nil && gzippedData.length < requestProtoData.length; + NSData *dataToSend = usingGzipData ? gzippedData : requestProtoData; + NSURLRequest *request = [self constructRequestWithURL:self.uploadURL + forTarget:target + data:dataToSend]; + GDTCORLogDebug(@"CTT: request containing %lu events for batch: %@ for target: " + @"%ld created: %@", + (unsigned long)batch.events.count, batch.batchID, (long)target, + request); + return request; + }] + .thenOn(self.uploaderQueue, + ^FBLPromise *(NSURLRequest *request) { + // 2. Send URL request. + NSURLSession *session = [self uploaderSessionCreateIfNeeded]; + return [FBLPromise wrapObjectOrErrorCompletion:^( + FBLPromiseObjectOrErrorCompletion _Nonnull handler) { + [[session dataTaskWithRequest:request + completionHandler:^(NSData *_Nullable data, + NSURLResponse *_Nullable response, + NSError *_Nullable error) { + if (error) { + handler(nil, error); + } else { + handler([[GDTCCTURLSessionDataResponse alloc] + initWithResponse:(NSHTTPURLResponse *)response + HTTPBody:data], + nil); + } + }] resume]; + }]; + }) + .thenOn(self.uploaderQueue, + ^GDTCCTURLSessionDataResponse *(GDTCCTURLSessionDataResponse *response) { + // Invalidate session to release the delegate (which is `self`) to break the retain + // cycle. + [self.uploaderSession finishTasksAndInvalidate]; + return response; + }) + .recoverOn(self.uploaderQueue, ^id(NSError *error) { + // Invalidate session to release the delegate (which is `self`) to break the retain cycle. + [self.uploaderSession finishTasksAndInvalidate]; + // Re-throw the error. + return error; + }); +} + +/** Parses server response and update next upload time for the specified target based on it. */ +- (void)updateNextUploadTimeWithResponse:(GDTCCTURLSessionDataResponse *)response + forTarget:(GDTCORTarget)target { + GDTCORClock *futureUploadTime; + if (response.HTTPBody) { + NSError *decodingError; + gdt_cct_LogResponse logResponse = GDTCCTDecodeLogResponse(response.HTTPBody, &decodingError); + if (!decodingError && logResponse.has_next_request_wait_millis) { + GDTCORLogDebug(@"CCT: The backend responded asking to not upload for %lld millis from now.", + logResponse.next_request_wait_millis); + futureUploadTime = + [GDTCORClock clockSnapshotInTheFuture:logResponse.next_request_wait_millis]; + } else if (decodingError) { + GDTCORLogDebug(@"There was a response decoding error: %@", decodingError); + } + pb_release(gdt_cct_LogResponse_fields, &logResponse); + } + + // If no futureUploadTime was parsed from the response body, then check + // [Retry-After](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After) header. + if (!futureUploadTime) { + NSString *retryAfterHeader = response.HTTPResponse.allHeaderFields[@"Retry-After"]; + if (retryAfterHeader.length > 0) { + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *retryAfterSeconds = [formatter numberFromString:retryAfterHeader]; + if (retryAfterSeconds != nil) { + uint64_t retryAfterMillis = retryAfterSeconds.unsignedIntegerValue * 1000u; + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:retryAfterMillis]; + } + } + } + + if (!futureUploadTime) { + GDTCORLogDebug(@"%@", @"CCT: The backend response failed to parse, so the next request " + @"won't occur until 15 minutes from now"); + // 15 minutes from now. + futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:15 * 60 * 1000]; + } + + [self.metadataProvider setNextUploadTime:futureUploadTime forTarget:target]; +} + +#pragma mark - Private helper methods + +/** @return A resolved promise if is ready and a rejected promise if not. */ +- (FBLPromise *)isReadyToUploadTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions { + FBLPromise *promise = [FBLPromise pendingPromise]; + if ([self readyToUploadTarget:target conditions:conditions]) { + [promise fulfill:[NSNull null]]; + } else { + NSString *reason = + [NSString stringWithFormat:@"Target %ld is not ready to upload with condition: %ld", + (long)target, (long)conditions]; + [promise reject:[self genericRejectedPromiseErrorWithReason:reason]]; + } + return promise; +} + +// TODO: Move to a separate class/extension/file when needed in other files. +/** Returns an error object with the specified failure reason. */ +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCCTUploader" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +/** Returns if the specified target is ready to be uploaded based on the specified conditions. */ +- (BOOL)readyToUploadTarget:(GDTCORTarget)target conditions:(GDTCORUploadConditions)conditions { + // Not ready to upload with no network connection. + // TODO: Reconsider using reachability to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if (conditions & GDTCORUploadConditionNoNetwork) { + GDTCORLogDebug(@"%@", @"CCT: Not ready to upload without a network connection."); + return NO; + } + + // Upload events with no additional conditions if high priority. + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + GDTCORLogDebug(@"%@", @"CCT: a high priority event is allowing an upload"); + return YES; + } + + // Check next upload time for the target. + BOOL isAfterNextUploadTime = YES; + GDTCORClock *nextUploadTime = [self.metadataProvider nextUploadTimeForTarget:target]; + if (nextUploadTime) { + isAfterNextUploadTime = [[GDTCORClock snapshot] isAfter:nextUploadTime]; + } + + if (isAfterNextUploadTime) { + GDTCORLogDebug(@"CCT: can upload to target %ld because the request wait time has transpired", + (long)target); + } else { + GDTCORLogDebug(@"CCT: can't upload to target %ld because the backend asked to wait", + (long)target); + } + + return isAfterNextUploadTime; +} + +/** Constructs data given an upload package. + * + * @param events The events used to construct the request proto bytes. + * @return Proto bytes representing a gdt_cct_LogRequest object. + */ +- (nonnull NSData *)constructRequestProtoWithEvents:(NSSet *)events { + // Segment the log events by log type. + NSMutableDictionary *> *logMappingIDToLogSet = + [[NSMutableDictionary alloc] init]; + [events enumerateObjectsUsingBlock:^(GDTCOREvent *_Nonnull event, BOOL *_Nonnull stop) { + NSMutableSet *logSet = logMappingIDToLogSet[event.mappingID]; + logSet = logSet ? logSet : [[NSMutableSet alloc] init]; + [logSet addObject:event]; + logMappingIDToLogSet[event.mappingID] = logSet; + }]; + + gdt_cct_BatchedLogRequest batchedLogRequest = + GDTCCTConstructBatchedLogRequest(logMappingIDToLogSet); + + NSData *data = GDTCCTEncodeBatchedLogRequest(&batchedLogRequest); + pb_release(gdt_cct_BatchedLogRequest_fields, &batchedLogRequest); + return data ? data : [[NSData alloc] init]; +} + +/** Constructs a request to the given URL and target with the specified request body data. + * + * @param target The target backend to send the request to. + * @param data The request body data. + * @return A new NSURLRequest ready to be sent to FLL. + */ +- (nullable NSURLRequest *)constructRequestWithURL:(NSURL *)URL + forTarget:(GDTCORTarget)target + data:(NSData *)data { + if (data == nil || data.length == 0) { + GDTCORLogDebug(@"There was no data to construct a request for target %ld.", (long)target); + return nil; + } + + NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL]; + NSString *targetString; + switch (target) { + case kGDTCORTargetCCT: + targetString = @"cct"; + break; + + case kGDTCORTargetFLL: + targetString = @"fll"; + break; + + case kGDTCORTargetCSH: + targetString = @"csh"; + break; + case kGDTCORTargetINT: + targetString = @"int"; + break; + + default: + targetString = @"unknown"; + break; + } + NSString *userAgent = + [NSString stringWithFormat:@"datatransport/%@ %@support/%@ apple/", kGDTCORVersion, + targetString, kGDTCCTSupportSDKVersion]; + + [request setValue:[self.metadataProvider APIKeyForTarget:target] + forHTTPHeaderField:@"X-Goog-Api-Key"]; + + if ([GDTCCTCompressionHelper isGzipped:data]) { + [request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"]; + } + [request setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"]; + [request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"]; + [request setValue:userAgent forHTTPHeaderField:@"User-Agent"]; + request.HTTPMethod = @"POST"; + [request setHTTPBody:data]; + return request; +} + +/** Creates and returns a storage event selector for the specified target and conditions. */ +- (GDTCORStorageEventSelector *)eventSelectorTarget:(GDTCORTarget)target + withConditions:(GDTCORUploadConditions)conditions { + if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) { + return [GDTCORStorageEventSelector eventSelectorForTarget:target]; + } + NSMutableSet *qosTiers = [[NSMutableSet alloc] init]; + if (conditions & GDTCORUploadConditionWifiData) { + [qosTiers addObjectsFromArray:@[ + @(GDTCOREventQoSFast), @(GDTCOREventQoSWifiOnly), @(GDTCOREventQosDefault), + @(GDTCOREventQoSTelemetry), @(GDTCOREventQoSUnknown) + ]]; + } + if (conditions & GDTCORUploadConditionMobileData) { + [qosTiers addObjectsFromArray:@[ @(GDTCOREventQoSFast), @(GDTCOREventQosDefault) ]]; + } + + return [[GDTCORStorageEventSelector alloc] initWithTarget:target + eventIDs:nil + mappingIDs:nil + qosTiers:qosTiers]; +} + +- (FBLPromise *)batchByAddingMetricsEventToBatch:(GDTCORUploadBatch *)batch + forTarget:(GDTCORTarget)target { + return [self.metricsController getAndResetMetrics] + .thenOn(self.uploaderQueue, + ^GDTCORUploadBatch *(GDTCORMetrics *metrics) { + // Save the metrics so they can be re-stored if upload fails. + [self setCurrentMetrics:metrics]; + + GDTCOREvent *metricsEvent = [GDTCOREvent eventWithMetrics:metrics forTarget:target]; + GDTCORUploadBatch *batchWithMetricEvent = [[GDTCORUploadBatch alloc] + initWithBatchID:batch.batchID + events:[batch.events setByAddingObject:metricsEvent]]; + + return batchWithMetricEvent; + }) + .recoverOn(self.uploaderQueue, ^GDTCORUploadBatch *(NSError *error) { + // Return given batch if an error occurs (i.e. no metrics were fetched). + return batch; + }); +} + +#pragma mark - NSURLSessionDelegate + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *_Nullable))completionHandler { + if (!completionHandler) { + return; + } + if (response.statusCode == 302 || response.statusCode == 301) { + NSURLRequest *newRequest = [self constructRequestWithURL:request.URL + forTarget:kGDTCORTargetCCT + data:task.originalRequest.HTTPBody]; + completionHandler(newRequest); + } else { + completionHandler(request); + } +} + +#pragma mark - NSOperation methods + +@synthesize executing = _executing; +@synthesize finished = _finished; + +- (BOOL)isFinished { + @synchronized(self) { + return _finished; + } +} + +- (BOOL)isExecuting { + @synchronized(self) { + return _executing; + } +} + +- (BOOL)isAsynchronous { + return YES; +} + +- (void)startOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = YES; + self->_finished = NO; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)finishOperation { + @synchronized(self) { + [self willChangeValueForKey:@"isExecuting"]; + [self willChangeValueForKey:@"isFinished"]; + self->_executing = NO; + self->_finished = YES; + [self didChangeValueForKey:@"isExecuting"]; + [self didChangeValueForKey:@"isFinished"]; + } +} + +- (void)start { + [self startOperation]; + + GDTCORLogDebug(@"Upload operation started: %@", self); + [self uploadTarget:self.target withConditions:self.conditions]; +} + +- (void)cancel { + @synchronized(self) { + [super cancel]; + + // If the operation hasn't been started we can set `isFinished = YES` straight away. + if (!_executing) { + _executing = NO; + _finished = YES; + } + } +} + +#pragma mark - Force Category Linking + +extern void GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(void); +extern void GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(void); +extern void GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(); + GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(); + GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m new file mode 100644 index 0000000..c436ed3 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCCTUploader.m @@ -0,0 +1,215 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCCTUploader () + +@property(nonatomic, readonly) NSOperationQueue *uploadOperationQueue; +@property(nonatomic, readonly) dispatch_queue_t uploadQueue; + +@property(nonatomic, readonly) + NSMutableDictionary *nextUploadTimeByTarget; + +@end + +@implementation GDTCCTUploader + +static NSURL *_testServerURL = nil; + ++ (void)load { + GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance]; +#if GDT_TEST + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetTest]; +#endif // GDT_TEST + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCCTUploader *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCCTUploader alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _uploadQueue = dispatch_queue_create("com.google.GDTCCTUploader", DISPATCH_QUEUE_SERIAL); + _uploadOperationQueue = [[NSOperationQueue alloc] init]; + _uploadOperationQueue.maxConcurrentOperationCount = 1; + _nextUploadTimeByTarget = [[NSMutableDictionary alloc] init]; + } + return self; +} + +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions { + // Current GDTCCTUploader expected behaviour: + // 1. Accept multiple upload request + // 2. Verify if there are events eligible for upload and start upload for the first suitable + // target + // 3. Ignore other requests while an upload is in-progress. + + // TODO: Revisit expected behaviour. + // Potentially better option: + // 1. Accept and enqueue all upload requests + // 2. Notify the client of upload stages + // 3. Allow the client cancelling upload requests as needed. + + id storage = GDTCORStoragePromiseInstanceForTarget(target); + if (storage == nil) { + GDTCORLogError(GDTCORMCEGeneralError, + @"Failed to upload target: %ld - could not find corresponding storage instance.", + (long)target); + return; + } + + id metricsController = + GDTCORMetricsControllerInstanceForTarget(target); + + GDTCCTUploadOperation *uploadOperation = + [[GDTCCTUploadOperation alloc] initWithTarget:target + conditions:conditions + uploadURL:[[self class] serverURLForTarget:target] + queue:self.uploadQueue + storage:storage + metadataProvider:self + metricsController:metricsController]; + + GDTCORLogDebug(@"Upload operation created: %@, target: %@", uploadOperation, @(target)); + + __weak __auto_type weakSelf = self; + __weak GDTCCTUploadOperation *weakOperation = uploadOperation; + uploadOperation.completionBlock = ^{ + __auto_type strongSelf = weakSelf; + GDTCCTUploadOperation *strongOperation = weakOperation; + if (strongSelf == nil || strongOperation == nil) { + GDTCORLogDebug(@"Internal inconsistency: GDTCCTUploader was deallocated during upload.", nil); + return; + } + + GDTCORLogDebug(@"Upload operation finished: %@, uploadAttempted: %@", strongOperation, + @(strongOperation.uploadAttempted)); + + if (strongOperation.uploadAttempted) { + // Ignore all upload requests received when the upload was in progress. + [strongSelf.uploadOperationQueue cancelAllOperations]; + } + }; + + [self.uploadOperationQueue addOperation:uploadOperation]; + GDTCORLogDebug(@"Upload operation scheduled: %@, operation count: %@", uploadOperation, + @(self.uploadOperationQueue.operationCount)); +} + +#pragma mark - URLs + ++ (void)setTestServerURL:(NSURL *_Nullable)serverURL { + _testServerURL = serverURL; +} + ++ (NSURL *_Nullable)testServerURL { + return _testServerURL; +} + ++ (nullable NSURL *)serverURLForTarget:(GDTCORTarget)target { +#if GDT_TEST + if (_testServerURL) { + return _testServerURL; + } +#endif // GDT_TEST + + return [GDTCOREndpoints uploadURLForTarget:target]; +} + +- (NSString *)FLLAndCSHAndINTAPIKey { + static NSString *defaultServerKey; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + // These strings should be interleaved to construct the real key. + const char *p1 = "AzSBG0honD6A-PxV5nBc"; + const char *p2 = "Iay44Iwtu2vV0AOrz1C"; + const char defaultKey[40] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], + p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], + p1[8], p2[8], p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], + p1[12], p2[12], p1[13], p2[13], p1[14], p2[14], p1[15], p2[15], + p1[16], p2[16], p1[17], p2[17], p1[18], p2[18], p1[19], '\0'}; + defaultServerKey = [NSString stringWithUTF8String:defaultKey]; + }); + return defaultServerKey; +} + +#pragma mark - GDTCCTUploadMetadataProvider + +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + return self.nextUploadTimeByTarget[@(target)]; + } +} + +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target { + @synchronized(self.nextUploadTimeByTarget) { + self.nextUploadTimeByTarget[@(target)] = time; + } +} + +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target { + if (target == kGDTCORTargetFLL || target == kGDTCORTargetCSH) { + return [self FLLAndCSHAndINTAPIKey]; + } + + if (target == kGDTCORTargetINT) { + return [self FLLAndCSHAndINTAPIKey]; + } + + return nil; +} + +#if GDT_TEST +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout { + NSDate *expirationDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + while ([expirationDate compare:[NSDate date]] == NSOrderedDescending) { + if (self.uploadOperationQueue.operationCount == 0) { + return YES; + } else { + [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; + } + } + + GDTCORLogDebug(@"Uploader wait for finish timeout exceeded. Operations still in queue: %@", + self.uploadOperationQueue.operations); + return NO; +} +#endif // GDT_TEST + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m new file mode 100644 index 0000000..f102c81 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTCCTSupport.m @@ -0,0 +1,244 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NSString *const GDTCCTNeedsNetworkConnectionInfo = @"needs_network_connection_info"; + +NSString *const GDTCCTNetworkConnectionInfo = @"network_connection_info"; + +NSString *const GDTCCTEventCodeInfo = @"event_code_info"; + +@implementation GDTCOREvent (GDTCCTSupport) + +- (void)setNeedsNetworkConnectionInfoPopulated:(BOOL)needsNetworkConnectionInfoPopulated { + if (!needsNetworkConnectionInfoPopulated) { + if (!self.customBytes) { + return; + } + + // Make sure we don't destroy the eventCode data, if any is present. + @try { + NSError *error; + NSMutableDictionary *bytesDict = + [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + NSNumber *eventCode = bytesDict[GDTCCTEventCodeInfo]; + if (eventCode != nil) { + self.customBytes = + [NSJSONSerialization dataWithJSONObject:@{GDTCCTEventCodeInfo : eventCode} + options:0 + error:&error]; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } else { + @try { + NSError *error; + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:@YES forKey:GDTCCTNeedsNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting the event for needs_network_connection_info: %@", + exception); + } + } +} + +- (BOOL)needsNetworkConnectionInfoPopulated { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + return bytesDict && !error && [bytesDict[GDTCCTNeedsNetworkConnectionInfo] boolValue]; + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when checking the event for needs_network_connection_info: %@", + exception); + } + } + return NO; +} + +- (void)setNetworkConnectionInfoData:(NSData *)networkConnectionInfoData { + @try { + NSError *error; + NSString *dataString = [networkConnectionInfoData base64EncodedStringWithOptions:0]; + if (dataString != nil) { + NSMutableDictionary *bytesDict; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an even'ts event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + [bytesDict setObject:dataString forKey:GDTCCTNetworkConnectionInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + } + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", exception); + } +} + +- (nullable NSData *)networkConnectionInfoData { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *base64Data = bytesDict[GDTCCTNetworkConnectionInfo]; + if (base64Data == nil) { + return nil; + } + + NSData *networkConnectionInfoData = [[NSData alloc] initWithBase64EncodedString:base64Data + options:0]; + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return networkConnectionInfoData; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } + } + return nil; +} + +- (NSNumber *)eventCode { + if (self.customBytes) { + @try { + NSError *error; + NSDictionary *bytesDict = [NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error]; + NSString *eventCodeString = bytesDict[GDTCCTEventCodeInfo]; + + if (!eventCodeString) { + return nil; + } + + NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init]; + formatter.numberStyle = NSNumberFormatterDecimalStyle; + NSNumber *eventCode = [formatter numberFromString:eventCodeString]; + + if (error) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", error); + return nil; + } else { + return eventCode; + } + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's event_code: %@", exception); + } + } + return nil; +} + +- (void)setEventCode:(NSNumber *)eventCode { + if (eventCode == nil) { + if (!self.customBytes) { + return; + } + + NSError *error; + NSMutableDictionary *bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes + options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + + [bytesDict removeObjectForKey:GDTCCTEventCodeInfo]; + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + return; + } + + @try { + NSMutableDictionary *bytesDict; + NSError *error; + if (self.customBytes) { + bytesDict = [[NSJSONSerialization JSONObjectWithData:self.customBytes options:0 + error:&error] mutableCopy]; + if (error) { + GDTCORLogDebug(@"Error when setting an event's event_code: %@", error); + return; + } + } else { + bytesDict = [[NSMutableDictionary alloc] init]; + } + + NSString *eventCodeString = [eventCode stringValue]; + if (eventCodeString == nil) { + return; + } + + [bytesDict setObject:eventCodeString forKey:GDTCCTEventCodeInfo]; + + self.customBytes = [NSJSONSerialization dataWithJSONObject:bytesDict options:0 error:&error]; + if (error) { + self.customBytes = nil; + GDTCORLogDebug(@"Error when setting an event's network_connection_info: %@", error); + return; + } + + } @catch (NSException *exception) { + GDTCORLogDebug(@"Error when getting an event's network_connection_info: %@", exception); + } +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCOREvent_GDTCCTSupport_Category(void) { +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m new file mode 100644 index 0000000..6386835 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCOREvent+GDTMetricsSupport.m @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +/// The mapping ID that represents the `LogSource` for GDT metrics. +static NSString *const kMetricEventMappingID = @"1710"; + +@implementation GDTCOREvent (GDTMetricsSupport) + ++ (GDTCOREvent *)eventWithMetrics:(GDTCORMetrics *)metrics forTarget:(GDTCORTarget)target { + GDTCOREvent *metricsEvent = [[GDTCOREvent alloc] initWithMappingID:kMetricEventMappingID + target:target]; + metricsEvent.dataObject = metrics; + + return metricsEvent; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCOREvent_GDTMetricsSupport_Category(void) { +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m new file mode 100644 index 0000000..044b85a --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/GDTCORMetrics+GDTCCTSupport.m @@ -0,0 +1,211 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h" + +#import +#import +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h" + +typedef NSDictionary GDTCORDroppedEventCounter; + +@interface GDTCORLogSourceMetrics (Internal) + +/// A dictionary of log sources that map to counters that reflect the number of events dropped for a +/// given set of reasons (``GDTCOREventDropReason``). +@property(nonatomic, readonly) + NSDictionary *droppedEventCounterByLogSource; + +@end + +@implementation GDTCORMetrics (GDTCCTSupport) + +- (NSData *)transportBytes { + // Create and populate proto. + gdt_client_metrics_ClientMetrics clientMetricsProto = + gdt_client_metrics_ClientMetrics_init_default; + + clientMetricsProto.window = + GDTCCTConstructTimeWindow(self.collectionStartDate, self.collectionEndDate); + + clientMetricsProto.log_source_metrics = GDTCCTConstructLogSourceMetrics(self.logSourceMetrics); + clientMetricsProto.log_source_metrics_count = + GDTCCTGetLogSourceMetricsCount(self.logSourceMetrics); + + clientMetricsProto.global_metrics = + GDTCCTConstructGlobalMetrics(self.currentCacheSize, self.maxCacheSize); + + clientMetricsProto.app_namespace = GDTCCTEncodeString(self.bundleID); + + // Encode proto into a data buffer. + pb_ostream_t sizeStream = PB_OSTREAM_SIZING; + + // - Encode 1 time to determine the expected size of the buffer. + if (!pb_encode(&sizeStream, gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&sizeStream)); + } + + // - Encode a 2nd time to actually copy the proto's bytes into the buffer. + size_t bufferSize = sizeStream.bytes_written; + CFMutableDataRef dataRef = CFDataCreateMutable(CFAllocatorGetDefault(), bufferSize); + CFDataSetLength(dataRef, bufferSize); + pb_ostream_t ostream = pb_ostream_from_buffer((void *)CFDataGetBytePtr(dataRef), bufferSize); + if (!pb_encode(&ostream, gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto)) { + GDTCORLogError(GDTCORMCETransportBytesError, @"Error in nanopb encoding for size: %s", + PB_GET_ERROR(&ostream)); + } + CFDataSetLength(dataRef, ostream.bytes_written); + + // Release the allocated proto. + pb_release(gdt_client_metrics_ClientMetrics_fields, &clientMetricsProto); + + return CFBridgingRelease(dataRef); +} + +/// Constructs and returns a ``gdt_client_metrics_LogSourceMetrics`` from the given log source +/// metrics. +/// @param logSourceMetrics The given log source metrics. +gdt_client_metrics_LogSourceMetrics *GDTCCTConstructLogSourceMetrics( + GDTCORLogSourceMetrics *logSourceMetrics) { + // The metrics proto is a repeating field where each element represents the + // dropped event data for a log source (mapping ID). + NSUInteger logMetricsCount = logSourceMetrics.droppedEventCounterByLogSource.count; + gdt_client_metrics_LogSourceMetrics *repeatedLogSourceMetrics = + calloc(logMetricsCount, sizeof(gdt_client_metrics_LogSourceMetrics)); + + // Each log source (mapping ID) has a corresponding dropped event counter. + // Enumerate over the dictionary of log source and, for each log source, + // (mapping ID) create a proto representation of the number of events dropped + // for each given reason. + __block NSUInteger logSourceIndex = 0; + [logSourceMetrics.droppedEventCounterByLogSource + enumerateKeysAndObjectsUsingBlock:^(NSString *logSource, + GDTCORDroppedEventCounter *eventCounterForLogSource, + BOOL *__unused _) { + // Create the log source proto for the given mapping ID. It contains a + // repeating field to encapsulate the number of events dropped for each + // given drop reason. + __block gdt_client_metrics_LogSourceMetrics logSourceMetrics = + gdt_client_metrics_LogSourceMetrics_init_zero; + logSourceMetrics.log_source = GDTCCTEncodeString(logSource); + logSourceMetrics.log_event_dropped_count = (pb_size_t)eventCounterForLogSource.count; + logSourceMetrics.log_event_dropped = + calloc(eventCounterForLogSource.count, sizeof(gdt_client_metrics_LogEventDropped)); + + // Each dropped event counter counts the number of events dropped for + // each drop reason. Enumerate over all of these counters to populate + // the log source proto's repeating field of event drop data. + __block NSUInteger eventCounterIndex = 0; + [eventCounterForLogSource + enumerateKeysAndObjectsUsingBlock:^(NSNumber *eventDropReason, + NSNumber *droppedEventCount, BOOL *__unused _) { + gdt_client_metrics_LogEventDropped droppedEvents = + gdt_client_metrics_LogEventDropped_init_zero; + droppedEvents.events_dropped_count = droppedEventCount.integerValue; + droppedEvents.reason = + GDTCCTConvertEventDropReasonToProtoReason(eventDropReason.integerValue); + + // Append the dropped events proto to the repeated field and + // increment the index used for appending. + logSourceMetrics.log_event_dropped[eventCounterIndex] = droppedEvents; + eventCounterIndex += 1; + }]; + + // Append the metrics for the given log source (mappingID) to the + // repeated field and increment the index used for appending. + repeatedLogSourceMetrics[logSourceIndex] = logSourceMetrics; + logSourceIndex += 1; + }]; + + return repeatedLogSourceMetrics; +} + +/// Returns the count of log sources that have event drop metrics. +/// @param logSourceMetrics The given log source metrics. +pb_size_t GDTCCTGetLogSourceMetricsCount(GDTCORLogSourceMetrics *logSourceMetrics) { + return (pb_size_t)logSourceMetrics.droppedEventCounterByLogSource.count; +} + +/// Constructs and returns a ``gdt_client_metrics_TimeWindow`` proto from the given parameters. +/// @param collectionStartDate The start of the time window. +/// @param collectionEndDate The end of the time window. +gdt_client_metrics_TimeWindow GDTCCTConstructTimeWindow(NSDate *collectionStartDate, + NSDate *collectionEndDate) { + gdt_client_metrics_TimeWindow timeWindow = gdt_client_metrics_TimeWindow_init_zero; + // `- [NSDate timeIntervalSince1970]` returns a time interval in seconds so + // multiply by 1000 to convert to milliseconds. + timeWindow.start_ms = (int64_t)collectionStartDate.timeIntervalSince1970 * 1000; + timeWindow.end_ms = (int64_t)collectionEndDate.timeIntervalSince1970 * 1000; + return timeWindow; +} + +/// Constructs and returns a ``gdt_client_metrics_GlobalMetrics`` proto from the given parameters. +/// @param currentCacheSize The current cache size. +/// @param maxCacheSize The max cache size. +gdt_client_metrics_GlobalMetrics GDTCCTConstructGlobalMetrics(uint64_t currentCacheSize, + uint64_t maxCacheSize) { + gdt_client_metrics_StorageMetrics storageMetrics = gdt_client_metrics_StorageMetrics_init_zero; + storageMetrics.current_cache_size_bytes = currentCacheSize; + storageMetrics.max_cache_size_bytes = maxCacheSize; + + gdt_client_metrics_GlobalMetrics globalMetrics = gdt_client_metrics_GlobalMetrics_init_zero; + globalMetrics.storage_metrics = storageMetrics; + + return globalMetrics; +} + +/// Returns the corresponding ``gdt_client_metrics_LogEventDropped_Reason`` for the given +/// ``GDTCOREventDropReason``. +/// +/// To represent ``GDTCOREventDropReason`` in a proto, the reason must be mapped to a +/// ``gdt_client_metrics_LogEventDropped_Reason``. +/// +/// @param reason The ``GDTCOREventDropReason`` to represent in a proto. +gdt_client_metrics_LogEventDropped_Reason GDTCCTConvertEventDropReasonToProtoReason( + GDTCOREventDropReason reason) { + switch (reason) { + case GDTCOREventDropReasonUnknown: + return gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN; + case GDTCOREventDropReasonMessageTooOld: + return gdt_client_metrics_LogEventDropped_Reason_MESSAGE_TOO_OLD; + case GDTCOREventDropReasonStorageFull: + return gdt_client_metrics_LogEventDropped_Reason_CACHE_FULL; + case GDTCOREventDropReasonPayloadTooBig: + return gdt_client_metrics_LogEventDropped_Reason_PAYLOAD_TOO_BIG; + case GDTCOREventDropReasonMaxRetriesReached: + return gdt_client_metrics_LogEventDropped_Reason_MAX_RETRIES_REACHED; + case GDTCOREventDropReasonInvalidPayload: + // The below typo (`PAYLOD`) is currently checked in to g3. + return gdt_client_metrics_LogEventDropped_Reason_INVALID_PAYLOD; + case GDTCOREventDropReasonServerError: + return gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR; + } +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCCTInclude_GDTCORLogSourceMetrics_Internal_Category(void) { +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h new file mode 100644 index 0000000..b53dd5f --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTCompressionHelper.h @@ -0,0 +1,40 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** A class with methods to help with gzipped data. */ +@interface GDTCCTCompressionHelper : NSObject + +/** Compresses the given data and returns a new data object. + * + * @note Reduced version from GULNSData+zlib.m of GoogleUtilities. + * @return Compressed data, or nil if there was an error. + */ ++ (nullable NSData *)gzippedData:(NSData *)data; + +/** Returns YES if the data looks like it was gzip compressed by checking for the gzip magic number. + * + * @note: From https://en.wikipedia.org/wiki/Gzip, gzip's magic number is 1f 8b. + * @return YES if the data appears gzipped, NO otherwise. + */ ++ (BOOL)isGzipped:(NSData *)data; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h new file mode 100644 index 0000000..2f0ccd0 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h @@ -0,0 +1,144 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" +#import "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +NS_ASSUME_NONNULL_BEGIN + +#pragma mark - General purpose encoders + +/** Converts an NSString* to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param string The string to convert. + * @return A newly allocated array of bytes representing the UTF8 encoding of the string. + */ +pb_bytes_array_t *GDTCCTEncodeString(NSString *string); + +/** Converts an NSData to a pb_bytes_array_t*. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param data The data to convert. + * @return A newly allocated array of bytes with [data bytes] copied into it. + */ +pb_bytes_array_t *GDTCCTEncodeData(NSData *data); + +#pragma mark - CCT object constructors + +/** Encodes a batched log request. + * + * @note Ensure that pb_release is called on the batchedLogRequest param. + * + * @param batchedLogRequest A pointer to the log batch to encode to bytes. + * @return An NSData object representing the bytes of the log request batch. + */ +FOUNDATION_EXPORT +NSData *GDTCCTEncodeBatchedLogRequest(gdt_cct_BatchedLogRequest *batchedLogRequest); + +/** Constructs a gdt_cct_BatchedLogRequest given sets of events segemented by mapping ID. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * + * @param logMappingIDToLogSet A map of mapping IDs to sets of events to convert into a batch. + * @return A newly created gdt_cct_BatchedLogRequest. + */ +FOUNDATION_EXPORT +gdt_cct_BatchedLogRequest GDTCCTConstructBatchedLogRequest( + NSDictionary *> *logMappingIDToLogSet); + +/** Constructs a log request given a log source and a set of events. + * + * @note calloc is called in this method. Ensure that pb_release is called on this or the parent. + * @param logSource The CCT log source to put into the log request. + * @param logSet The set of events to send in this log request. + */ +FOUNDATION_EXPORT +gdt_cct_LogRequest GDTCCTConstructLogRequest(int32_t logSource, NSSet *logSet); + +/** Constructs a gdt_cct_LogEvent given a GDTCOREvent*. + * + * @param event The GDTCOREvent to convert. + * @return The new gdt_cct_LogEvent object. + */ +FOUNDATION_EXPORT +gdt_cct_LogEvent GDTCCTConstructLogEvent(GDTCOREvent *event); + +/** Constructs a `gdt_cct_ComplianceData` given a `GDTCORProductData` instance. + * + * @param productData The product data to convert to compliance data. + */ +FOUNDATION_EXPORT +gdt_cct_ComplianceData GDTCCTConstructComplianceData(GDTCORProductData *productData); + +/** Constructs a gdt_cct_ClientInfo representing the client device. + * + * @return The new gdt_cct_ClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_ClientInfo GDTCCTConstructClientInfo(void); + +/** Constructs a gdt_cct_IosClientInfo representing the client device. + * + * @return The new gdt_cct_IosClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_IosClientInfo GDTCCTConstructiOSClientInfo(void); + +/** Constructs a gdt_cct_MacClientInfo representing the client device. + * + * @return The new gdt_cct_MacClientInfo object. + */ +FOUNDATION_EXPORT +gdt_cct_MacClientInfo GDTCCTConstructMacClientInfo(void); + +/** Constructs the data of a gdt_cct_NetworkConnectionInfo representing the client nework connection + * information. + * + * @return The data of a gdt_cct_NetworkConnectionInfo object. + */ +FOUNDATION_EXPORT +NSData *GDTCCTConstructNetworkConnectionInfoData(void); + +/** Return a gdt_cct_NetworkConnectionInfo_MobileSubtype representing the client + * + * @return The gdt_cct_NetworkConnectionInfo_MobileSubtype. + */ +FOUNDATION_EXPORT +gdt_cct_NetworkConnectionInfo_MobileSubtype GDTCCTNetworkConnectionInfoNetworkMobileSubtype(void); + +#pragma mark - CCT object decoders + +/** Decodes a gdt_cct_LogResponse given proto bytes. + * + * @note calloc is called in this method. Ensure that pb_release is called on the return value. + * + * @param data The proto bytes of the gdt_cct_LogResponse. + * @param error An error that will be populated if something went wrong during decoding. + * @return A newly allocated gdt_cct_LogResponse from the data, if the bytes decoded properly. + */ +FOUNDATION_EXPORT +gdt_cct_LogResponse GDTCCTDecodeLogResponse(NSData *data, NSError **error); + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h new file mode 100644 index 0000000..30ec203 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTURLSessionDataResponse.h @@ -0,0 +1,29 @@ +// Copyright 2024 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** The class represents HTTP response received from `NSURLSession`. */ +@interface GDTCCTURLSessionDataResponse : NSObject + +@property(nonatomic, readonly) NSHTTPURLResponse *HTTPResponse; +@property(nonatomic, nullable, readonly) NSData *HTTPBody; + +- (instancetype)initWithResponse:(NSHTTPURLResponse *)response HTTPBody:(nullable NSData *)body; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h new file mode 100644 index 0000000..cfc2c48 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploadOperation.h @@ -0,0 +1,78 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +@protocol GDTCORStoragePromiseProtocol; +@protocol GDTCORMetricsControllerProtocol; + +NS_ASSUME_NONNULL_BEGIN + +/// The protocol defines methods to retrieve/update data shared between different upload operations. +@protocol GDTCCTUploadMetadataProvider + +/** Returns a GDTCORClock object representing time after which a next upload attempt is allowed for + * the specified target. Upload is allowed now if `nil`. */ +- (nullable GDTCORClock *)nextUploadTimeForTarget:(GDTCORTarget)target; + +/** Stores or resets time after which a next upload attempt is allowed for the specified target. */ +- (void)setNextUploadTime:(nullable GDTCORClock *)time forTarget:(GDTCORTarget)target; + +/** Returns an API key for the specified target. */ +- (nullable NSString *)APIKeyForTarget:(GDTCORTarget)target; + +@end + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploadOperation : NSOperation + +- (instancetype)init NS_UNAVAILABLE; + +/// Designated initializer. +/// @param target The events target to upload. +/// @param conditions A set of upload conditions. The conditions affect the set of events to be +/// uploaded, e.g. events with some QoS are not uploaded on a cellular network, etc. +/// @param uploadURL The backend URL to upload the events. +/// @param queue A queue to dispatch async upload steps. +/// @param storage A storage object to fetch events for upload. +/// @param metadataProvider An object to retrieve/update data shared between upload operations. +/// @param metricsController The metrics controller corresponding to the given target. If the given +/// target does not support metrics controller, `nil` should be passed. +/// @return An individual operation that can be added to an operation queue. +- (instancetype)initWithTarget:(GDTCORTarget)target + conditions:(GDTCORUploadConditions)conditions + uploadURL:(NSURL *)uploadURL + queue:(dispatch_queue_t)queue + storage:(id)storage + metadataProvider:(id)metadataProvider + metricsController:(nullable id)metricsController + NS_DESIGNATED_INITIALIZER; + +/** YES if a batch upload attempt was performed. NO otherwise. If NO for the finished operation, + * then there were no events suitable for upload. */ +@property(nonatomic, readonly) BOOL uploadAttempted; + +/** The queue on which all CCT uploading will occur. */ +@property(nonatomic, readonly) dispatch_queue_t uploaderQueue; + +/** The current upload task. */ +@property(nullable, nonatomic, readonly) NSURLSessionUploadTask *currentTask; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h new file mode 100644 index 0000000..36934c6 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCCTUploader.h @@ -0,0 +1,45 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Class capable of uploading events to the CCT backend. */ +@interface GDTCCTUploader : NSObject + +/** Creates and/or returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +#if GDT_TEST +/** An upload URL used across all targets. For testing only. */ +@property(class, nullable, nonatomic) NSURL *testServerURL; + +/** Spins runloop until upload finishes or timeout. + * @return YES if upload finishes, NO in the case of timeout. + */ +- (BOOL)waitForUploadFinishedWithTimeout:(NSTimeInterval)timeout; + +#endif // GDT_TEST + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h new file mode 100644 index 0000000..84d36ae --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCOREvent+GDTMetricsSupport.h @@ -0,0 +1,34 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +@class GDTCORMetrics; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCOREvent (GDTMetricsSupport) + +/// Creates and returns an event for the given target with the given metrics. +/// @param metrics The metrics to set at the event's data. +/// @param target The backend target that the event corresponds to. ++ (GDTCOREvent *)eventWithMetrics:(GDTCORMetrics *)metrics forTarget:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h new file mode 100644 index 0000000..8d1e696 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Private/GDTCORMetrics+GDTCCTSupport.h @@ -0,0 +1,25 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORMetrics (GDTCCTSupport) + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c new file mode 100644 index 0000000..8e5412e --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.c @@ -0,0 +1,138 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default = gdt_cct_NetworkConnectionInfo_NetworkType_NONE; +const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default = gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE; +const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default = gdt_cct_QosTierConfiguration_QosTier_DEFAULT; +const int32_t gdt_cct_QosTierConfiguration_log_source_default = 0; + + +const pb_field_t gdt_cct_LogEvent_fields[8] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogEvent, event_time_ms, event_time_ms, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_LogEvent, source_extension, event_time_ms, 0), + PB_FIELD( 11, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_code, source_extension, 0), + PB_FIELD( 15, SINT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, timezone_offset_seconds, event_code, 0), + PB_FIELD( 17, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, event_uptime_ms, timezone_offset_seconds, 0), + PB_FIELD( 23, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, network_connection_info, event_uptime_ms, &gdt_cct_NetworkConnectionInfo_fields), + PB_FIELD( 33, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogEvent, compliance_data, network_connection_info, &gdt_cct_ComplianceData_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3] = { + PB_FIELD( 1, ENUM , OPTIONAL, STATIC , FIRST, gdt_cct_NetworkConnectionInfo, network_type, network_type, &gdt_cct_NetworkConnectionInfo_network_type_default), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_NetworkConnectionInfo, mobile_subtype, network_type, &gdt_cct_NetworkConnectionInfo_mobile_subtype_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_MacClientInfo_fields[5] = { + PB_FIELD( 1, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_MacClientInfo, os_major_version, os_major_version, 0), + PB_FIELD( 2, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, os_full_version, os_major_version, 0), + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, application_build, os_full_version, 0), + PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_MacClientInfo, application_bundle_id, application_build, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_IosClientInfo_fields[8] = { + PB_FIELD( 3, BYTES , OPTIONAL, POINTER , FIRST, gdt_cct_IosClientInfo, os_major_version, os_major_version, 0), + PB_FIELD( 4, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, os_full_version, os_major_version, 0), + PB_FIELD( 5, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_build, os_full_version, 0), + PB_FIELD( 6, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, country, application_build, 0), + PB_FIELD( 7, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, model, country, 0), + PB_FIELD( 8, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, language_code, model, 0), + PB_FIELD( 11, BYTES , OPTIONAL, POINTER , OTHER, gdt_cct_IosClientInfo, application_bundle_id, language_code, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_ClientInfo_fields[4] = { + PB_FIELD( 1, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_ClientInfo, client_type, client_type, 0), + PB_FIELD( 4, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, ios_client_info, client_type, &gdt_cct_IosClientInfo_fields), + PB_FIELD( 13, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_ClientInfo, mac_client_info, ios_client_info, &gdt_cct_MacClientInfo_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_BatchedLogRequest_fields[2] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_BatchedLogRequest, log_request, log_request, &gdt_cct_LogRequest_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogRequest_fields[7] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_LogRequest, client_info, client_info, &gdt_cct_ClientInfo_fields), + PB_FIELD( 2, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, log_source, client_info, 0), + PB_FIELD( 3, MESSAGE , REPEATED, POINTER , OTHER, gdt_cct_LogRequest, log_event, log_source, &gdt_cct_LogEvent_fields), + PB_FIELD( 4, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_time_ms, log_event, 0), + PB_FIELD( 8, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, request_uptime_ms, request_time_ms, 0), + PB_FIELD( 9, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_LogRequest, qos_tier, request_uptime_ms, &gdt_cct_LogRequest_qos_tier_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTierConfiguration_fields[3] = { + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , FIRST, gdt_cct_QosTierConfiguration, qos_tier, qos_tier, 0), + PB_FIELD( 3, INT32 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTierConfiguration, log_source, qos_tier, &gdt_cct_QosTierConfiguration_log_source_default), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_QosTiersOverride_fields[3] = { + PB_FIELD( 1, MESSAGE , REPEATED, POINTER , FIRST, gdt_cct_QosTiersOverride, qos_tier_configuration, qos_tier_configuration, &gdt_cct_QosTierConfiguration_fields), + PB_FIELD( 2, INT64 , OPTIONAL, STATIC , OTHER, gdt_cct_QosTiersOverride, qos_tier_fingerprint, qos_tier_configuration, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_cct_LogResponse_fields[3] = { + PB_FIELD( 1, INT64 , OPTIONAL, STATIC , FIRST, gdt_cct_LogResponse, next_request_wait_millis, next_request_wait_millis, 0), + PB_FIELD( 3, MESSAGE , OPTIONAL, STATIC , OTHER, gdt_cct_LogResponse, qos_tier, next_request_wait_millis, &gdt_cct_QosTiersOverride_fields), + PB_LAST_FIELD +}; + + + + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 65536 && pb_membersize(gdt_cct_LogEvent, compliance_data) < 65536 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 65536 && pb_membersize(gdt_cct_ClientInfo, mac_client_info) < 65536 && pb_membersize(gdt_cct_LogRequest, client_info) < 65536 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_MacClientInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_LogEvent, network_connection_info) < 256 && pb_membersize(gdt_cct_LogEvent, compliance_data) < 256 && pb_membersize(gdt_cct_ClientInfo, ios_client_info) < 256 && pb_membersize(gdt_cct_ClientInfo, mac_client_info) < 256 && pb_membersize(gdt_cct_LogRequest, client_info) < 256 && pb_membersize(gdt_cct_LogResponse, qos_tier) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_LogEvent_gdt_cct_NetworkConnectionInfo_gdt_cct_MacClientInfo_gdt_cct_IosClientInfo_gdt_cct_ClientInfo_gdt_cct_BatchedLogRequest_gdt_cct_LogRequest_gdt_cct_QosTierConfiguration_gdt_cct_QosTiersOverride_gdt_cct_LogResponse) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h new file mode 100644 index 0000000..a13a16c --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h @@ -0,0 +1,305 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#define PB_GDT_CCT_CCT_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_cct_NetworkConnectionInfo_NetworkType { + gdt_cct_NetworkConnectionInfo_NetworkType_NONE = -1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE = 0, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI = 1, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_MMS = 2, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_SUPL = 3, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_DUN = 4, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_HIPRI = 5, + gdt_cct_NetworkConnectionInfo_NetworkType_WIMAX = 6, + gdt_cct_NetworkConnectionInfo_NetworkType_BLUETOOTH = 7, + gdt_cct_NetworkConnectionInfo_NetworkType_DUMMY = 8, + gdt_cct_NetworkConnectionInfo_NetworkType_ETHERNET = 9, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_FOTA = 10, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IMS = 11, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_CBS = 12, + gdt_cct_NetworkConnectionInfo_NetworkType_WIFI_P2P = 13, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_IA = 14, + gdt_cct_NetworkConnectionInfo_NetworkType_MOBILE_EMERGENCY = 15, + gdt_cct_NetworkConnectionInfo_NetworkType_PROXY = 16, + gdt_cct_NetworkConnectionInfo_NetworkType_VPN = 17 +} gdt_cct_NetworkConnectionInfo_NetworkType; +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MIN gdt_cct_NetworkConnectionInfo_NetworkType_NONE +#define _gdt_cct_NetworkConnectionInfo_NetworkType_MAX gdt_cct_NetworkConnectionInfo_NetworkType_VPN +#define _gdt_cct_NetworkConnectionInfo_NetworkType_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_NetworkType)(gdt_cct_NetworkConnectionInfo_NetworkType_VPN+1)) + +typedef enum _gdt_cct_NetworkConnectionInfo_MobileSubtype { + gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE = 0, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GPRS = 1, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EDGE = 2, + gdt_cct_NetworkConnectionInfo_MobileSubtype_UMTS = 3, + gdt_cct_NetworkConnectionInfo_MobileSubtype_CDMA = 4, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_0 = 5, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_A = 6, + gdt_cct_NetworkConnectionInfo_MobileSubtype_RTT = 7, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSDPA = 8, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSUPA = 9, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPA = 10, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IDEN = 11, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EVDO_B = 12, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE = 13, + gdt_cct_NetworkConnectionInfo_MobileSubtype_EHRPD = 14, + gdt_cct_NetworkConnectionInfo_MobileSubtype_HSPAP = 15, + gdt_cct_NetworkConnectionInfo_MobileSubtype_GSM = 16, + gdt_cct_NetworkConnectionInfo_MobileSubtype_TD_SCDMA = 17, + gdt_cct_NetworkConnectionInfo_MobileSubtype_IWLAN = 18, + gdt_cct_NetworkConnectionInfo_MobileSubtype_LTE_CA = 19, + gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED = 100 +} gdt_cct_NetworkConnectionInfo_MobileSubtype; +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_MAX gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED +#define _gdt_cct_NetworkConnectionInfo_MobileSubtype_ARRAYSIZE ((gdt_cct_NetworkConnectionInfo_MobileSubtype)(gdt_cct_NetworkConnectionInfo_MobileSubtype_COMBINED+1)) + +typedef enum _gdt_cct_ClientInfo_ClientType { + gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN = 0, + gdt_cct_ClientInfo_ClientType_IOS_FIREBASE = 15 +} gdt_cct_ClientInfo_ClientType; +#define _gdt_cct_ClientInfo_ClientType_MIN gdt_cct_ClientInfo_ClientType_CLIENT_UNKNOWN +#define _gdt_cct_ClientInfo_ClientType_MAX gdt_cct_ClientInfo_ClientType_IOS_FIREBASE +#define _gdt_cct_ClientInfo_ClientType_ARRAYSIZE ((gdt_cct_ClientInfo_ClientType)(gdt_cct_ClientInfo_ClientType_IOS_FIREBASE+1)) + +typedef enum _gdt_cct_QosTierConfiguration_QosTier { + gdt_cct_QosTierConfiguration_QosTier_DEFAULT = 0, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_ONLY = 1, + gdt_cct_QosTierConfiguration_QosTier_UNMETERED_OR_DAILY = 2, + gdt_cct_QosTierConfiguration_QosTier_FAST_IF_RADIO_AWAKE = 3, + gdt_cct_QosTierConfiguration_QosTier_NEVER = 4 +} gdt_cct_QosTierConfiguration_QosTier; +#define _gdt_cct_QosTierConfiguration_QosTier_MIN gdt_cct_QosTierConfiguration_QosTier_DEFAULT +#define _gdt_cct_QosTierConfiguration_QosTier_MAX gdt_cct_QosTierConfiguration_QosTier_NEVER +#define _gdt_cct_QosTierConfiguration_QosTier_ARRAYSIZE ((gdt_cct_QosTierConfiguration_QosTier)(gdt_cct_QosTierConfiguration_QosTier_NEVER+1)) + +/* Struct definitions */ +typedef struct _gdt_cct_BatchedLogRequest { + pb_size_t log_request_count; + struct _gdt_cct_LogRequest *log_request; +/* @@protoc_insertion_point(struct:gdt_cct_BatchedLogRequest) */ +} gdt_cct_BatchedLogRequest; + +typedef struct _gdt_cct_IosClientInfo { + pb_bytes_array_t *os_major_version; + pb_bytes_array_t *os_full_version; + pb_bytes_array_t *application_build; + pb_bytes_array_t *country; + pb_bytes_array_t *model; + pb_bytes_array_t *language_code; + pb_bytes_array_t *application_bundle_id; +/* @@protoc_insertion_point(struct:gdt_cct_IosClientInfo) */ +} gdt_cct_IosClientInfo; + +typedef struct _gdt_cct_MacClientInfo { + pb_bytes_array_t *os_major_version; + pb_bytes_array_t *os_full_version; + pb_bytes_array_t *application_build; + pb_bytes_array_t *application_bundle_id; +/* @@protoc_insertion_point(struct:gdt_cct_MacClientInfo) */ +} gdt_cct_MacClientInfo; + +typedef struct _gdt_cct_ClientInfo { + bool has_client_type; + gdt_cct_ClientInfo_ClientType client_type; + bool has_ios_client_info; + gdt_cct_IosClientInfo ios_client_info; + bool has_mac_client_info; + gdt_cct_MacClientInfo mac_client_info; +/* @@protoc_insertion_point(struct:gdt_cct_ClientInfo) */ +} gdt_cct_ClientInfo; + +typedef struct _gdt_cct_NetworkConnectionInfo { + bool has_network_type; + gdt_cct_NetworkConnectionInfo_NetworkType network_type; + bool has_mobile_subtype; + gdt_cct_NetworkConnectionInfo_MobileSubtype mobile_subtype; +/* @@protoc_insertion_point(struct:gdt_cct_NetworkConnectionInfo) */ +} gdt_cct_NetworkConnectionInfo; + +typedef struct _gdt_cct_QosTierConfiguration { + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; + bool has_log_source; + int32_t log_source; +/* @@protoc_insertion_point(struct:gdt_cct_QosTierConfiguration) */ +} gdt_cct_QosTierConfiguration; + +typedef struct _gdt_cct_QosTiersOverride { + pb_size_t qos_tier_configuration_count; + struct _gdt_cct_QosTierConfiguration *qos_tier_configuration; + bool has_qos_tier_fingerprint; + int64_t qos_tier_fingerprint; +/* @@protoc_insertion_point(struct:gdt_cct_QosTiersOverride) */ +} gdt_cct_QosTiersOverride; + +typedef struct _gdt_cct_LogEvent { + bool has_event_time_ms; + int64_t event_time_ms; + pb_bytes_array_t *source_extension; + bool has_event_code; + int32_t event_code; + bool has_timezone_offset_seconds; + int64_t timezone_offset_seconds; + bool has_event_uptime_ms; + int64_t event_uptime_ms; + bool has_network_connection_info; + gdt_cct_NetworkConnectionInfo network_connection_info; + bool has_compliance_data; + gdt_cct_ComplianceData compliance_data; +/* @@protoc_insertion_point(struct:gdt_cct_LogEvent) */ +} gdt_cct_LogEvent; + +typedef struct _gdt_cct_LogRequest { + bool has_client_info; + gdt_cct_ClientInfo client_info; + bool has_log_source; + int32_t log_source; + pb_size_t log_event_count; + struct _gdt_cct_LogEvent *log_event; + bool has_request_time_ms; + int64_t request_time_ms; + bool has_request_uptime_ms; + int64_t request_uptime_ms; + bool has_qos_tier; + gdt_cct_QosTierConfiguration_QosTier qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogRequest) */ +} gdt_cct_LogRequest; + +typedef struct _gdt_cct_LogResponse { + bool has_next_request_wait_millis; + int64_t next_request_wait_millis; + bool has_qos_tier; + gdt_cct_QosTiersOverride qos_tier; +/* @@protoc_insertion_point(struct:gdt_cct_LogResponse) */ +} gdt_cct_LogResponse; + +/* Default values for struct fields */ +extern const gdt_cct_NetworkConnectionInfo_NetworkType gdt_cct_NetworkConnectionInfo_network_type_default; +extern const gdt_cct_NetworkConnectionInfo_MobileSubtype gdt_cct_NetworkConnectionInfo_mobile_subtype_default; +extern const gdt_cct_QosTierConfiguration_QosTier gdt_cct_LogRequest_qos_tier_default; +extern const int32_t gdt_cct_QosTierConfiguration_log_source_default; + +/* Initializer values for message structs */ +#define gdt_cct_LogEvent_init_default {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_default, false, gdt_cct_ComplianceData_init_default} +#define gdt_cct_NetworkConnectionInfo_init_default {false, gdt_cct_NetworkConnectionInfo_NetworkType_NONE, false, gdt_cct_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE} +#define gdt_cct_MacClientInfo_init_default {NULL, NULL, NULL, NULL} +#define gdt_cct_IosClientInfo_init_default {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_default {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_default, false, gdt_cct_MacClientInfo_init_default} +#define gdt_cct_BatchedLogRequest_init_default {0, NULL} +#define gdt_cct_LogRequest_init_default {false, gdt_cct_ClientInfo_init_default, false, 0, 0, NULL, false, 0, false, 0, false, gdt_cct_QosTierConfiguration_QosTier_DEFAULT} +#define gdt_cct_QosTierConfiguration_init_default {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_default {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_default {false, 0, false, gdt_cct_QosTiersOverride_init_default} +#define gdt_cct_LogEvent_init_zero {false, 0, NULL, false, 0, false, 0, false, 0, false, gdt_cct_NetworkConnectionInfo_init_zero, false, gdt_cct_ComplianceData_init_zero} +#define gdt_cct_NetworkConnectionInfo_init_zero {false, _gdt_cct_NetworkConnectionInfo_NetworkType_MIN, false, _gdt_cct_NetworkConnectionInfo_MobileSubtype_MIN} +#define gdt_cct_MacClientInfo_init_zero {NULL, NULL, NULL, NULL} +#define gdt_cct_IosClientInfo_init_zero {NULL, NULL, NULL, NULL, NULL, NULL, NULL} +#define gdt_cct_ClientInfo_init_zero {false, _gdt_cct_ClientInfo_ClientType_MIN, false, gdt_cct_IosClientInfo_init_zero, false, gdt_cct_MacClientInfo_init_zero} +#define gdt_cct_BatchedLogRequest_init_zero {0, NULL} +#define gdt_cct_LogRequest_init_zero {false, gdt_cct_ClientInfo_init_zero, false, 0, 0, NULL, false, 0, false, 0, false, _gdt_cct_QosTierConfiguration_QosTier_MIN} +#define gdt_cct_QosTierConfiguration_init_zero {false, _gdt_cct_QosTierConfiguration_QosTier_MIN, false, 0} +#define gdt_cct_QosTiersOverride_init_zero {0, NULL, false, 0} +#define gdt_cct_LogResponse_init_zero {false, 0, false, gdt_cct_QosTiersOverride_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_cct_BatchedLogRequest_log_request_tag 1 +#define gdt_cct_IosClientInfo_os_major_version_tag 3 +#define gdt_cct_IosClientInfo_os_full_version_tag 4 +#define gdt_cct_IosClientInfo_application_build_tag 5 +#define gdt_cct_IosClientInfo_country_tag 6 +#define gdt_cct_IosClientInfo_model_tag 7 +#define gdt_cct_IosClientInfo_language_code_tag 8 +#define gdt_cct_IosClientInfo_application_bundle_id_tag 11 +#define gdt_cct_MacClientInfo_os_major_version_tag 1 +#define gdt_cct_MacClientInfo_os_full_version_tag 2 +#define gdt_cct_MacClientInfo_application_build_tag 3 +#define gdt_cct_MacClientInfo_application_bundle_id_tag 7 +#define gdt_cct_ClientInfo_client_type_tag 1 +#define gdt_cct_ClientInfo_ios_client_info_tag 4 +#define gdt_cct_ClientInfo_mac_client_info_tag 13 +#define gdt_cct_NetworkConnectionInfo_network_type_tag 1 +#define gdt_cct_NetworkConnectionInfo_mobile_subtype_tag 2 +#define gdt_cct_QosTierConfiguration_qos_tier_tag 2 +#define gdt_cct_QosTierConfiguration_log_source_tag 3 +#define gdt_cct_QosTiersOverride_qos_tier_configuration_tag 1 +#define gdt_cct_QosTiersOverride_qos_tier_fingerprint_tag 2 +#define gdt_cct_LogEvent_event_time_ms_tag 1 +#define gdt_cct_LogEvent_event_code_tag 11 +#define gdt_cct_LogEvent_event_uptime_ms_tag 17 +#define gdt_cct_LogEvent_source_extension_tag 6 +#define gdt_cct_LogEvent_timezone_offset_seconds_tag 15 +#define gdt_cct_LogEvent_network_connection_info_tag 23 +#define gdt_cct_LogEvent_compliance_data_tag 33 +#define gdt_cct_LogRequest_request_time_ms_tag 4 +#define gdt_cct_LogRequest_request_uptime_ms_tag 8 +#define gdt_cct_LogRequest_client_info_tag 1 +#define gdt_cct_LogRequest_log_source_tag 2 +#define gdt_cct_LogRequest_log_event_tag 3 +#define gdt_cct_LogRequest_qos_tier_tag 9 +#define gdt_cct_LogResponse_next_request_wait_millis_tag 1 +#define gdt_cct_LogResponse_qos_tier_tag 3 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_cct_LogEvent_fields[8]; +extern const pb_field_t gdt_cct_NetworkConnectionInfo_fields[3]; +extern const pb_field_t gdt_cct_MacClientInfo_fields[5]; +extern const pb_field_t gdt_cct_IosClientInfo_fields[8]; +extern const pb_field_t gdt_cct_ClientInfo_fields[4]; +extern const pb_field_t gdt_cct_BatchedLogRequest_fields[2]; +extern const pb_field_t gdt_cct_LogRequest_fields[7]; +extern const pb_field_t gdt_cct_QosTierConfiguration_fields[3]; +extern const pb_field_t gdt_cct_QosTiersOverride_fields[3]; +extern const pb_field_t gdt_cct_LogResponse_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* gdt_cct_LogEvent_size depends on runtime parameters */ +#define gdt_cct_NetworkConnectionInfo_size 13 +/* gdt_cct_MacClientInfo_size depends on runtime parameters */ +/* gdt_cct_IosClientInfo_size depends on runtime parameters */ +/* gdt_cct_ClientInfo_size depends on runtime parameters */ +/* gdt_cct_BatchedLogRequest_size depends on runtime parameters */ +/* gdt_cct_LogRequest_size depends on runtime parameters */ +#define gdt_cct_QosTierConfiguration_size 13 +/* gdt_cct_QosTiersOverride_size depends on runtime parameters */ +/* gdt_cct_LogResponse_size depends on runtime parameters */ + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CCT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c new file mode 100644 index 0000000..1e95954 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.c @@ -0,0 +1,92 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t gdt_client_metrics_ClientMetrics_fields[5] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, gdt_client_metrics_ClientMetrics, window, window, &gdt_client_metrics_TimeWindow_fields), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, gdt_client_metrics_ClientMetrics, log_source_metrics, window, &gdt_client_metrics_LogSourceMetrics_fields), + PB_FIELD( 3, MESSAGE , SINGULAR, STATIC , OTHER, gdt_client_metrics_ClientMetrics, global_metrics, log_source_metrics, &gdt_client_metrics_GlobalMetrics_fields), + PB_FIELD( 4, BYTES , SINGULAR, POINTER , OTHER, gdt_client_metrics_ClientMetrics, app_namespace, global_metrics, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_TimeWindow_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_TimeWindow, start_ms, start_ms, 0), + PB_FIELD( 2, INT64 , SINGULAR, STATIC , OTHER, gdt_client_metrics_TimeWindow, end_ms, start_ms, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_GlobalMetrics_fields[2] = { + PB_FIELD( 1, MESSAGE , SINGULAR, STATIC , FIRST, gdt_client_metrics_GlobalMetrics, storage_metrics, storage_metrics, &gdt_client_metrics_StorageMetrics_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_StorageMetrics_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_StorageMetrics, current_cache_size_bytes, current_cache_size_bytes, 0), + PB_FIELD( 2, INT64 , SINGULAR, STATIC , OTHER, gdt_client_metrics_StorageMetrics, max_cache_size_bytes, current_cache_size_bytes, 0), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_LogSourceMetrics_fields[3] = { + PB_FIELD( 1, BYTES , SINGULAR, POINTER , FIRST, gdt_client_metrics_LogSourceMetrics, log_source, log_source, 0), + PB_FIELD( 2, MESSAGE , REPEATED, POINTER , OTHER, gdt_client_metrics_LogSourceMetrics, log_event_dropped, log_source, &gdt_client_metrics_LogEventDropped_fields), + PB_LAST_FIELD +}; + +const pb_field_t gdt_client_metrics_LogEventDropped_fields[3] = { + PB_FIELD( 1, INT64 , SINGULAR, STATIC , FIRST, gdt_client_metrics_LogEventDropped, events_dropped_count, events_dropped_count, 0), + PB_FIELD( 3, UENUM , SINGULAR, STATIC , OTHER, gdt_client_metrics_LogEventDropped, reason, events_dropped_count, 0), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_client_metrics_ClientMetrics, window) < 65536 && pb_membersize(gdt_client_metrics_ClientMetrics, global_metrics) < 65536 && pb_membersize(gdt_client_metrics_GlobalMetrics, storage_metrics) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_client_metrics_ClientMetrics_gdt_client_metrics_TimeWindow_gdt_client_metrics_GlobalMetrics_gdt_client_metrics_StorageMetrics_gdt_client_metrics_LogSourceMetrics_gdt_client_metrics_LogEventDropped) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_client_metrics_ClientMetrics, window) < 256 && pb_membersize(gdt_client_metrics_ClientMetrics, global_metrics) < 256 && pb_membersize(gdt_client_metrics_GlobalMetrics, storage_metrics) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_client_metrics_ClientMetrics_gdt_client_metrics_TimeWindow_gdt_client_metrics_GlobalMetrics_gdt_client_metrics_StorageMetrics_gdt_client_metrics_LogSourceMetrics_gdt_client_metrics_LogEventDropped) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h new file mode 100644 index 0000000..c4d7686 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/client_metrics.nanopb.h @@ -0,0 +1,141 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CLIENT_METRICS_CLIENT_METRICS_NANOPB_H_INCLUDED +#define PB_GDT_CLIENT_METRICS_CLIENT_METRICS_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_client_metrics_LogEventDropped_Reason { + gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN = 0, + gdt_client_metrics_LogEventDropped_Reason_MESSAGE_TOO_OLD = 1, + gdt_client_metrics_LogEventDropped_Reason_CACHE_FULL = 2, + gdt_client_metrics_LogEventDropped_Reason_PAYLOAD_TOO_BIG = 3, + gdt_client_metrics_LogEventDropped_Reason_MAX_RETRIES_REACHED = 4, + gdt_client_metrics_LogEventDropped_Reason_INVALID_PAYLOD = 5, + gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR = 6 +} gdt_client_metrics_LogEventDropped_Reason; +#define _gdt_client_metrics_LogEventDropped_Reason_MIN gdt_client_metrics_LogEventDropped_Reason_REASON_UNKNOWN +#define _gdt_client_metrics_LogEventDropped_Reason_MAX gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR +#define _gdt_client_metrics_LogEventDropped_Reason_ARRAYSIZE ((gdt_client_metrics_LogEventDropped_Reason)(gdt_client_metrics_LogEventDropped_Reason_SERVER_ERROR+1)) + +/* Struct definitions */ +typedef struct _gdt_client_metrics_LogSourceMetrics { + pb_bytes_array_t *log_source; + pb_size_t log_event_dropped_count; + struct _gdt_client_metrics_LogEventDropped *log_event_dropped; +/* @@protoc_insertion_point(struct:gdt_client_metrics_LogSourceMetrics) */ +} gdt_client_metrics_LogSourceMetrics; + +typedef struct _gdt_client_metrics_LogEventDropped { + int64_t events_dropped_count; + gdt_client_metrics_LogEventDropped_Reason reason; +/* @@protoc_insertion_point(struct:gdt_client_metrics_LogEventDropped) */ +} gdt_client_metrics_LogEventDropped; + +typedef struct _gdt_client_metrics_StorageMetrics { + int64_t current_cache_size_bytes; + int64_t max_cache_size_bytes; +/* @@protoc_insertion_point(struct:gdt_client_metrics_StorageMetrics) */ +} gdt_client_metrics_StorageMetrics; + +typedef struct _gdt_client_metrics_TimeWindow { + int64_t start_ms; + int64_t end_ms; +/* @@protoc_insertion_point(struct:gdt_client_metrics_TimeWindow) */ +} gdt_client_metrics_TimeWindow; + +typedef struct _gdt_client_metrics_GlobalMetrics { + gdt_client_metrics_StorageMetrics storage_metrics; +/* @@protoc_insertion_point(struct:gdt_client_metrics_GlobalMetrics) */ +} gdt_client_metrics_GlobalMetrics; + +typedef struct _gdt_client_metrics_ClientMetrics { + gdt_client_metrics_TimeWindow window; + pb_size_t log_source_metrics_count; + struct _gdt_client_metrics_LogSourceMetrics *log_source_metrics; + gdt_client_metrics_GlobalMetrics global_metrics; + pb_bytes_array_t *app_namespace; +/* @@protoc_insertion_point(struct:gdt_client_metrics_ClientMetrics) */ +} gdt_client_metrics_ClientMetrics; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define gdt_client_metrics_ClientMetrics_init_default {gdt_client_metrics_TimeWindow_init_default, 0, NULL, gdt_client_metrics_GlobalMetrics_init_default, NULL} +#define gdt_client_metrics_TimeWindow_init_default {0, 0} +#define gdt_client_metrics_GlobalMetrics_init_default {gdt_client_metrics_StorageMetrics_init_default} +#define gdt_client_metrics_StorageMetrics_init_default {0, 0} +#define gdt_client_metrics_LogSourceMetrics_init_default {NULL, 0, NULL} +#define gdt_client_metrics_LogEventDropped_init_default {0, _gdt_client_metrics_LogEventDropped_Reason_MIN} +#define gdt_client_metrics_ClientMetrics_init_zero {gdt_client_metrics_TimeWindow_init_zero, 0, NULL, gdt_client_metrics_GlobalMetrics_init_zero, NULL} +#define gdt_client_metrics_TimeWindow_init_zero {0, 0} +#define gdt_client_metrics_GlobalMetrics_init_zero {gdt_client_metrics_StorageMetrics_init_zero} +#define gdt_client_metrics_StorageMetrics_init_zero {0, 0} +#define gdt_client_metrics_LogSourceMetrics_init_zero {NULL, 0, NULL} +#define gdt_client_metrics_LogEventDropped_init_zero {0, _gdt_client_metrics_LogEventDropped_Reason_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_client_metrics_LogSourceMetrics_log_source_tag 1 +#define gdt_client_metrics_LogSourceMetrics_log_event_dropped_tag 2 +#define gdt_client_metrics_LogEventDropped_events_dropped_count_tag 1 +#define gdt_client_metrics_LogEventDropped_reason_tag 3 +#define gdt_client_metrics_StorageMetrics_current_cache_size_bytes_tag 1 +#define gdt_client_metrics_StorageMetrics_max_cache_size_bytes_tag 2 +#define gdt_client_metrics_TimeWindow_start_ms_tag 1 +#define gdt_client_metrics_TimeWindow_end_ms_tag 2 +#define gdt_client_metrics_GlobalMetrics_storage_metrics_tag 1 +#define gdt_client_metrics_ClientMetrics_window_tag 1 +#define gdt_client_metrics_ClientMetrics_log_source_metrics_tag 2 +#define gdt_client_metrics_ClientMetrics_global_metrics_tag 3 +#define gdt_client_metrics_ClientMetrics_app_namespace_tag 4 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_client_metrics_ClientMetrics_fields[5]; +extern const pb_field_t gdt_client_metrics_TimeWindow_fields[3]; +extern const pb_field_t gdt_client_metrics_GlobalMetrics_fields[2]; +extern const pb_field_t gdt_client_metrics_StorageMetrics_fields[3]; +extern const pb_field_t gdt_client_metrics_LogSourceMetrics_fields[3]; +extern const pb_field_t gdt_client_metrics_LogEventDropped_fields[3]; + +/* Maximum encoded size of messages (where known) */ +/* gdt_client_metrics_ClientMetrics_size depends on runtime parameters */ +#define gdt_client_metrics_TimeWindow_size 22 +#define gdt_client_metrics_GlobalMetrics_size 24 +#define gdt_client_metrics_StorageMetrics_size 22 +/* gdt_client_metrics_LogSourceMetrics_size depends on runtime parameters */ +#define gdt_client_metrics_LogEventDropped_size 13 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define CLIENT_METRICS_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c new file mode 100644 index 0000000..f3552f7 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.c @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + +const gdt_cct_ComplianceData_ProductIdOrigin gdt_cct_ComplianceData_product_id_origin_default = gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET; + + +const pb_field_t gdt_cct_ComplianceData_fields[3] = { + PB_FIELD( 1, MESSAGE , OPTIONAL, STATIC , FIRST, gdt_cct_ComplianceData, privacy_context, privacy_context, &privacy_context_external_ExternalPrivacyContext_fields), + PB_FIELD( 2, UENUM , OPTIONAL, STATIC , OTHER, gdt_cct_ComplianceData, product_id_origin, privacy_context, &gdt_cct_ComplianceData_product_id_origin_default), + PB_LAST_FIELD +}; + + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_ComplianceData, privacy_context) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_gdt_cct_ComplianceData) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(gdt_cct_ComplianceData, privacy_context) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_gdt_cct_ComplianceData) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h new file mode 100644 index 0000000..a143c76 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/compliance.nanopb.h @@ -0,0 +1,77 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_GDT_CCT_COMPLIANCE_NANOPB_H_INCLUDED +#define PB_GDT_CCT_COMPLIANCE_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Enum definitions */ +typedef enum _gdt_cct_ComplianceData_ProductIdOrigin { + gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET = 0, + gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE = 5 +} gdt_cct_ComplianceData_ProductIdOrigin; +#define _gdt_cct_ComplianceData_ProductIdOrigin_MIN gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET +#define _gdt_cct_ComplianceData_ProductIdOrigin_MAX gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE +#define _gdt_cct_ComplianceData_ProductIdOrigin_ARRAYSIZE ((gdt_cct_ComplianceData_ProductIdOrigin)(gdt_cct_ComplianceData_ProductIdOrigin_EVENT_OVERRIDE+1)) + +/* Struct definitions */ +typedef struct _gdt_cct_ComplianceData { + bool has_privacy_context; + privacy_context_external_ExternalPrivacyContext privacy_context; + bool has_product_id_origin; + gdt_cct_ComplianceData_ProductIdOrigin product_id_origin; +/* @@protoc_insertion_point(struct:gdt_cct_ComplianceData) */ +} gdt_cct_ComplianceData; + +/* Default values for struct fields */ +extern const gdt_cct_ComplianceData_ProductIdOrigin gdt_cct_ComplianceData_product_id_origin_default; + +/* Initializer values for message structs */ +#define gdt_cct_ComplianceData_init_default {false, privacy_context_external_ExternalPrivacyContext_init_default, false, gdt_cct_ComplianceData_ProductIdOrigin_NOT_SET} +#define gdt_cct_ComplianceData_init_zero {false, privacy_context_external_ExternalPrivacyContext_init_zero, false, _gdt_cct_ComplianceData_ProductIdOrigin_MIN} + +/* Field tags (for use in manual encoding/decoding) */ +#define gdt_cct_ComplianceData_privacy_context_tag 1 +#define gdt_cct_ComplianceData_product_id_origin_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t gdt_cct_ComplianceData_fields[3]; + +/* Maximum encoded size of messages (where known) */ +#define gdt_cct_ComplianceData_size (14 + privacy_context_external_ExternalPRequestContext_size) + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define COMPLIANCE_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c new file mode 100644 index 0000000..9eb1d16 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.c @@ -0,0 +1,35 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t privacy_context_external_ExternalPRequestContext_fields[2] = { + PB_FIELD( 13, INT32 , OPTIONAL, STATIC , FIRST, privacy_context_external_ExternalPRequestContext, origin_associated_product_id, origin_associated_product_id, 0), + PB_LAST_FIELD +}; + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h new file mode 100644 index 0000000..03f0f12 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h @@ -0,0 +1,62 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PREQUEST_CONTEXT_NANOPB_H_INCLUDED +#define PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PREQUEST_CONTEXT_NANOPB_H_INCLUDED +#include + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _privacy_context_external_ExternalPRequestContext { + bool has_origin_associated_product_id; + int32_t origin_associated_product_id; +/* @@protoc_insertion_point(struct:privacy_context_external_ExternalPRequestContext) */ +} privacy_context_external_ExternalPRequestContext; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define privacy_context_external_ExternalPRequestContext_init_default {false, 0} +#define privacy_context_external_ExternalPRequestContext_init_zero {false, 0} + +/* Field tags (for use in manual encoding/decoding) */ +#define privacy_context_external_ExternalPRequestContext_origin_associated_product_id_tag 13 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t privacy_context_external_ExternalPRequestContext_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define privacy_context_external_ExternalPRequestContext_size 11 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define EXTERNAL_PREQUEST_CONTEXT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c new file mode 100644 index 0000000..8b81605 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.c @@ -0,0 +1,59 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb constant definitions */ +/* Generated by nanopb-0.3.9.9 */ + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + + +const pb_field_t privacy_context_external_ExternalPrivacyContext_fields[2] = { + PB_FIELD( 2, MESSAGE , OPTIONAL, STATIC , FIRST, privacy_context_external_ExternalPrivacyContext, prequest, prequest, &privacy_context_external_ExternalPRequestContext_fields), + PB_LAST_FIELD +}; + + +/* Check that field information fits in pb_field_t */ +#if !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_32BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in 8 or 16 bit + * field descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(privacy_context_external_ExternalPrivacyContext, prequest) < 65536), YOU_MUST_DEFINE_PB_FIELD_32BIT_FOR_MESSAGES_privacy_context_external_ExternalPrivacyContext) +#endif + +#if !defined(PB_FIELD_16BIT) && !defined(PB_FIELD_32BIT) +/* If you get an error here, it means that you need to define PB_FIELD_16BIT + * compile-time option. You can do that in pb.h or on compiler command line. + * + * The reason you need to do this is that some of your messages contain tag + * numbers or field sizes that are larger than what can fit in the default + * 8 bit descriptors. + */ +PB_STATIC_ASSERT((pb_membersize(privacy_context_external_ExternalPrivacyContext, prequest) < 256), YOU_MUST_DEFINE_PB_FIELD_16BIT_FOR_MESSAGES_privacy_context_external_ExternalPrivacyContext) +#endif + + +/* @@protoc_insertion_point(eof) */ diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h new file mode 100644 index 0000000..dc6981a --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_privacy_context.nanopb.h @@ -0,0 +1,64 @@ +/* + * Copyright 2023 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Automatically generated nanopb header */ +/* Generated by nanopb-0.3.9.9 */ + +#ifndef PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PRIVACY_CONTEXT_NANOPB_H_INCLUDED +#define PB_PRIVACY_CONTEXT_EXTERNAL_EXTERNAL_PRIVACY_CONTEXT_NANOPB_H_INCLUDED +#include + +#include "GoogleDataTransport/GDTCCTLibrary/Protogen/nanopb/external_prequest_context.nanopb.h" + +/* @@protoc_insertion_point(includes) */ +#if PB_PROTO_HEADER_VERSION != 30 +#error Regenerate this file with the current version of nanopb generator. +#endif + + +/* Struct definitions */ +typedef struct _privacy_context_external_ExternalPrivacyContext { + bool has_prequest; + privacy_context_external_ExternalPRequestContext prequest; +/* @@protoc_insertion_point(struct:privacy_context_external_ExternalPrivacyContext) */ +} privacy_context_external_ExternalPrivacyContext; + +/* Default values for struct fields */ + +/* Initializer values for message structs */ +#define privacy_context_external_ExternalPrivacyContext_init_default {false, privacy_context_external_ExternalPRequestContext_init_default} +#define privacy_context_external_ExternalPrivacyContext_init_zero {false, privacy_context_external_ExternalPRequestContext_init_zero} + +/* Field tags (for use in manual encoding/decoding) */ +#define privacy_context_external_ExternalPrivacyContext_prequest_tag 2 + +/* Struct field encoding specification for nanopb */ +extern const pb_field_t privacy_context_external_ExternalPrivacyContext_fields[2]; + +/* Maximum encoded size of messages (where known) */ +#define privacy_context_external_ExternalPrivacyContext_size 13 + +/* Message IDs (where set with "msgid" option) */ +#ifdef PB_MSGID + +#define EXTERNAL_PRIVACY_CONTEXT_MESSAGES \ + + +#endif + +/* @@protoc_insertion_point(eof) */ + +#endif diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h new file mode 100644 index 0000000..295e6f8 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCCTLibrary/Public/GDTCOREvent+GDTCCTSupport.h @@ -0,0 +1,51 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A string sets in customBytes as a key paired to @YES if current event needs to + * populate network connection info data, @NO otherwise. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNeedsNetworkConnectionInfo; + +/** A string sets in customBytes as a key paired to the network connection info data + * of current event. + */ +FOUNDATION_EXPORT NSString *const GDTCCTNetworkConnectionInfo; + +/** A category that uses the customBytes property of a GDTCOREvent to store network connection info. + */ +@interface GDTCOREvent (GDTCCTSupport) + +/** If YES, needs the network connection info field set during prioritization. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nonatomic) BOOL needsNetworkConnectionInfoPopulated; + +/** The network connection info as collected at the time of the event. + * @note Uses the GDTCOREvent customBytes property. + */ +@property(nullable, nonatomic) NSData *networkConnectionInfoData; + +/** Code that identifies the event to be sent to the CCT backend. + */ +@property(nullable, nonatomic) NSNumber *eventCode; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m new file mode 100644 index 0000000..14462ae --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORAssert.m @@ -0,0 +1,36 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" + +GDTCORAssertionBlock GDTCORAssertionBlockToRunInstead(void) { + // This class is only compiled in by unit tests, and this should fail quickly in optimized builds. + Class GDTCORAssertClass = NSClassFromString(@"GDTCORAssertHelper"); + if (__builtin_expect(!!GDTCORAssertClass, 0)) { + SEL assertionBlockSEL = NSSelectorFromString(@"assertionBlock"); + if (assertionBlockSEL) { + IMP assertionBlockIMP = [GDTCORAssertClass methodForSelector:assertionBlockSEL]; + if (assertionBlockIMP) { + GDTCORAssertionBlock assertionBlock = ((GDTCORAssertionBlock(*)(id, SEL))assertionBlockIMP)( + GDTCORAssertClass, assertionBlockSEL); + if (assertionBlock) { + return assertionBlock; + } + } + } + } + return NULL; +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m new file mode 100644 index 0000000..97f96fa --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORClock.m @@ -0,0 +1,174 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +#import + +// Using a monotonic clock is necessary because CFAbsoluteTimeGetCurrent(), NSDate, and related all +// are subject to drift. That it to say, multiple consecutive calls do not always result in a +// time that is in the future. Clocks may be adjusted by the user, NTP, or any number of external +// factors. This class attempts to determine the wall-clock time at the time of the event by +// capturing the kernel start and time since boot to determine a wallclock time in UTC. +// +// Timezone offsets at the time of a snapshot are also captured in order to provide local-time +// details. Other classes in this library depend on comparing times at some time in the future to +// a time captured in the past, and this class needs to provide a mechanism to do that. +// +// TL;DR: This class attempts to accomplish two things: 1. Provide accurate event times. 2. Provide +// a monotonic clock mechanism to accurately check if some clock snapshot was before or after +// by using a shared reference point (kernel boot time). +// +// Note: Much of the mach time stuff doesn't work properly in the simulator. So this class can be +// difficult to unit test. + +/** Returns the kernel boottime property from sysctl. + * + * @return The KERN_BOOTTIME property from sysctl, in nanoseconds. + */ +static int64_t KernelBootTimeInNanoseconds(void) { + // Caching the result is not possible because clock drift would not be accounted for. + struct timeval boottime; + int mib[2] = {CTL_KERN, KERN_BOOTTIME}; + size_t size = sizeof(boottime); + int rc = sysctl(mib, 2, &boottime, &size, NULL, 0); + if (rc != 0) { + return 0; + } + return (int64_t)boottime.tv_sec * NSEC_PER_SEC + (int64_t)boottime.tv_usec * NSEC_PER_USEC; +} + +/** Returns value of gettimeofday, in nanoseconds. + * + * @return The value of gettimeofday, in nanoseconds. + */ +static int64_t UptimeInNanoseconds(void) { + int64_t before_now_nsec; + int64_t after_now_nsec; + struct timeval now; + + before_now_nsec = KernelBootTimeInNanoseconds(); + // Addresses a race condition in which the system time has updated, but the boottime has not. + do { + gettimeofday(&now, NULL); + after_now_nsec = KernelBootTimeInNanoseconds(); + } while (after_now_nsec != before_now_nsec); + return (int64_t)now.tv_sec * NSEC_PER_SEC + (int64_t)now.tv_usec * NSEC_PER_USEC - + before_now_nsec; +} + +// TODO: Consider adding a 'trustedTime' property that can be populated by the response from a BE. +@implementation GDTCORClock + +- (instancetype)init { + self = [super init]; + if (self) { + _kernelBootTimeNanoseconds = KernelBootTimeInNanoseconds(); + _uptimeNanoseconds = UptimeInNanoseconds(); + _timeMillis = + (int64_t)((CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970) * NSEC_PER_USEC); + _timezoneOffsetSeconds = [[NSTimeZone systemTimeZone] secondsFromGMT]; + } + return self; +} + ++ (GDTCORClock *)snapshot { + return [[GDTCORClock alloc] init]; +} + ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture { + GDTCORClock *snapshot = [self snapshot]; + snapshot->_timeMillis += millisInTheFuture; + return snapshot; +} + +- (BOOL)isAfter:(GDTCORClock *)otherClock { + // These clocks are trivially comparable when they share a kernel boot time. + if (_kernelBootTimeNanoseconds == otherClock->_kernelBootTimeNanoseconds) { + int64_t timeDiff = (_timeMillis + _timezoneOffsetSeconds) - + (otherClock->_timeMillis + otherClock->_timezoneOffsetSeconds); + return timeDiff > 0; + } else { + int64_t kernelBootTimeDiff = + otherClock->_kernelBootTimeNanoseconds - _kernelBootTimeNanoseconds; + // This isn't a great solution, but essentially, if the other clock's boot time is 'later', NO + // is returned. This can be altered by changing the system time and rebooting. + return kernelBootTimeDiff < 0 ? YES : NO; + } +} + +- (int64_t)uptimeMilliseconds { + return self.uptimeNanoseconds / NSEC_PER_MSEC; +} + +- (NSUInteger)hash { + return [@(_kernelBootTimeNanoseconds) hash] ^ [@(_uptimeNanoseconds) hash] ^ + [@(_timeMillis) hash] ^ [@(_timezoneOffsetSeconds) hash]; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - NSSecureCoding + +/** NSKeyedCoder key for timeMillis property. */ +static NSString *const kGDTCORClockTimeMillisKey = @"GDTCORClockTimeMillis"; + +/** NSKeyedCoder key for timezoneOffsetMillis property. */ +static NSString *const kGDTCORClockTimezoneOffsetSeconds = @"GDTCORClockTimezoneOffsetSeconds"; + +/** NSKeyedCoder key for _kernelBootTime ivar. */ +static NSString *const kGDTCORClockKernelBootTime = @"GDTCORClockKernelBootTime"; + +/** NSKeyedCoder key for _uptimeNanoseconds ivar. */ +static NSString *const kGDTCORClockUptime = @"GDTCORClockUptime"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)initWithCoder:(NSCoder *)aDecoder { + self = [super init]; + if (self) { + // TODO: If the kernelBootTimeNanoseconds is more recent, we need to change the kernel boot time + // and uptimeMillis ivars + _timeMillis = [aDecoder decodeInt64ForKey:kGDTCORClockTimeMillisKey]; + _timezoneOffsetSeconds = [aDecoder decodeInt64ForKey:kGDTCORClockTimezoneOffsetSeconds]; + _kernelBootTimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockKernelBootTime]; + _uptimeNanoseconds = [aDecoder decodeInt64ForKey:kGDTCORClockUptime]; + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeInt64:_timeMillis forKey:kGDTCORClockTimeMillisKey]; + [aCoder encodeInt64:_timezoneOffsetSeconds forKey:kGDTCORClockTimezoneOffsetSeconds]; + [aCoder encodeInt64:_kernelBootTimeNanoseconds forKey:kGDTCORClockKernelBootTime]; + [aCoder encodeInt64:_uptimeNanoseconds forKey:kGDTCORClockUptime]; +} + +#pragma mark - Deprecated properties + +- (int64_t)kernelBootTime { + return self.kernelBootTimeNanoseconds; +} + +- (int64_t)uptime { + return self.uptimeNanoseconds; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m new file mode 100644 index 0000000..5eaee92 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORConsoleLogger.m @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +volatile NSInteger GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelErrors; + +/** The console logger prefix. */ +static NSString *kGDTCORConsoleLogger = @"[GoogleDataTransport]"; + +NSString *GDTCORMessageCodeEnumToString(GDTCORMessageCode code) { + return [[NSString alloc] initWithFormat:@"I-GDTCOR%06ld", (long)code]; +} + +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + if (logLevel >= GDTCORConsoleLoggerLoggingLevel) { + NSString *logFormat = [NSString stringWithFormat:@"%@[%@] %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); + } +#endif // !NDEBUG +} + +void GDTCORLogAssert( + BOOL wasFatal, NSString *_Nonnull file, NSInteger line, NSString *_Nullable format, ...) { +// Don't log anything in not debug builds. +#if !NDEBUG + GDTCORMessageCode code = wasFatal ? GDTCORMCEFatalAssertion : GDTCORMCEGeneralError; + NSString *logFormat = + [NSString stringWithFormat:@"%@[%@] (%@:%ld) : %@", kGDTCORConsoleLogger, + GDTCORMessageCodeEnumToString(code), file, (long)line, format]; + va_list args; + va_start(args, format); + NSLogv(logFormat, args); + va_end(args); +#endif // !NDEBUG +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m new file mode 100644 index 0000000..0bc8515 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORDirectorySizeTracker.m @@ -0,0 +1,101 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +@interface GDTCORDirectorySizeTracker () + +/** The observed directory path. */ +@property(nonatomic, readonly) NSString *directoryPath; + +/** The cached content size of the observed directory. */ +@property(nonatomic, nullable) NSNumber *cachedSizeBytes; + +@end + +@implementation GDTCORDirectorySizeTracker + +- (instancetype)initWithDirectoryPath:(NSString *)path { + self = [super init]; + if (self) { + _directoryPath = path; + } + return self; +} + +- (GDTCORStorageSizeBytes)directoryContentSize { + if (self.cachedSizeBytes == nil) { + self.cachedSizeBytes = @([self calculateDirectoryContentSize]); + } + + return self.cachedSizeBytes.unsignedLongLongValue; +} + +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] + fileSize); +} + +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize { + if (![path hasPrefix:self.directoryPath]) { + // Ignore because the file is not inside the directory. + return; + } + + self.cachedSizeBytes = @([self directoryContentSize] - fileSize); +} + +- (void)resetCachedSize { + self.cachedSizeBytes = nil; +} + +- (GDTCORStorageSizeBytes)calculateDirectoryContentSize { + NSArray *prefetchedProperties = @[ NSURLIsRegularFileKey, NSURLFileSizeKey ]; + uint64_t totalBytes = 0; + NSURL *directoryURL = [NSURL fileURLWithPath:self.directoryPath]; + + NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] + enumeratorAtURL:directoryURL + includingPropertiesForKeys:prefetchedProperties + options:NSDirectoryEnumerationSkipsHiddenFiles + errorHandler:^BOOL(NSURL *_Nonnull url, NSError *_Nonnull error) { + return YES; + }]; + + for (NSURL *fileURL in enumerator) { + @autoreleasepool { + NSNumber *isRegularFile; + [fileURL getResourceValue:&isRegularFile forKey:NSURLIsRegularFileKey error:nil]; + if (isRegularFile.boolValue) { + totalBytes += [self fileSizeAtURL:fileURL]; + } + } + } + + return totalBytes; +} + +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL { + NSNumber *fileSize; + [fileURL getResourceValue:&fileSize forKey:NSURLFileSizeKey error:nil]; + return fileSize.unsignedLongLongValue; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m new file mode 100644 index 0000000..f16db13 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREndpoints.m @@ -0,0 +1,92 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +static NSString *const kINTServerURL = + @"https://dummyapiverylong-dummy.google.com/dummy/api/very/long"; + +@implementation GDTCOREndpoints + ++ (NSDictionary *)uploadURLs { + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + static NSURL *CCTServerURL; + static dispatch_once_t CCTOnceToken; + dispatch_once(&CCTOnceToken, ^{ + const char *p1 = "hts/frbslgiggolai.o/0clgbth"; + const char *p2 = "tp:/ieaeogn.ogepscmvc/o/ac"; + const char URL[54] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], '\0'}; + CCTServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *FLLServerURL; + static dispatch_once_t FLLOnceToken; + dispatch_once(&FLLOnceToken, ^{ + const char *p1 = "hts/frbslgigp.ogepscmv/ieo/eaybtho"; + const char *p2 = "tp:/ieaeogn-agolai.o/1frlglgc/aclg"; + const char URL[69] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], '\0'}; + FLLServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + + static NSURL *CSHServerURL; + static dispatch_once_t CSHOnceToken; + dispatch_once(&CSHOnceToken, ^{ + // These strings should be interleaved to construct the real URL. This is just to (hopefully) + // fool github URL scanning bots. + const char *p1 = "hts/cahyiseot-agolai.o/1frlglgc/aclg"; + const char *p2 = "tp:/rsltcrprsp.ogepscmv/ieo/eaybtho"; + const char URL[72] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4], + p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8], + p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13], + p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17], + p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22], + p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26], + p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31], + p2[31], p1[32], p2[32], p1[33], p2[33], p1[34], p2[34], p1[35], '\0'}; + CSHServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]]; + }); + static NSDictionary *uploadURLs; + static dispatch_once_t URLOnceToken; + dispatch_once(&URLOnceToken, ^{ + uploadURLs = @{ + @(kGDTCORTargetCCT) : CCTServerURL, + @(kGDTCORTargetFLL) : FLLServerURL, + @(kGDTCORTargetCSH) : CSHServerURL, + @(kGDTCORTargetINT) : [NSURL URLWithString:kINTServerURL] + }; + }); + return uploadURLs; +} + ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target { + NSDictionary *URLs = [self uploadURLs]; + return [URLs objectForKey:@(target)]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m new file mode 100644 index 0000000..98db41a --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCOREvent.m @@ -0,0 +1,170 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" + +@implementation GDTCOREvent + ++ (NSString *)nextEventID { + // Replace special non-alphanumeric characters to avoid potential conflicts with storage logic. + return [[NSUUID UUID].UUIDString stringByReplacingOccurrencesOfString:@"-" withString:@""]; +} + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + productData:(nullable GDTCORProductData *)productData + target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"Please give a valid mapping ID"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _eventID = [GDTCOREvent nextEventID]; + _mappingID = mappingID; + _productData = productData; + _target = target; + _qosTier = GDTCOREventQosDefault; + _expirationDate = [NSDate dateWithTimeIntervalSinceNow:604800]; // 7 days. + + GDTCORLogDebug(@"Event %@ created. ID:%@ mappingID: %@ target:%ld", self, _eventID, mappingID, + (long)target); + } + + return self; +} + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target { + return [self initWithMappingID:mappingID productData:nil target:target]; +} + +- (instancetype)copy { + GDTCOREvent *copy = [[GDTCOREvent alloc] initWithMappingID:_mappingID + productData:_productData + target:_target]; + copy->_eventID = _eventID; + copy.dataObject = _dataObject; + copy.qosTier = _qosTier; + copy.clockSnapshot = _clockSnapshot; + copy.customBytes = _customBytes; + GDTCORLogDebug(@"Copying event %@ to event %@", self, copy); + return copy; +} + +- (NSUInteger)hash { + // This loses some precision, but it's probably fine. + NSUInteger eventIDHash = [_eventID hash]; + NSUInteger mappingIDHash = [_mappingID hash]; + NSUInteger productDataHash = [_productData hash]; + NSUInteger timeHash = [_clockSnapshot hash]; + NSInteger serializedBytesHash = [_serializedDataObjectBytes hash]; + + return eventIDHash ^ mappingIDHash ^ productDataHash ^ _target ^ _qosTier ^ timeHash ^ + serializedBytesHash; +} + +- (BOOL)isEqual:(id)object { + return [self hash] == [object hash]; +} + +#pragma mark - Property overrides + +- (void)setDataObject:(id)dataObject { + // If you're looking here because of a performance issue in -transportBytes slowing the assignment + // of -dataObject, one way to address this is to add a queue to this class, + // dispatch_(barrier_ if concurrent)async here, and implement the getter with a dispatch_sync. + if (dataObject != _dataObject) { + _dataObject = dataObject; + } + self->_serializedDataObjectBytes = [dataObject transportBytes]; +} + +#pragma mark - NSSecureCoding and NSCoding Protocols + +/** NSCoding key for eventID property. */ +static NSString *kEventIDKey = @"GDTCOREventEventIDKey"; + +/** NSCoding key for mappingID property. */ +static NSString *kMappingIDKey = @"GDTCOREventMappingIDKey"; + +/** NSCoding key for target property. */ +static NSString *kTargetKey = @"GDTCOREventTargetKey"; + +/** NSCoding key for qosTier property. */ +static NSString *kQoSTierKey = @"GDTCOREventQoSTierKey"; + +/** NSCoding key for clockSnapshot property. */ +static NSString *kClockSnapshotKey = @"GDTCOREventClockSnapshotKey"; + +/** NSCoding key for expirationDate property. */ +static NSString *kExpirationDateKey = @"GDTCOREventExpirationDateKey"; + +/** NSCoding key for serializedDataObjectBytes property. */ +static NSString *kSerializedDataObjectBytes = @"GDTCOREventSerializedDataObjectBytesKey"; + +/** NSCoding key for customData property. */ +static NSString *kCustomDataKey = @"GDTCOREventCustomDataKey"; + +/** NSCoding key for productData property. */ +static NSString *kProductDataKey = @"GDTCOREventProductDataKey"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (id)initWithCoder:(NSCoder *)aDecoder { + self = [self init]; + if (self) { + _mappingID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kMappingIDKey]; + _productData = [aDecoder decodeObjectOfClass:[GDTCORProductData class] forKey:kProductDataKey]; + _target = [aDecoder decodeIntegerForKey:kTargetKey]; + _eventID = [aDecoder decodeObjectOfClass:[NSString class] forKey:kEventIDKey] + ?: [GDTCOREvent nextEventID]; + _qosTier = [aDecoder decodeIntegerForKey:kQoSTierKey]; + _clockSnapshot = [aDecoder decodeObjectOfClass:[GDTCORClock class] forKey:kClockSnapshotKey]; + _customBytes = [aDecoder decodeObjectOfClass:[NSData class] forKey:kCustomDataKey]; + _expirationDate = [aDecoder decodeObjectOfClass:[NSDate class] forKey:kExpirationDateKey]; + _serializedDataObjectBytes = [aDecoder decodeObjectOfClass:[NSData class] + forKey:kSerializedDataObjectBytes]; + if (!_serializedDataObjectBytes) { + return nil; + } + } + return self; +} + +- (void)encodeWithCoder:(NSCoder *)aCoder { + [aCoder encodeObject:_eventID forKey:kEventIDKey]; + [aCoder encodeObject:_mappingID forKey:kMappingIDKey]; + [aCoder encodeObject:_productData forKey:kProductDataKey]; + [aCoder encodeInteger:_target forKey:kTargetKey]; + [aCoder encodeInteger:_qosTier forKey:kQoSTierKey]; + [aCoder encodeObject:_clockSnapshot forKey:kClockSnapshotKey]; + [aCoder encodeObject:_customBytes forKey:kCustomDataKey]; + [aCoder encodeObject:_expirationDate forKey:kExpirationDateKey]; + [aCoder encodeObject:self.serializedDataObjectBytes forKey:kSerializedDataObjectBytes]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m new file mode 100644 index 0000000..4ff937c --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage+Promises.m @@ -0,0 +1,161 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORFlatFileStorage (Promises) + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapObjectCompletion:^(FBLPromiseObjectCompletion _Nonnull handler) { + [self batchIDsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents { + return [FBLPromise onQueue:self.storageQueue + wrapCompletion:^(FBLPromiseCompletion _Nonnull handler) { + [self removeBatchWithID:batchID deleteEvents:deleteEvents onComplete:handler]; + }]; +} + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents { + NSMutableArray *removeBatchPromises = + [NSMutableArray arrayWithCapacity:batchIDs.count]; + for (NSNumber *batchID in batchIDs) { + [removeBatchPromises addObject:[self removeBatchWithID:batchID deleteEvents:deleteEvents]]; + } + + return [FBLPromise onQueue:self.storageQueue all:[removeBatchPromises copy]].thenOn( + self.storageQueue, ^id(id result) { + return [FBLPromise resolvedWith:[NSNull null]]; + }); +} + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents { + return + [self batchIDsForTarget:target].thenOn(self.storageQueue, ^id(NSSet *batchIDs) { + if (batchIDs.count == 0) { + return [FBLPromise resolvedWith:[NSNull null]]; + } else { + return [self removeBatchesWithIDs:batchIDs deleteEvents:NO]; + } + }); +} + +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target { + return [FBLPromise onQueue:self.storageQueue + wrapBoolCompletion:^(FBLPromiseBoolCompletion _Nonnull handler) { + [self hasEventsForTarget:target onComplete:handler]; + }]; +} + +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration { + return [FBLPromise + onQueue:self.storageQueue + async:^(FBLPromiseFulfillBlock _Nonnull fulfill, FBLPromiseRejectBlock _Nonnull reject) { + [self batchWithEventSelector:eventSelector + batchExpiration:expiration + onComplete:^(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents) { + if (newBatchID == nil || batchEvents == nil) { + reject([self genericRejectedPromiseErrorWithReason: + @"There are no events for the selector."]); + } else { + fulfill([[GDTCORUploadBatch alloc] initWithBatchID:newBatchID + events:batchEvents]); + } + }]; + }]; +} + +- (FBLPromise *)fetchAndUpdateMetricsWithHandler: + (GDTCORMetricsMetadata * (^)(GDTCORMetricsMetadata *_Nullable fetchedMetadata, + NSError *_Nullable fetchError))handler { + return FBLPromise.doOn(self.storageQueue, ^id { + // Fetch the stored metrics metadata. + NSError *decodeError; + NSString *metricsMetadataPath = + [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:@"metrics_metadata"]; + GDTCORMetricsMetadata *decodedMetadata = (GDTCORMetricsMetadata *)GDTCORDecodeArchiveAtPath( + GDTCORMetricsMetadata.class, metricsMetadataPath, &decodeError); + + // Update the metadata using the retrieved metadata. + GDTCORMetricsMetadata *updatedMetadata = handler(decodedMetadata, decodeError); + if (updatedMetadata == nil) { + // `nil` metadata is not expected and will be a no-op. + return nil; + } + + if (![updatedMetadata isEqual:decodedMetadata]) { + // The metadata was updated so it needs to be saved. + // - Encode the updated metadata. + NSError *encodeError; + NSData *encodedMetadata = GDTCOREncodeArchive(updatedMetadata, nil, &encodeError); + if (encodeError) { + return encodeError; + } + + // - Write the encoded metadata to disk. + NSError *writeError; + BOOL writeResult = GDTCORWriteDataToFile(encodedMetadata, metricsMetadataPath, &writeError); + if (writeResult == NO || writeError) { + return writeError; + } + } + + return nil; + }); +} + +- (FBLPromise *)fetchStorageMetadata { + return FBLPromise.asyncOn(self.storageQueue, ^(FBLPromiseFulfillBlock _Nonnull fulfill, + FBLPromiseRejectBlock _Nonnull reject) { + [self storageSizeWithCallback:^(GDTCORStorageSizeBytes storageSize) { + fulfill([GDTCORStorageMetadata metadataWithCurrentCacheSize:storageSize + maxCacheSize:kGDTCORFlatFileStorageSizeLimit]); + }]; + }); +} + +// TODO: Move to a separate class/extension when needed in more places. +- (NSError *)genericRejectedPromiseErrorWithReason:(NSString *)reason { + return [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSLocalizedFailureReasonErrorKey : reason}]; +} + +@end + +/// Stub used to force the linker to include the categories in this file. +void GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(void) { +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m new file mode 100644 index 0000000..fe36a19 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORFlatFileStorage.m @@ -0,0 +1,849 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A library data key this class uses to track batchIDs. */ +static NSString *const gBatchIDCounterKey = @"GDTCORFlatFileStorageBatchIDCounter"; + +/** The separator used between metadata elements in filenames. */ +static NSString *const kMetadataSeparator = @"-"; + +NSString *const kGDTCOREventComponentsEventIDKey = @"GDTCOREventComponentsEventIDKey"; + +NSString *const kGDTCOREventComponentsQoSTierKey = @"GDTCOREventComponentsQoSTierKey"; + +NSString *const kGDTCOREventComponentsMappingIDKey = @"GDTCOREventComponentsMappingIDKey"; + +NSString *const kGDTCOREventComponentsExpirationKey = @"GDTCOREventComponentsExpirationKey"; + +NSString *const kGDTCORBatchComponentsTargetKey = @"GDTCORBatchComponentsTargetKey"; + +NSString *const kGDTCORBatchComponentsBatchIDKey = @"GDTCORBatchComponentsBatchIDKey"; + +NSString *const kGDTCORBatchComponentsExpirationKey = @"GDTCORBatchComponentsExpirationKey"; + +NSString *const GDTCORFlatFileStorageErrorDomain = @"GDTCORFlatFileStorage"; + +const uint64_t kGDTCORFlatFileStorageSizeLimit = 20 * 1000 * 1000; // 20 MB. + +@interface GDTCORFlatFileStorage () + +/** An instance of the size tracker to keep track of the disk space consumed by the storage. */ +@property(nonatomic, readonly) GDTCORDirectorySizeTracker *sizeTracker; + +@end + +@implementation GDTCORFlatFileStorage + +@synthesize sizeTracker = _sizeTracker; +@synthesize delegate = _delegate; + ++ (void)load { +#if !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetTest]; +#endif // !NDEBUG + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCCT]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetFLL]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerStorage:[self sharedInstance] target:kGDTCORTargetINT]; +} + ++ (instancetype)sharedInstance { + static GDTCORFlatFileStorage *sharedStorage; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedStorage = [[GDTCORFlatFileStorage alloc] init]; + }); + return sharedStorage; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _storageQueue = + dispatch_queue_create("com.google.GDTCORFlatFileStorage", DISPATCH_QUEUE_SERIAL); + _uploadCoordinator = [GDTCORUploadCoordinator sharedInstance]; + } + return self; +} + +- (GDTCORDirectorySizeTracker *)sizeTracker { + if (_sizeTracker == nil) { + _sizeTracker = + [[GDTCORDirectorySizeTracker alloc] initWithDirectoryPath:GDTCORRootDirectory().path]; + } + return _sizeTracker; +} + +#pragma mark - GDTCORStorageProtocol + +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORLogDebug(@"Saving event: %@", event); + if (event == nil || event.serializedDataObjectBytes == nil) { + GDTCORLogDebug(@"%@", @"The event was nil, so it was not saved."); + if (completion) { + completion(NO, [NSError errorWithDomain:NSInternalInconsistencyException + code:-1 + userInfo:nil]); + } + return; + } + if (!completion) { + completion = ^(BOOL wasWritten, NSError *_Nullable error) { + GDTCORLogDebug(@"event %@ stored. success:%@ error:%@", event, wasWritten ? @"YES" : @"NO", + error); + }; + } + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + bgID = [[GDTCORApplication sharedApplication] + beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + // End the background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + dispatch_async(_storageQueue, ^{ + // Check that a backend implementation is available for this target. + GDTCORTarget target = event.target; + NSString *filePath = [GDTCORFlatFileStorage pathForTarget:target + eventID:event.eventID + qosTier:@(event.qosTier) + expirationDate:event.expirationDate + mappingID:event.mappingID]; + NSError *error; + NSData *encodedEvent = GDTCOREncodeArchive(event, nil, &error); + if (error) { + completion(NO, error); + return; + } + + // Check storage size limit before storing the event. + uint64_t resultingStorageSize = self.sizeTracker.directoryContentSize + encodedEvent.length; + if (resultingStorageSize > kGDTCORFlatFileStorageSizeLimit) { + NSError *error = [NSError + errorWithDomain:GDTCORFlatFileStorageErrorDomain + code:GDTCORFlatFileStorageErrorSizeLimitReached + userInfo:@{ + NSLocalizedFailureReasonErrorKey : @"Storage size limit has been reached." + }]; + if (self.delegate != nil) { + GDTCORLogDebug(@"Delegate notified that event with mapping ID %@ was dropped.", + event.mappingID); + [self.delegate storage:self didDropEvent:event]; + } + completion(NO, error); + return; + } + + // Write the encoded event to the file. + BOOL writeResult = GDTCORWriteDataToFile(encodedEvent, filePath, &error); + if (writeResult == NO || error) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, error); + completion(NO, error); + return; + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + completion(YES, nil); + } + + // Notify size tracker. + [self.sizeTracker fileWasAddedAtPath:filePath withSize:encodedEvent.length]; + + // Check the QoS, if it's high priority, notify the target that it has a high priority event. + if (event.qosTier == GDTCOREventQoSFast) { + // TODO: Remove a direct dependency on the upload coordinator. + [self.uploadCoordinator forceUploadForTarget:target]; + } + + // Cancel or end the associated background task if it's still valid. + [[GDTCORApplication sharedApplication] endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete: + (nonnull void (^)(NSNumber *_Nullable batchID, + NSSet *_Nullable events))onComplete { + dispatch_queue_t queue = _storageQueue; + void (^onPathsForTargetComplete)(NSNumber *, NSSet *_Nonnull) = ^( + NSNumber *batchID, NSSet *_Nonnull paths) { + dispatch_async(queue, ^{ + NSMutableSet *events = [[NSMutableSet alloc] init]; + for (NSString *eventPath in paths) { + NSError *error; + GDTCOREvent *event = + (GDTCOREvent *)GDTCORDecodeArchiveAtPath([GDTCOREvent class], eventPath, &error); + if (event == nil || error) { + GDTCORLogDebug(@"Error deserializing event: %@", error); + [[NSFileManager defaultManager] removeItemAtPath:eventPath error:nil]; + continue; + } else { + NSString *fileName = [eventPath lastPathComponent]; + NSString *batchPath = + [GDTCORFlatFileStorage batchPathForTarget:eventSelector.selectedTarget + batchID:batchID + expirationDate:expiration]; + [[NSFileManager defaultManager] createDirectoryAtPath:batchPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSString *destinationPath = [batchPath stringByAppendingPathComponent:fileName]; + error = nil; + [[NSFileManager defaultManager] moveItemAtPath:eventPath + toPath:destinationPath + error:&error]; + if (error) { + GDTCORLogDebug(@"An event file wasn't moveable into the batch directory: %@", error); + } + [events addObject:event]; + } + } + if (onComplete) { + if (events.count == 0) { + onComplete(nil, nil); + } else { + onComplete(batchID, events); + } + } + }); + }; + + void (^onBatchIDFetchComplete)(NSNumber *) = ^(NSNumber *batchID) { + dispatch_async(queue, ^{ + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + return; + } + } + [self pathsForTarget:eventSelector.selectedTarget + eventIDs:eventSelector.selectedEventIDs + qosTiers:eventSelector.selectedQosTiers + mappingIDs:eventSelector.selectedMappingIDs + onComplete:^(NSSet *_Nonnull paths) { + onPathsForTargetComplete(batchID, paths); + }]; + }); + }; + + [self nextBatchID:^(NSNumber *_Nullable batchID) { + if (batchID == nil) { + if (onComplete) { + onComplete(nil, nil); + } + } else { + onBatchIDFetchComplete(batchID); + } + }]; +} + +- (void)removeBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete { + dispatch_async(_storageQueue, ^{ + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:deleteEvents]; + + if (onComplete) { + onComplete(); + } + }); +} + +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(nonnull void (^)(NSSet *_Nullable))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batchPaths = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (error || batchPaths.count == 0) { + if (onComplete) { + onComplete(nil); + } + return; + } + NSMutableSet *batchIDs = [[NSMutableSet alloc] init]; + for (NSString *path in batchPaths) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *targetNumber = components[kGDTCORBatchComponentsTargetKey]; + NSNumber *batchID = components[kGDTCORBatchComponentsBatchIDKey]; + if (batchID != nil && targetNumber.intValue == target) { + [batchIDs addObject:batchID]; + } + } + if (onComplete) { + onComplete(batchIDs); + } + }); +} + +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable, NSError *_Nullable))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock { + dispatch_async(_storageQueue, ^{ + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + NSError *error; + NSData *data = [NSData dataWithContentsOfFile:dataPath options:0 error:&error]; + if (onFetchComplete) { + onFetchComplete(data, error); + } + if (setValueBlock) { + NSData *newValue = setValueBlock(); + // The -isKindOfClass check is necessary because without an explicit 'return nil' in the block + // the implicit return value will be the block itself. The compiler doesn't detect this. + if (newValue != nil && [newValue isKindOfClass:[NSData class]] && newValue.length) { + NSError *newValueError; + if ([newValue writeToFile:dataPath options:NSDataWritingAtomic error:&newValueError]) { + // Update storage size. + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:data.length]; + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:newValue.length]; + } else { + GDTCORLogDebug(@"Error writing new value in libraryDataForKey: %@", newValueError); + } + } + } + }); +} + +- (void)storeLibraryData:(NSData *)data + forKey:(nonnull NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete { + if (!data || data.length <= 0) { + if (onComplete) { + onComplete([NSError errorWithDomain:NSInternalInconsistencyException code:-1 userInfo:nil]); + } + return; + } + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + if ([data writeToFile:dataPath options:NSDataWritingAtomic error:&error]) { + [self.sizeTracker fileWasAddedAtPath:dataPath withSize:data.length]; + } + if (onComplete) { + onComplete(error); + } + }); +} + +- (void)removeLibraryDataForKey:(nonnull NSString *)key + onComplete:(nonnull void (^)(NSError *_Nullable error))onComplete { + dispatch_async(_storageQueue, ^{ + NSError *error; + NSString *dataPath = [[[self class] libraryDataStoragePath] stringByAppendingPathComponent:key]; + GDTCORStorageSizeBytes fileSize = + [self.sizeTracker fileSizeAtURL:[NSURL fileURLWithPath:dataPath]]; + + if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) { + if ([[NSFileManager defaultManager] removeItemAtPath:dataPath error:&error]) { + [self.sizeTracker fileWasRemovedAtPath:dataPath withSize:fileSize]; + } + if (onComplete) { + onComplete(error); + } + } + }); +} + +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete { + dispatch_async(_storageQueue, ^{ + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:targetPath]; + BOOL hasEventAtLeastOneEvent = [enumerator nextObject] != nil; + if (onComplete) { + onComplete(hasEventAtLeastOneEvent); + } + }); +} + +- (void)checkForExpirations { + dispatch_async(_storageQueue, ^{ + GDTCORLogDebug(@"%@", @"Checking for expired events and batches"); + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + NSFileManager *fileManager = [NSFileManager defaultManager]; + + // TODO: Storage may not have enough context to remove batches because a batch may be being + // uploaded but the storage has not context of it. + + // Find expired batches and move their events back to the main storage. + // If a batch contains expired events they are expected to be removed further in the method + // together with other expired events in the main storage. + NSString *batchDataPath = [GDTCORFlatFileStorage batchDataStoragePath]; + NSArray *batchDataPaths = [fileManager contentsOfDirectoryAtPath:batchDataPath + error:nil]; + for (NSString *path in batchDataPaths) { + @autoreleasepool { + NSString *fileName = [path lastPathComponent]; + NSDictionary *batchComponents = [self batchComponentsFromFilename:fileName]; + NSDate *expirationDate = batchComponents[kGDTCORBatchComponentsExpirationKey]; + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now && batchID != nil) { + NSNumber *batchID = batchComponents[kGDTCORBatchComponentsBatchIDKey]; + // Move all events from the expired batch back to the main storage. + [self syncThreadUnsafeRemoveBatchWithID:batchID deleteEvents:NO]; + } + } + } + + // Find expired events and remove them from the storage. + NSMutableSet *expiredEvents = [NSMutableSet set]; + NSString *eventDataPath = [GDTCORFlatFileStorage eventDataStoragePath]; + NSDirectoryEnumerator *enumerator = [fileManager enumeratorAtPath:eventDataPath]; + NSString *path; + + while (YES) { + @autoreleasepool { + // Call `[enumerator nextObject]` under autorelease pool to make sure all autoreleased + // objects created under the hood are released on each iteration end to avoid unnecessary + // memory growth. + path = [enumerator nextObject]; + if (path == nil) { + break; + } + + NSString *fileName = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:fileName]; + NSDate *expirationDate = eventComponents[kGDTCOREventComponentsExpirationKey]; + if (expirationDate != nil && expirationDate.timeIntervalSince1970 < now) { + NSString *pathToDelete = [eventDataPath stringByAppendingPathComponent:path]; + + // Decode the expired event from the path to be deleted. + NSError *decodeError; + GDTCOREvent *event = (GDTCOREvent *)GDTCORDecodeArchiveAtPath([GDTCOREvent class], + pathToDelete, &decodeError); + if (event == nil || decodeError) { + GDTCORLogDebug(@"Error deserializing event while checking for expired events: %@", + decodeError); + event = nil; + } + + // Remove the path to be deleted, adding the decoded event to the + // event set if the removal was successful. + NSError *removeError; + [fileManager removeItemAtPath:pathToDelete error:&removeError]; + if (removeError != nil) { + GDTCORLogDebug(@"There was an error deleting an expired item: %@", removeError); + } else { + GDTCORLogDebug(@"Item deleted because it expired: %@", pathToDelete); + if (event) { + [expiredEvents addObject:event]; + } + } + } + } + } + + if (self.delegate != nil && [expiredEvents count] > 0) { + GDTCORLogDebug(@"Delegate notified that %@ events were dropped.", @(expiredEvents.count)); + [self.delegate storage:self didRemoveExpiredEvents:[expiredEvents copy]]; + } + + [self.sizeTracker resetCachedSize]; + }); +} + +- (void)storageSizeWithCallback:(void (^)(uint64_t storageSize))onComplete { + if (!onComplete) { + return; + } + + dispatch_async(_storageQueue, ^{ + onComplete([self.sizeTracker directoryContentSize]); + }); +} + +#pragma mark - Private not thread safe methods +/** Looks for directory paths containing events for a batch with the specified ID. + * @param batchID A batch ID. + * @param outError A pointer to `NSError *` to assign as possible error to. + * @return An array of an array of paths to directories for event batches with a specified batch ID + * or `nil` in the case of an error. Usually returns a single path but potentially return more in + * cases when the app is terminated while uploading a batch. + */ +- (nullable NSArray *)batchDirPathsForBatchID:(NSNumber *)batchID + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error; + NSArray *batches = + [fileManager contentsOfDirectoryAtPath:[GDTCORFlatFileStorage batchDataStoragePath] + error:&error]; + if (batches == nil) { + *outError = error; + GDTCORLogDebug(@"Failed to find event file paths for batchID: %@, error: %@", batchID, error); + return nil; + } + + NSMutableArray *batchDirPaths = [NSMutableArray array]; + for (NSString *path in batches) { + NSDictionary *components = [self batchComponentsFromFilename:path]; + NSNumber *pathBatchID = components[kGDTCORBatchComponentsBatchIDKey]; + if ([pathBatchID isEqual:batchID]) { + NSString *batchDirPath = + [[GDTCORFlatFileStorage batchDataStoragePath] stringByAppendingPathComponent:path]; + [batchDirPaths addObject:batchDirPath]; + } + } + + return [batchDirPaths copy]; +} + +/** Makes a copy of the contents of a directory to a directory at the specified path.*/ +- (BOOL)moveContentsOfDirectoryAtPath:(NSString *)sourcePath + to:(NSString *)destinationPath + error:(NSError **_Nonnull)outError { + NSFileManager *fileManager = [NSFileManager defaultManager]; + + NSError *error; + NSArray *contentsPaths = [fileManager contentsOfDirectoryAtPath:sourcePath + error:&error]; + if (contentsPaths == nil) { + *outError = error; + return NO; + } + + NSMutableArray *errors = [NSMutableArray array]; + for (NSString *path in contentsPaths) { + NSString *contentDestinationPath = [destinationPath stringByAppendingPathComponent:path]; + NSString *contentSourcePath = [sourcePath stringByAppendingPathComponent:path]; + + NSError *moveError; + if (![fileManager moveItemAtPath:contentSourcePath + toPath:contentDestinationPath + error:&moveError] && + moveError) { + [errors addObject:moveError]; + } + } + + if (errors.count == 0) { + return YES; + } else { + NSError *combinedError = [NSError errorWithDomain:@"GDTCORFlatFileStorage" + code:-1 + userInfo:@{NSUnderlyingErrorKey : errors}]; + *outError = combinedError; + return NO; + } +} + +- (void)syncThreadUnsafeRemoveBatchWithID:(nonnull NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents { + NSError *error; + NSArray *batchDirPaths = [self batchDirPathsForBatchID:batchID error:&error]; + + if (batchDirPaths == nil) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + + void (^removeBatchDir)(NSString *batchDirPath) = ^(NSString *batchDirPath) { + NSError *error; + if ([fileManager removeItemAtPath:batchDirPath error:&error]) { + GDTCORLogDebug(@"Batch removed at path: %@", batchDirPath); + } else { + GDTCORLogDebug(@"Failed to remove batch at path: %@", batchDirPath); + } + }; + + for (NSString *batchDirPath in batchDirPaths) { + @autoreleasepool { + if (deleteEvents) { + removeBatchDir(batchDirPath); + } else { + NSString *batchDirName = [batchDirPath lastPathComponent]; + NSDictionary *components = [self batchComponentsFromFilename:batchDirName]; + NSString *targetValue = [components[kGDTCORBatchComponentsTargetKey] stringValue]; + NSString *destinationPath; + if (targetValue) { + destinationPath = [[GDTCORFlatFileStorage eventDataStoragePath] + stringByAppendingPathComponent:targetValue]; + } + + // `- [NSFileManager moveItemAtPath:toPath:error:]` method fails if an item by the + // destination path already exists (which usually is the case for the current method). Move + // the events one by one instead. + if (destinationPath && [self moveContentsOfDirectoryAtPath:batchDirPath + to:destinationPath + error:&error]) { + GDTCORLogDebug(@"Batched events at path: %@ moved back to the storage: %@", batchDirPath, + destinationPath); + } else { + GDTCORLogDebug(@"Error encountered whilst moving events back: %@", error); + } + + // Even if not all events where moved back to the storage, there is not much can be done at + // this point, so cleanup batch directory now to avoid cluttering. + removeBatchDir(batchDirPath); + } + } + } + + [self.sizeTracker resetCachedSize]; +} + +#pragma mark - Private helper methods + ++ (NSString *)eventDataStoragePath { + static NSString *eventDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventDataPath = [NSString stringWithFormat:@"%@/%@/gdt_event_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:eventDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return eventDataPath; +} + ++ (NSString *)batchDataStoragePath { + static NSString *batchDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + batchDataPath = [NSString stringWithFormat:@"%@/%@/gdt_batch_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:batchDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the batch data path failed: %@", error); + return batchDataPath; +} + ++ (NSString *)libraryDataStoragePath { + static NSString *libraryDataPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + libraryDataPath = + [NSString stringWithFormat:@"%@/%@/gdt_library_data", GDTCORRootDirectory().path, + NSStringFromClass([self class])]; + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:libraryDataPath + withIntermediateDirectories:YES + attributes:0 + error:&error]; + GDTCORAssert(error == nil, @"Creating the library data path failed: %@", error); + return libraryDataPath; +} + ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate { + return + [NSString stringWithFormat:@"%@/%ld%@%@%@%llu", [GDTCORFlatFileStorage batchDataStoragePath], + (long)target, kMetadataSeparator, batchID, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970)]; +} + ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID { + NSMutableCharacterSet *allowedChars = [[NSCharacterSet alphanumericCharacterSet] mutableCopy]; + [allowedChars addCharactersInString:kMetadataSeparator]; + mappingID = [mappingID stringByAddingPercentEncodingWithAllowedCharacters:allowedChars]; + return [NSString stringWithFormat:@"%@/%ld/%@%@%@%@%llu%@%@", + [GDTCORFlatFileStorage eventDataStoragePath], (long)target, + eventID, kMetadataSeparator, qosTier, kMetadataSeparator, + ((uint64_t)expirationDate.timeIntervalSince1970), + kMetadataSeparator, mappingID]; +} + +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete { + void (^completion)(NSSet *) = onComplete == nil ? ^(NSSet *paths){} : onComplete; + dispatch_async(_storageQueue, ^{ + NSMutableSet *paths = [[NSMutableSet alloc] init]; + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSString *targetPath = [NSString + stringWithFormat:@"%@/%ld", [GDTCORFlatFileStorage eventDataStoragePath], (long)target]; + [fileManager createDirectoryAtPath:targetPath + withIntermediateDirectories:YES + attributes:nil + error:nil]; + NSError *error; + NSArray *dirPaths = [fileManager contentsOfDirectoryAtPath:targetPath error:&error]; + if (error) { + GDTCORLogDebug(@"There was an error reading the contents of the target path: %@", error); + completion(paths); + return; + } + BOOL checkingIDs = eventIDs.count > 0; + BOOL checkingQosTiers = qosTiers.count > 0; + BOOL checkingMappingIDs = mappingIDs.count > 0; + BOOL checkingAnything = checkingIDs == NO && checkingQosTiers == NO && checkingMappingIDs == NO; + for (NSString *path in dirPaths) { + // Skip hidden files that are created as part of atomic file creation. + if ([path hasPrefix:@"."]) { + continue; + } + NSString *filePath = [targetPath stringByAppendingPathComponent:path]; + if (checkingAnything) { + [paths addObject:filePath]; + continue; + } + NSString *filename = [path lastPathComponent]; + NSDictionary *eventComponents = [self eventComponentsFromFilename:filename]; + if (!eventComponents) { + GDTCORLogDebug(@"There was an error reading the filename components: %@", eventComponents); + continue; + } + NSString *eventID = eventComponents[kGDTCOREventComponentsEventIDKey]; + NSNumber *qosTier = eventComponents[kGDTCOREventComponentsQoSTierKey]; + NSString *mappingID = eventComponents[kGDTCOREventComponentsMappingIDKey]; + + NSNumber *eventIDMatch = checkingIDs ? @([eventIDs containsObject:eventID]) : nil; + NSNumber *qosTierMatch = checkingQosTiers ? @([qosTiers containsObject:qosTier]) : nil; + NSNumber *mappingIDMatch = + checkingMappingIDs + ? @([mappingIDs containsObject:[mappingID stringByRemovingPercentEncoding]]) + : nil; + if ((eventIDMatch == nil || eventIDMatch.boolValue) && + (qosTierMatch == nil || qosTierMatch.boolValue) && + (mappingIDMatch == nil || mappingIDMatch.boolValue)) { + [paths addObject:filePath]; + } + } + completion(paths); + }); +} + +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))nextBatchID { + __block int32_t lastBatchID = -1; + [self libraryDataForKey:gBatchIDCounterKey + onFetchComplete:^(NSData *_Nullable data, NSError *_Nullable getValueError) { + if (!getValueError) { + [data getBytes:(void *)&lastBatchID length:sizeof(int32_t)]; + } + if (data == nil) { + lastBatchID = 0; + } + if (nextBatchID) { + nextBatchID(@(lastBatchID)); + } + } + setNewValue:^NSData *_Nullable(void) { + if (lastBatchID != -1) { + int32_t incrementedValue = lastBatchID + 1; + return [NSData dataWithBytes:&incrementedValue length:sizeof(int32_t)]; + } + return nil; + }]; +} + +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count >= 4) { + NSString *eventID = components[0]; + NSNumber *qosTier = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].longLongValue]; + NSString *mappingID = [[components subarrayWithRange:NSMakeRange(3, components.count - 3)] + componentsJoinedByString:kMetadataSeparator]; + if (eventID == nil || qosTier == nil || mappingID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the event filename components: %@", components); + return nil; + } + return @{ + kGDTCOREventComponentsEventIDKey : eventID, + kGDTCOREventComponentsQoSTierKey : qosTier, + kGDTCOREventComponentsExpirationKey : expirationDate, + kGDTCOREventComponentsMappingIDKey : mappingID + }; + } + GDTCORLogDebug(@"The event filename could not be split: %@", fileName); + return nil; +} + +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName { + NSArray *components = [fileName componentsSeparatedByString:kMetadataSeparator]; + if (components.count == 3) { + NSNumber *target = @(components[0].integerValue); + NSNumber *batchID = @(components[1].integerValue); + NSDate *expirationDate = [NSDate dateWithTimeIntervalSince1970:components[2].doubleValue]; + if (target == nil || batchID == nil || expirationDate == nil) { + GDTCORLogDebug(@"There was an error parsing the batch filename components: %@", components); + return nil; + } + return @{ + kGDTCORBatchComponentsTargetKey : target, + kGDTCORBatchComponentsBatchIDKey : batchID, + kGDTCORBatchComponentsExpirationKey : expirationDate + }; + } + GDTCORLogDebug(@"The batch filename could not be split: %@", fileName); + return nil; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_storageQueue, ^{ + // Immediately request a background task to run until the end of the current queue of work, + // and cancel it once the work is done. + __block GDTCORBackgroundIdentifier bgID = + [app beginBackgroundTaskWithName:@"GDTStorage" + expirationHandler:^{ + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + // End the background task if it's still valid. + [app endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }); +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m new file mode 100644 index 0000000..7e53456 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLifecycle.m @@ -0,0 +1,118 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +@implementation GDTCORLifecycle + ++ (void)load { + [self sharedInstance]; +} + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance { + static GDTCORLifecycle *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORLifecycle alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(applicationDidEnterBackgroundNotification:) + name:kGDTCORApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(applicationWillEnterForegroundNotification:) + name:kGDTCORApplicationWillEnterForegroundNotification + object:nil]; + + [notificationCenter addObserver:self + selector:@selector(applicationWillTerminateNotification:) + name:kGDTCORApplicationWillTerminateNotification + object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)applicationDidEnterBackgroundNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is backgrounding."); + [[GDTCORTransformer sharedInstance] appWillBackground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is backgrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillBackground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillBackground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is backgrounding."); + [[GDTCORRegistrar sharedInstance] appWillBackground:application]; + } +} + +- (void)applicationWillEnterForegroundNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is foregrounding."); + [[GDTCORTransformer sharedInstance] appWillForeground:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is foregrounding."); + [[GDTCORUploadCoordinator sharedInstance] appWillForeground:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillForeground:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is foregrounding."); + [[GDTCORRegistrar sharedInstance] appWillForeground:application]; + } +} + +- (void)applicationWillTerminateNotification:(NSNotification *)notification { + GDTCORApplication *application = [GDTCORApplication sharedApplication]; + if ([[GDTCORTransformer sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORTransformer that the app is terminating."); + [[GDTCORTransformer sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORUploadCoordinator sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORUploadCoordinator that the app is terminating."); + [[GDTCORUploadCoordinator sharedInstance] appWillTerminate:application]; + } + if ([[GDTCORRegistrar sharedInstance] respondsToSelector:@selector(appWillTerminate:)]) { + GDTCORLogDebug(@"%@", @"Signaling GDTCORRegistrar that the app is terminating."); + [[GDTCORRegistrar sharedInstance] appWillTerminate:application]; + } +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m new file mode 100644 index 0000000..9da40db --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORLogSourceMetrics.m @@ -0,0 +1,184 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +static NSString *const kDroppedEventCounterByLogSource = @"droppedEventCounterByLogSource"; + +typedef NSDictionary GDTCORDroppedEventCounter; + +@interface GDTCORLogSourceMetrics () + +/// A dictionary of log sources that map to counters that reflect the number of events dropped for a +/// given set of reasons (``GDTCOREventDropReason``). +@property(nonatomic, readonly) + NSDictionary *droppedEventCounterByLogSource; + +@end + +@implementation GDTCORLogSourceMetrics + ++ (instancetype)metrics { + return [[self alloc] initWithDroppedEventCounterByLogSource:@{}]; +} + ++ (instancetype)metricsWithEvents:(NSArray *)events + droppedForReason:(GDTCOREventDropReason)reason { + NSMutableDictionary *eventCounterByLogSource = + [NSMutableDictionary dictionary]; + + for (GDTCOREvent *event in [events copy]) { + // Dropped events with a `nil` or empty mapping ID (log source) are not recorded. + if (event.mappingID.length == 0) { + continue; + } + + // Get the dropped event counter for the event's mapping ID (log source). + // If the dropped event counter for this event's mapping ID is `nil`, + // an empty mutable counter is returned. + NSMutableDictionary *eventCounter = [NSMutableDictionary + dictionaryWithDictionary:eventCounterByLogSource[event.mappingID] ?: @{}]; + + // Increment the log source metrics for the given reason. + NSInteger currentEventCountForReason = [eventCounter[@(reason)] integerValue]; + NSInteger updatedEventCountForReason = currentEventCountForReason + 1; + + eventCounter[@(reason)] = @(updatedEventCountForReason); + + // Update the mapping ID's (log source's) event counter with an immutable + // copy of the updated counter. + eventCounterByLogSource[event.mappingID] = [eventCounter copy]; + } + + return [[self alloc] initWithDroppedEventCounterByLogSource:[eventCounterByLogSource copy]]; +} + +- (instancetype)initWithDroppedEventCounterByLogSource: + (NSDictionary *)droppedEventCounterByLogSource { + self = [super init]; + if (self) { + _droppedEventCounterByLogSource = [droppedEventCounterByLogSource copy]; + } + return self; +} + +- (GDTCORLogSourceMetrics *)logSourceMetricsByMergingWithLogSourceMetrics: + (GDTCORLogSourceMetrics *)metrics { + // Create new log source metrics by merging the current metrics with the given metrics. + NSDictionary *mergedEventCounterByLogSource = [[self + class] dictionaryByMergingDictionary:self.droppedEventCounterByLogSource + withOtherDictionary:metrics.droppedEventCounterByLogSource + uniquingKeysWithBlock:^NSDictionary *(NSDictionary *eventCounter1, + NSDictionary *eventCounter2) { + return [[self class] + dictionaryByMergingDictionary:eventCounter1 + withOtherDictionary:eventCounter2 + uniquingKeysWithBlock:^NSNumber *(NSNumber *eventCount1, + NSNumber *eventCount2) { + return @(eventCount1.integerValue + eventCount2.integerValue); + }]; + }]; + + return + [[[self class] alloc] initWithDroppedEventCounterByLogSource:mergedEventCounterByLogSource]; +} + +/// Creates a new dictionary by merging together two given dictionaries. +/// @param dictionary A dictionary for merging. +/// @param otherDictionary Another dictionary for merging. +/// @param block A block that is called with the values for any duplicate keys that are encountered. +/// The block returns the desired value for the merged dictionary. ++ (NSDictionary *)dictionaryByMergingDictionary:(NSDictionary *)dictionary + withOtherDictionary:(NSDictionary *)otherDictionary + uniquingKeysWithBlock:(id (^)(id value1, id value2))block { + NSMutableDictionary *mergedDictionary = [NSMutableDictionary dictionaryWithDictionary:dictionary]; + + [otherDictionary enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + if (mergedDictionary[key] != nil) { + // The key exists in both given dictionaries so combine the corresponding values with the + // given block. + id newValue = block(mergedDictionary[key], obj); + mergedDictionary[key] = newValue; + } else { + mergedDictionary[key] = obj; + } + }]; + + return [mergedDictionary copy]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)otherMetrics { + return [_droppedEventCounterByLogSource + isEqualToDictionary:otherMetrics.droppedEventCounterByLogSource]; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)object]; +} + +- (NSUInteger)hash { + return [_droppedEventCounterByLogSource hash]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + NSDictionary *droppedEventCounterByLogSource = + [coder decodeObjectOfClasses: + [NSSet setWithArray:@[ NSDictionary.class, NSString.class, NSNumber.class ]] + forKey:kDroppedEventCounterByLogSource]; + + if (!droppedEventCounterByLogSource || + ![droppedEventCounterByLogSource isKindOfClass:[NSDictionary class]]) { + // If any of the fields are corrupted, the initializer should fail. + return nil; + } + + return [self initWithDroppedEventCounterByLogSource:droppedEventCounterByLogSource]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.droppedEventCounterByLogSource forKey:kDroppedEventCounterByLogSource]; +} + +#pragma mark - Description + +- (NSString *)description { + return [NSString + stringWithFormat:@"%@ %@", [super description], self.droppedEventCounterByLogSource]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m new file mode 100644 index 0000000..ffbf0e1 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetrics.m @@ -0,0 +1,100 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@implementation GDTCORMetrics + +- (instancetype)initWithCollectionStartDate:(NSDate *)collectionStartDate + collectionEndDate:(NSDate *)collectionEndDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics + currentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize + bundleID:(NSString *)bundleID { + self = [super init]; + if (self) { + _collectionStartDate = [collectionStartDate copy]; + _collectionEndDate = [collectionEndDate copy]; + _logSourceMetrics = logSourceMetrics; + _currentCacheSize = currentCacheSize; + _maxCacheSize = maxCacheSize; + _bundleID = [bundleID copy]; + } + return self; +} + ++ (instancetype)metricsWithMetricsMetadata:(GDTCORMetricsMetadata *)metricsMetadata + storageMetadata:(GDTCORStorageMetadata *)storageMetadata { + // The window of collection ends at the time of creating the metrics object. + NSDate *collectionEndDate = [NSDate date]; + // The main bundle ID is associated with the created metrics. + NSString *bundleID = [[NSBundle mainBundle] bundleIdentifier] ?: @""; + + return [[GDTCORMetrics alloc] initWithCollectionStartDate:metricsMetadata.collectionStartDate + collectionEndDate:collectionEndDate + logSourceMetrics:metricsMetadata.logSourceMetrics + currentCacheSize:storageMetadata.currentCacheSize + maxCacheSize:storageMetadata.maxCacheSize + bundleID:bundleID]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToMetrics:(GDTCORMetrics *)otherMetrics { + return [self.collectionStartDate isEqualToDate:otherMetrics.collectionStartDate] && + [self.collectionEndDate isEqualToDate:otherMetrics.collectionEndDate] && + [self.logSourceMetrics isEqualToLogSourceMetrics:otherMetrics.logSourceMetrics] && + [self.bundleID isEqualToString:otherMetrics.bundleID] && + self.currentCacheSize == otherMetrics.currentCacheSize && + self.maxCacheSize == otherMetrics.maxCacheSize; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToMetrics:(GDTCORMetrics *)object]; +} + +- (NSUInteger)hash { + return [self.collectionStartDate hash] ^ [self.collectionEndDate hash] ^ + [self.logSourceMetrics hash] ^ [self.bundleID hash] ^ [@(self.currentCacheSize) hash] ^ + [@(self.maxCacheSize) hash]; +} + +#pragma mark - Description + +- (NSString *)description { + return [NSString + stringWithFormat: + @"%@ {\n\tcollectionStartDate: %@,\n\tcollectionEndDate: %@,\n\tcurrentCacheSize: " + @"%llu,\n\tmaxCacheSize: %llu,\n\tbundleID: %@,\n\tlogSourceMetrics: %@}\n", + [super description], self.collectionStartDate, self.collectionEndDate, + self.currentCacheSize, self.maxCacheSize, self.bundleID, self.logSourceMetrics]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m new file mode 100644 index 0000000..2978da7 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsController.m @@ -0,0 +1,201 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h" + +#if __has_include() +#import +#else +#import "FBLPromises.h" +#endif + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@interface GDTCORMetricsController () +/// The underlying storage object where metrics are stored. +@property(nonatomic) id storage; + +@end + +@implementation GDTCORMetricsController + ++ (void)load { +#if GDT_TEST + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetTest]; +#endif // GDT_TEST + // Only the Firelog backend supports metrics collection. + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetCSH]; + [[GDTCORRegistrar sharedInstance] registerMetricsController:[self sharedInstance] + target:kGDTCORTargetFLL]; +} + ++ (instancetype)sharedInstance { + static id sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[self alloc] initWithStorage:[GDTCORFlatFileStorage sharedInstance]]; + }); + return sharedInstance; +} + +- (instancetype)initWithStorage:(id)storage { + self = [super init]; + if (self) { + _storage = storage; + } + return self; +} + +- (nonnull FBLPromise *)logEventsDroppedForReason:(GDTCOREventDropReason)reason + events:(nonnull NSSet *)events { + // No-op if there are no events to log. + if ([events count] == 0) { + return [FBLPromise resolvedWith:nil]; + } + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + GDTCORLogSourceMetrics *logSourceMetrics = + [GDTCORLogSourceMetrics metricsWithEvents:[events allObjects] droppedForReason:reason]; + + if (metricsMetadata) { + GDTCORLogSourceMetrics *updatedLogSourceMetrics = [metricsMetadata.logSourceMetrics + logSourceMetricsByMergingWithLogSourceMetrics:logSourceMetrics]; + + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[metricsMetadata collectionStartDate] + logSourceMetrics:updatedLogSourceMetrics]; + } else { + // There was an error (e.g. empty storage); `metricsMetadata` is nil. + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:logSourceMetrics]; + } + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler]; +} + +- (nonnull FBLPromise *)getAndResetMetrics { + __block GDTCORMetricsMetadata *_Nullable snapshottedMetricsMetadata = nil; + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + if (metricsMetadata) { + snapshottedMetricsMetadata = metricsMetadata; + } else { + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + } + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:[GDTCORLogSourceMetrics metrics]]; + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler] + .validate(^BOOL(NSNull *__unused _) { + // Break and reject the promise chain when storage contains no metrics + // metadata. + return snapshottedMetricsMetadata != nil; + }) + .then(^FBLPromise *(NSNull *__unused _) { + // Fetch and return storage metadata (needed for metrics). + return [self.storage fetchStorageMetadata]; + }) + .then(^GDTCORMetrics *(GDTCORStorageMetadata *storageMetadata) { + // Use the fetched metrics & storage metadata to create and return a + // complete metrics object. + return [GDTCORMetrics metricsWithMetricsMetadata:snapshottedMetricsMetadata + storageMetadata:storageMetadata]; + }); +} + +- (nonnull FBLPromise *)offerMetrics:(nonnull GDTCORMetrics *)metrics { + // No-op if there are no metrics to offer. + if (metrics == nil) { + return [FBLPromise resolvedWith:nil]; + } + + __auto_type handler = ^GDTCORMetricsMetadata *(GDTCORMetricsMetadata *_Nullable metricsMetadata, + NSError *_Nullable fetchError) { + if (metricsMetadata) { + if (metrics.collectionStartDate.timeIntervalSince1970 <= + metricsMetadata.collectionStartDate.timeIntervalSince1970) { + // If the metrics to append are older than the metrics represented by + // the currently stored metrics, then return a new metadata object that + // incorporates the data from the given metrics. + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[metrics collectionStartDate] + logSourceMetrics:[metricsMetadata.logSourceMetrics + logSourceMetricsByMergingWithLogSourceMetrics: + metrics.logSourceMetrics]]; + } else { + // This catches an edge case where the given metrics to append are + // newer than metrics represented by the currently stored metrics + // metadata. In this case, return the existing metadata object as the + // given metrics are assumed to already be accounted for by the + // currently stored metadata. + return metricsMetadata; + } + } else { + // There was an error (e.g. empty storage); `metricsMetadata` is nil. + GDTCORLogDebug(@"Error fetching metrics metadata: %@", fetchError); + + NSDate *now = [NSDate date]; + if (metrics.collectionStartDate.timeIntervalSince1970 <= now.timeIntervalSince1970) { + // The given metrics are were recorded up until now. They wouldn't + // be offered if they were successfully uploaded so their + // corresponding metadata can be safely placed back in storage. + return [GDTCORMetricsMetadata metadataWithCollectionStartDate:metrics.collectionStartDate + logSourceMetrics:metrics.logSourceMetrics]; + } else { + // This catches an edge case where the given metrics are from the + // future. If this occurs, ignore them and store an empty metadata + // object intended to track metrics metadata from this time forward. + return [GDTCORMetricsMetadata + metadataWithCollectionStartDate:[NSDate date] + logSourceMetrics:[GDTCORLogSourceMetrics metrics]]; + } + } + }; + + return [_storage fetchAndUpdateMetricsWithHandler:handler]; +} + +#pragma mark - GDTCORStorageDelegate + +- (void)storage:(id)storage + didRemoveExpiredEvents:(nonnull NSSet *)events { + [self logEventsDroppedForReason:GDTCOREventDropReasonMessageTooOld events:events]; +} + +- (void)storage:(nonnull id)storage + didDropEvent:(nonnull GDTCOREvent *)event { + [self logEventsDroppedForReason:GDTCOREventDropReasonStorageFull + events:[NSSet setWithObject:event]]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m new file mode 100644 index 0000000..624c8c5 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORMetricsMetadata.m @@ -0,0 +1,96 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h" + +static NSString *const kCollectionStartDate = @"collectionStartDate"; +static NSString *const kLogSourceMetrics = @"logSourceMetrics"; + +@implementation GDTCORMetricsMetadata + ++ (instancetype)metadataWithCollectionStartDate:(NSDate *)collectedSinceDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics { + return [[self alloc] initWithCollectionStartDate:collectedSinceDate + logSourceMetrics:logSourceMetrics]; +} + +- (instancetype)initWithCollectionStartDate:(NSDate *)collectionStartDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics { + self = [super init]; + if (self) { + _collectionStartDate = [collectionStartDate copy]; + _logSourceMetrics = logSourceMetrics; + } + return self; +} + +#pragma mark - Equality + +- (BOOL)isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)otherMetricsMetadata { + return [self.collectionStartDate isEqualToDate:otherMetricsMetadata.collectionStartDate] && + [self.logSourceMetrics isEqualToLogSourceMetrics:otherMetricsMetadata.logSourceMetrics]; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)object]; +} + +- (NSUInteger)hash { + return [self.collectionStartDate hash] ^ [self.logSourceMetrics hash]; +} + +#pragma mark - NSSecureCoding + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + NSDate *collectionStartDate = [coder decodeObjectOfClass:[NSDate class] + forKey:kCollectionStartDate]; + GDTCORLogSourceMetrics *logSourceMetrics = + [coder decodeObjectOfClass:[GDTCORLogSourceMetrics class] forKey:kLogSourceMetrics]; + + if (!collectionStartDate || !logSourceMetrics || + ![collectionStartDate isKindOfClass:[NSDate class]] || + ![logSourceMetrics isKindOfClass:[GDTCORLogSourceMetrics class]]) { + // If any of the fields are corrupted, the initializer should fail. + return nil; + } + + return [self initWithCollectionStartDate:collectionStartDate logSourceMetrics:logSourceMetrics]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeObject:self.collectionStartDate forKey:kCollectionStartDate]; + [coder encodeObject:self.logSourceMetrics forKey:kLogSourceMetrics]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m new file mode 100644 index 0000000..0729bde --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m @@ -0,0 +1,566 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#ifdef GDTCOR_VERSION +#define STR(x) STR_EXPAND(x) +#define STR_EXPAND(x) #x +NSString *const kGDTCORVersion = @STR(GDTCOR_VERSION); +#else +NSString *const kGDTCORVersion = @"Unknown"; +#endif // GDTCOR_VERSION + +const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid = 0; + +NSString *const kGDTCORApplicationDidEnterBackgroundNotification = + @"GDTCORApplicationDidEnterBackgroundNotification"; + +NSString *const kGDTCORApplicationWillEnterForegroundNotification = + @"GDTCORApplicationWillEnterForegroundNotification"; + +NSString *const kGDTCORApplicationWillTerminateNotification = + @"GDTCORApplicationWillTerminateNotification"; + +NSURL *GDTCORRootDirectory(void) { + static NSURL *GDTPath; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSString *cachePath = + NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES)[0]; + GDTPath = + [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/google-sdks-events", cachePath]]; + GDTCORLogDebug(@"GDT's state will be saved to: %@", GDTPath); + }); + NSError *error; + [[NSFileManager defaultManager] createDirectoryAtPath:GDTPath.path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + GDTCORAssert(error == nil, @"There was an error creating GDT's path"); + return GDTPath; +} + +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags) { +#if !TARGET_OS_WATCH + BOOL reachable = + (flags & kSCNetworkReachabilityFlagsReachable) == kSCNetworkReachabilityFlagsReachable; + BOOL connectionRequired = (flags & kSCNetworkReachabilityFlagsConnectionRequired) == + kSCNetworkReachabilityFlagsConnectionRequired; + return reachable && !connectionRequired; +#else + return (flags & kGDTCORNetworkReachabilityFlagsReachable) == + kGDTCORNetworkReachabilityFlagsReachable; +#endif +} + +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags) { +#if TARGET_OS_IOS + return (flags & kSCNetworkReachabilityFlagsIsWWAN) == kSCNetworkReachabilityFlagsIsWWAN; +#else + // Assume network connection not WWAN on macOS, tvOS, watchOS. + return NO; +#endif // TARGET_OS_IOS +} + +GDTCORNetworkType GDTCORNetworkTypeMessage(void) { +#if !TARGET_OS_WATCH + SCNetworkReachabilityFlags reachabilityFlags = [GDTCORReachability currentFlags]; + if ((reachabilityFlags & kSCNetworkReachabilityFlagsReachable) == + kSCNetworkReachabilityFlagsReachable) { + if (GDTCORReachabilityFlagsContainWWAN(reachabilityFlags)) { + return GDTCORNetworkTypeMobile; + } else { + return GDTCORNetworkTypeWIFI; + } + } +#endif + return GDTCORNetworkTypeUNKNOWN; +} + +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage(void) { +// TODO(Xcode 15): When Xcode 15 is the minimum supported Xcode version, +// it will be unnecessary to check if `TARGET_OS_VISION` is defined. +#if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) + static NSDictionary *CTRadioAccessTechnologyToNetworkSubTypeMessage; + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + CTRadioAccessTechnologyToNetworkSubTypeMessage = @{ + CTRadioAccessTechnologyGPRS : @(GDTCORNetworkMobileSubtypeGPRS), + CTRadioAccessTechnologyEdge : @(GDTCORNetworkMobileSubtypeEdge), + CTRadioAccessTechnologyWCDMA : @(GDTCORNetworkMobileSubtypeWCDMA), + CTRadioAccessTechnologyHSDPA : @(GDTCORNetworkMobileSubtypeHSDPA), + CTRadioAccessTechnologyHSUPA : @(GDTCORNetworkMobileSubtypeHSUPA), + CTRadioAccessTechnologyCDMA1x : @(GDTCORNetworkMobileSubtypeCDMA1x), + CTRadioAccessTechnologyCDMAEVDORev0 : @(GDTCORNetworkMobileSubtypeCDMAEVDORev0), + CTRadioAccessTechnologyCDMAEVDORevA : @(GDTCORNetworkMobileSubtypeCDMAEVDORevA), + CTRadioAccessTechnologyCDMAEVDORevB : @(GDTCORNetworkMobileSubtypeCDMAEVDORevB), + CTRadioAccessTechnologyeHRPD : @(GDTCORNetworkMobileSubtypeHRPD), + CTRadioAccessTechnologyLTE : @(GDTCORNetworkMobileSubtypeLTE), + }; + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + NSString *networkCurrentRadioAccessTechnology; +#if TARGET_OS_MACCATALYST + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } +#else // TARGET_OS_MACCATALYST + NSDictionary *networkCurrentRadioAccessTechnologyDict = + networkInfo.serviceCurrentRadioAccessTechnology; + if (networkCurrentRadioAccessTechnologyDict.count) { + // In iOS 12, multiple radio technologies can be captured. We prefer not particular radio + // tech to another, so we'll just return the first value in the dictionary. + networkCurrentRadioAccessTechnology = networkCurrentRadioAccessTechnologyDict.allValues[0]; + } +#endif // TARGET_OS_MACCATALYST + if (networkCurrentRadioAccessTechnology) { + NSNumber *networkMobileSubtype = + CTRadioAccessTechnologyToNetworkSubTypeMessage[networkCurrentRadioAccessTechnology]; + return networkMobileSubtype.intValue; + } else { + return GDTCORNetworkMobileSubtypeUNKNOWN; + } +#else // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) + return GDTCORNetworkMobileSubtypeUNKNOWN; +#endif // TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) +} + +NSString *_Nonnull GDTCORDeviceModel(void) { + static NSString *deviceModel = @"Unknown"; + +#if TARGET_OS_IOS || TARGET_OS_TV + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + size_t size; + char *keyToExtract = "hw.machine"; + sysctlbyname(keyToExtract, NULL, &size, NULL, 0); + if (size > 0) { + char *machine = calloc(1, size); + sysctlbyname(keyToExtract, machine, &size, NULL, 0); + deviceModel = [NSString stringWithCString:machine encoding:NSUTF8StringEncoding]; + free(machine); + } else { + deviceModel = [UIDevice currentDevice].model; + } + }); +#endif + + return deviceModel; +} + +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *filePath, + NSError *_Nullable *error) { + BOOL result = NO; + if (filePath.length > 0) { + // TODO(ncooke3): For future cleanup– this API shouldn't touch the file + // system unless it successfully encoded the given object. + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:error]; + if (result == NO || *error) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *error); + return nil; + } + } + NSData *resultData; + resultData = [NSKeyedArchiver archivedDataWithRootObject:obj + requiringSecureCoding:YES + error:error]; + if (resultData == nil || (error != NULL && *error != nil)) { + GDTCORLogDebug(@"Encoding an object failed: %@", *error); + return nil; + } + if (filePath.length > 0) { + result = [resultData writeToFile:filePath options:NSDataWritingAtomic error:error]; + if (result == NO || (error != NULL && *error != nil)) { + if (error != NULL && *error != nil) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *error); + } else { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@", filePath); + } + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + return resultData; +} + +id _Nullable GDTCORDecodeArchiveAtPath(Class archiveClass, + NSString *_Nonnull archivePath, + NSError **_Nonnull error) { + NSData *data = [NSData dataWithContentsOfFile:archivePath options:0 error:error]; + if (data == nil) { + // Reading the file failed and `error` will be populated. + return nil; + } + + return GDTCORDecodeArchive(archiveClass, data, error); +} + +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSData *_Nonnull archiveData, + NSError **_Nonnull error) { + return [NSKeyedUnarchiver unarchivedObjectOfClass:archiveClass fromData:archiveData error:error]; +} + +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError) { + BOOL result = NO; + if (filePath.length > 0) { + result = [[NSFileManager defaultManager] + createDirectoryAtPath:[filePath stringByDeletingLastPathComponent] + withIntermediateDirectories:YES + attributes:nil + error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to create directory failed: path:%@ error:%@", filePath, *outError); + return result; + } + } + + if (filePath.length > 0) { + result = [data writeToFile:filePath options:NSDataWritingAtomic error:outError]; + if (result == NO || *outError) { + GDTCORLogDebug(@"Attempt to write archive failed: path:%@ error:%@", filePath, *outError); + } else { + GDTCORLogDebug(@"Writing archive succeeded: %@", filePath); + } + } + + return result; +} + +@interface GDTCORApplication () +/** + Private flag to match the existing `readonly` public flag. This will be accurate for all platforms, + since we handle each platform's lifecycle notifications separately. + */ +@property(atomic, readwrite) BOOL isRunningInBackground; + +@end + +@implementation GDTCORApplication + +#if TARGET_OS_WATCH +/** A dispatch queue on which all task semaphores will populate and remove from + * gBackgroundIdentifierToSemaphoreMap. + */ +static dispatch_queue_t gSemaphoreQueue; + +/** For mapping backgroundIdentifier to task semaphore. */ +static NSMutableDictionary *gBackgroundIdentifierToSemaphoreMap; +#endif + ++ (void)load { + GDTCORLogDebug( + @"%@", @"GDT is initializing. Please note that if you quit the app via the " + "debugger and not through a lifecycle event, event data will remain on disk but " + "storage won't have a reference to them since the singleton wasn't saved to disk."); +#if TARGET_OS_IOS || TARGET_OS_TV + // If this asserts, please file a bug at https://github.com/firebase/firebase-ios-sdk/issues. + GDTCORFatalAssert( + GDTCORBackgroundIdentifierInvalid == UIBackgroundTaskInvalid, + @"GDTCORBackgroundIdentifierInvalid and UIBackgroundTaskInvalid should be the same."); +#endif + [self sharedApplication]; +} + ++ (void)initialize { +#if TARGET_OS_WATCH + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gSemaphoreQueue = dispatch_queue_create("com.google.GDTCORApplication", DISPATCH_QUEUE_SERIAL); + GDTCORLogDebug( + @"%@", + @"GDTCORApplication is initializing on watchOS, gSemaphoreQueue has been initialized."); + gBackgroundIdentifierToSemaphoreMap = [[NSMutableDictionary alloc] init]; + GDTCORLogDebug(@"%@", @"GDTCORApplication is initializing on watchOS, " + @"gBackgroundIdentifierToSemaphoreMap has been initialized."); + }); +#endif +} + ++ (nullable GDTCORApplication *)sharedApplication { + static GDTCORApplication *application; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + application = [[GDTCORApplication alloc] init]; + }); + return application; +} + +- (instancetype)init { + self = [super init]; + if (self) { + // This class will be instantiated in the foreground. + _isRunningInBackground = NO; + +#if TARGET_OS_IOS || TARGET_OS_TV + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UIApplicationDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UIApplicationWillEnterForegroundNotification + object:nil]; + + NSString *name = UIApplicationWillTerminateNotification; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillTerminate:) + name:name + object:nil]; + +#if defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + if (@available(iOS 13, tvOS 13.0, *)) { + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:UISceneWillEnterForegroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:UISceneWillDeactivateNotification + object:nil]; + } +#endif // defined(__IPHONE_13_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000 + +#elif TARGET_OS_OSX + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(macOSApplicationWillTerminate:) + name:NSApplicationWillTerminateNotification + object:nil]; + +#elif TARGET_OS_WATCH + // TODO: Notification on watchOS platform is currently posted by strings which are frangible. + // TODO: Needs improvements here. + NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:@"UIApplicationDidEnterBackgroundNotification" + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:@"UIApplicationWillEnterForegroundNotification" + object:nil]; + + // Adds observers for app extension on watchOS platform + [notificationCenter addObserver:self + selector:@selector(iOSApplicationDidEnterBackground:) + name:NSExtensionHostDidEnterBackgroundNotification + object:nil]; + [notificationCenter addObserver:self + selector:@selector(iOSApplicationWillEnterForeground:) + name:NSExtensionHostWillEnterForegroundNotification + object:nil]; +#endif + } + return self; +} + +#if TARGET_OS_WATCH +/** Generates and maps a unique background identifier to the given semaphore. + * + * @param semaphore The semaphore to map. + * @return A unique GDTCORBackgroundIdentifier mapped to the given semaphore. + */ ++ (GDTCORBackgroundIdentifier)createAndMapBackgroundIdentifierToSemaphore: + (dispatch_semaphore_t)semaphore { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + if (queue && map) { + dispatch_sync(queue, ^{ + bgID = arc4random(); + NSNumber *bgIDNumber = @(bgID); + while (bgID == GDTCORBackgroundIdentifierInvalid || map[bgIDNumber]) { + bgID = arc4random(); + bgIDNumber = @(bgID); + } + map[bgIDNumber] = semaphore; + }); + } + return bgID; +} + +/** Returns the semaphore mapped to given bgID and removes the value from the map. + * + * @param bgID The unique NSUInteger as GDTCORBackgroundIdentifier. + * @return The semaphore mapped by given bgID. + */ ++ (dispatch_semaphore_t)semaphoreForBackgroundIdentifier:(GDTCORBackgroundIdentifier)bgID { + __block dispatch_semaphore_t semaphore; + dispatch_queue_t queue = gSemaphoreQueue; + NSMutableDictionary *map = gBackgroundIdentifierToSemaphoreMap; + NSNumber *bgIDNumber = @(bgID); + if (queue && map) { + dispatch_sync(queue, ^{ + semaphore = map[bgIDNumber]; + [map removeObjectForKey:bgIDNumber]; + }); + } + return semaphore; +} +#endif + +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^)(void))handler { + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; +#if !TARGET_OS_WATCH + bgID = [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name + expirationHandler:handler]; +#if !NDEBUG + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating background task with name:%@ bgID:%ld", name, (long)bgID); + } +#endif // !NDEBUG +#elif TARGET_OS_WATCH + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + bgID = [GDTCORApplication createAndMapBackgroundIdentifierToSemaphore:semaphore]; + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Creating activity with name:%@ bgID:%ld on watchOS.", name, (long)bgID); + } + [[self sharedNSProcessInfoForBackgroundTask] + performExpiringActivityWithReason:name + usingBlock:^(BOOL expired) { + if (expired) { + if (handler) { + handler(); + } + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug( + @"Activity with name:%@ bgID:%ld on watchOS is expiring.", + name, (long)bgID); + } else { + dispatch_semaphore_wait( + semaphore, + dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC)); + } + }]; +#endif + return bgID; +} + +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID { +#if !TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + GDTCORLogDebug(@"Ending background task with ID:%ld was successful", (long)bgID); + [[self sharedApplicationForBackgroundTask] endBackgroundTask:bgID]; + return; + } +#elif TARGET_OS_WATCH + if (bgID != GDTCORBackgroundIdentifierInvalid) { + dispatch_semaphore_t semaphore = [GDTCORApplication semaphoreForBackgroundIdentifier:bgID]; + GDTCORLogDebug(@"Ending activity with bgID:%ld on watchOS.", (long)bgID); + if (semaphore) { + dispatch_semaphore_signal(semaphore); + GDTCORLogDebug(@"Signaling semaphore with bgID:%ld on watchOS.", (long)bgID); + } else { + GDTCORLogDebug(@"Semaphore with bgID:%ld is nil on watchOS.", (long)bgID); + } + } +#endif // !TARGET_OS_WATCH +} + +#pragma mark - App environment helpers + +- (BOOL)isAppExtension { + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +} + +/** Returns a UIApplication or NSProcessInfo instance if on the appropriate platform. + * + * @return The shared UIApplication or NSProcessInfo if on the appropriate platform. + */ +#if TARGET_OS_IOS || TARGET_OS_TV +- (nullable UIApplication *)sharedApplicationForBackgroundTask { +#elif TARGET_OS_WATCH +- (nullable NSProcessInfo *)sharedNSProcessInfoForBackgroundTask { +#else +- (nullable id)sharedApplicationForBackgroundTask { +#endif + id sharedInstance = nil; +#if TARGET_OS_IOS || TARGET_OS_TV + if (![self isAppExtension]) { + Class uiApplicationClass = NSClassFromString(@"UIApplication"); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedInstance = [uiApplicationClass sharedApplication]; + } + } +#elif TARGET_OS_WATCH + sharedInstance = [NSProcessInfo processInfo]; +#endif + return sharedInstance; +} + +#pragma mark - UIApplicationDelegate and WKExtensionDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH +- (void)iOSApplicationDidEnterBackground:(NSNotification *)notif { + _isRunningInBackground = YES; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is backgrounding."); + [notifCenter postNotificationName:kGDTCORApplicationDidEnterBackgroundNotification object:nil]; +} + +- (void)iOSApplicationWillEnterForeground:(NSNotification *)notif { + _isRunningInBackground = NO; + + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is foregrounding."); + [notifCenter postNotificationName:kGDTCORApplicationWillEnterForegroundNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + +#pragma mark - UIApplicationDelegate + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)iOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - NSApplicationDelegate + +#if TARGET_OS_OSX +- (void)macOSApplicationWillTerminate:(NSNotification *)notif { + NSNotificationCenter *notifCenter = [NSNotificationCenter defaultCenter]; + GDTCORLogDebug(@"%@", @"GDTCORPlatform is sending a notif that the app is terminating."); + [notifCenter postNotificationName:kGDTCORApplicationWillTerminateNotification object:nil]; +} +#endif // TARGET_OS_OSX + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m new file mode 100644 index 0000000..5e15e8f --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORProductData.m @@ -0,0 +1,77 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h" + +@implementation GDTCORProductData + +- (instancetype)initWithProductID:(int32_t)productID { + self = [super init]; + if (self) { + _productID = productID; + } + return self; +} + +- (nonnull id)copyWithZone:(nullable NSZone *)zone { + return [[[self class] alloc] initWithProductID:self.productID]; +} + +#pragma mark - Equality + +- (BOOL)isEqualToProductData:(GDTCORProductData *)otherProductData { + return self.productID == otherProductData.productID; +} + +- (BOOL)isEqual:(nullable id)object { + if (object == nil) { + return NO; + } + + if (self == object) { + return YES; + } + + if (![object isKindOfClass:[self class]]) { + return NO; + } + + return [self isEqualToProductData:(GDTCORProductData *)object]; +} + +- (NSUInteger)hash { + return self.productID; +} + +#pragma mark - NSSecureCoding + +/// NSCoding key for `productID` property. +static NSString *kProductIDKey = @"GDTCORProductDataProductIDKey"; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (nullable instancetype)initWithCoder:(nonnull NSCoder *)coder { + int32_t productID = [coder decodeInt32ForKey:kProductIDKey]; + return [self initWithProductID:productID]; +} + +- (void)encodeWithCoder:(nonnull NSCoder *)coder { + [coder encodeInt32:self.productID forKey:kProductIDKey]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m new file mode 100644 index 0000000..43811e6 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORReachability.m @@ -0,0 +1,125 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import + +/** Sets the _callbackFlag ivar whenever the network changes. + * + * @param reachability The reachability object calling back. + * @param flags The new flag values. + * @param info Any data that might be passed in by the callback. + */ +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info); + +@implementation GDTCORReachability { + /** The reachability object. */ + GDTCORNetworkReachabilityRef _reachabilityRef; + + /** The queue on which callbacks and all work will occur. */ + dispatch_queue_t _reachabilityQueue; + + /** Flags specified by reachability callbacks. */ + GDTCORNetworkReachabilityFlags _callbackFlags; +} + ++ (void)initialize { + [self sharedInstance]; +} + ++ (instancetype)sharedInstance { + static GDTCORReachability *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORReachability alloc] init]; + }); + return sharedInstance; +} + ++ (GDTCORNetworkReachabilityFlags)currentFlags { + __block GDTCORNetworkReachabilityFlags currentFlags; +#if !TARGET_OS_WATCH + dispatch_sync([GDTCORReachability sharedInstance] -> _reachabilityQueue, ^{ + GDTCORReachability *reachability = [GDTCORReachability sharedInstance]; + currentFlags = + reachability->_callbackFlags ? reachability->_callbackFlags : reachability->_flags; + GDTCORLogDebug(@"Initial reachability flags determined: %d", currentFlags); + }); +#else + currentFlags = kGDTCORNetworkReachabilityFlagsReachable; +#endif + return currentFlags; +} + +- (instancetype)init { + self = [super init]; +#if !TARGET_OS_WATCH + if (self) { + struct sockaddr_in zeroAddress; + bzero(&zeroAddress, sizeof(zeroAddress)); + zeroAddress.sin_len = sizeof(zeroAddress); + zeroAddress.sin_family = AF_INET; + + _reachabilityQueue = + dispatch_queue_create("com.google.GDTCORReachability", DISPATCH_QUEUE_SERIAL); + _reachabilityRef = SCNetworkReachabilityCreateWithAddress( + kCFAllocatorDefault, (const struct sockaddr *)&zeroAddress); + Boolean success = SCNetworkReachabilitySetDispatchQueue(_reachabilityRef, _reachabilityQueue); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", @"The reachability queue wasn't set."); + } + success = SCNetworkReachabilitySetCallback(_reachabilityRef, GDTCORReachabilityCallback, NULL); + if (!success) { + GDTCORLogWarning(GDTCORMCWReachabilityFailed, @"%@", + @"The reachability callback wasn't set."); + } + + // Get the initial set of flags. + dispatch_async(_reachabilityQueue, ^{ + Boolean valid = SCNetworkReachabilityGetFlags(self->_reachabilityRef, &self->_flags); + if (!valid) { + GDTCORLogDebug(@"%@", @"Determining reachability failed."); + self->_flags = 0; + } + }); + } +#endif + return self; +} + +- (void)setCallbackFlags:(GDTCORNetworkReachabilityFlags)flags { + if (_callbackFlags != flags) { + self->_callbackFlags = flags; + } +} + +@end + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +static void GDTCORReachabilityCallback(GDTCORNetworkReachabilityRef reachability, + GDTCORNetworkReachabilityFlags flags, + void *info) { +#pragma clang diagnostic pop + GDTCORLogDebug(@"Reachability changed, new flags: %d", flags); + [[GDTCORReachability sharedInstance] setCallbackFlags:flags]; +} diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m new file mode 100644 index 0000000..5aefd6c --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORRegistrar.m @@ -0,0 +1,194 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target) { + return [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; +} + +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target) { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[@(target)]; + if ([storage conformsToProtocol:@protocol(GDTCORStoragePromiseProtocol)]) { + return storage; + } else { + return nil; + } +} + +id _Nullable GDTCORMetricsControllerInstanceForTarget( + GDTCORTarget target) { + return [GDTCORRegistrar sharedInstance].targetToMetricsController[@(target)]; +} + +@implementation GDTCORRegistrar + +// Manaully synthesize properties declared in `GDTCORRegistrar_Private.h` category. +@synthesize targetToUploader = _targetToUploader; +@synthesize targetToStorage = _targetToStorage; +@synthesize targetToMetricsController = _targetToMetricsController; + ++ (instancetype)sharedInstance { + static GDTCORRegistrar *sharedInstance; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedInstance = [[GDTCORRegistrar alloc] init]; + }); + return sharedInstance; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _registrarQueue = dispatch_queue_create("com.google.GDTCORRegistrar", DISPATCH_QUEUE_SERIAL); + _targetToUploader = [NSMutableDictionary dictionary]; + _targetToStorage = [NSMutableDictionary dictionary]; + _targetToMetricsController = [NSMutableDictionary dictionary]; + } + return self; +} + +- (void)registerUploader:(id)backend target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered an uploader: %@ for target:%ld", backend, (long)target); + strongSelf->_targetToUploader[@(target)] = backend; + } + }); +} + +- (void)registerStorage:(id)storage target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered storage: %@ for target:%ld", storage, (long)target); + strongSelf->_targetToStorage[@(target)] = storage; + [self setMetricsControllerAsStorageDelegateForTarget:target]; + } + }); +} + +- (void)registerMetricsController:(id)metricsController + target:(GDTCORTarget)target { + __weak GDTCORRegistrar *weakSelf = self; + dispatch_async(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + GDTCORLogDebug(@"Registered metrics controller: %@ for target:%ld", metricsController, + (long)target); + strongSelf->_targetToMetricsController[@(target)] = metricsController; + [self setMetricsControllerAsStorageDelegateForTarget:target]; + } + }); +} + +- (NSMutableDictionary> *)targetToUploader { + __block NSMutableDictionary> *targetToUploader; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToUploader = strongSelf->_targetToUploader; + } + }); + return targetToUploader; +} + +- (NSMutableDictionary> *)targetToStorage { + __block NSMutableDictionary> *targetToStorage; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToStorage = strongSelf->_targetToStorage; + } + }); + return targetToStorage; +} + +- (NSMutableDictionary> *) + targetToMetricsController { + __block NSMutableDictionary> + *targetToMetricsController; + __weak GDTCORRegistrar *weakSelf = self; + dispatch_sync(_registrarQueue, ^{ + GDTCORRegistrar *strongSelf = weakSelf; + if (strongSelf) { + targetToMetricsController = strongSelf->_targetToMetricsController; + } + }); + return targetToMetricsController; +} + +- (void)setMetricsControllerAsStorageDelegateForTarget:(GDTCORTarget)target { + _targetToStorage[@(target)].delegate = _targetToMetricsController[@(target)]; +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillBackground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillBackground:)]) { + [uploader appWillBackground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillBackground:)]) { + [storage appWillBackground:app]; + } + } +} + +- (void)appWillForeground:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillForeground:)]) { + [uploader appWillForeground:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillForeground:)]) { + [storage appWillForeground:app]; + } + } +} + +- (void)appWillTerminate:(nonnull GDTCORApplication *)app { + NSArray> *uploaders = [self.targetToUploader allValues]; + for (id uploader in uploaders) { + if ([uploader respondsToSelector:@selector(appWillTerminate:)]) { + [uploader appWillTerminate:app]; + } + } + NSArray> *storages = [self.targetToStorage allValues]; + for (id storage in storages) { + if ([storage respondsToSelector:@selector(appWillTerminate:)]) { + [storage appWillTerminate:app]; + } + } +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m new file mode 100644 index 0000000..30915da --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageEventSelector.m @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" + +@implementation GDTCORStorageEventSelector + ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target { + return [[self alloc] initWithTarget:target eventIDs:nil mappingIDs:nil qosTiers:nil]; +} + +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers { + self = [super init]; + if (self) { + _selectedTarget = target; + _selectedEventIDs = eventIDs; + _selectedMappingIDs = mappingIDs; + _selectedQosTiers = qosTiers; + } + return self; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m new file mode 100644 index 0000000..de3b466 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORStorageMetadata.m @@ -0,0 +1,36 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h" + +@implementation GDTCORStorageMetadata + +- (instancetype)initWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize { + self = [super init]; + if (self) { + _currentCacheSize = currentCacheSize; + _maxCacheSize = maxCacheSize; + } + return self; +} + ++ (instancetype)metadataWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize { + return [[self alloc] initWithCurrentCacheSize:currentCacheSize maxCacheSize:maxCacheSize]; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m new file mode 100644 index 0000000..ece9368 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORTransformer + ++ (instancetype)sharedInstance { + static GDTCORTransformer *eventTransformer; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + eventTransformer = [[self alloc] init]; + }); + return eventTransformer; +} + +- (instancetype)init { + return [self initWithApplication:[GDTCORApplication sharedApplication]]; +} + +- (instancetype)initWithApplication:(id)application { + self = [super init]; + if (self) { + _eventWritingQueue = + dispatch_queue_create("com.google.GDTCORTransformer", DISPATCH_QUEUE_SERIAL); + _application = application; + } + return self; +} + +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event, @"You can't write a nil event"); + + __block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid; + __auto_type __weak weakApplication = self.application; + bgID = [self.application beginBackgroundTaskWithName:@"GDTTransformer" + expirationHandler:^{ + [weakApplication endBackgroundTask:bgID]; + bgID = GDTCORBackgroundIdentifierInvalid; + }]; + + __auto_type completionWrapper = ^(BOOL wasWritten, NSError *_Nullable error) { + if (completion) { + completion(wasWritten, error); + } + + if (bgID != GDTCORBackgroundIdentifierInvalid) { + // The work is done, cancel the background task if it's valid. + [weakApplication endBackgroundTask:bgID]; + } else { + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelWarnings, + @"Attempted to cancel invalid background task in GDTCORTransformer."); + } + bgID = GDTCORBackgroundIdentifierInvalid; + }; + + dispatch_async(_eventWritingQueue, ^{ + GDTCOREvent *transformedEvent = event; + for (id transformer in transformers) { + if ([transformer respondsToSelector:@selector(transformGDTEvent:)]) { + GDTCORLogDebug(@"Applying a transformer to event %@", event); + transformedEvent = [transformer transformGDTEvent:event]; + if (!transformedEvent) { + completionWrapper(NO, nil); + return; + } + } else { + GDTCORLogError(GDTCORMCETransformerDoesntImplementTransform, + @"Transformer doesn't implement transformGDTEvent: %@", transformer); + completionWrapper(NO, nil); + return; + } + } + + id storage = + [GDTCORRegistrar sharedInstance].targetToStorage[@(event.target)]; + + [storage storeEvent:transformedEvent onComplete:completionWrapper]; + }); +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m new file mode 100644 index 0000000..870ad71 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORTransport.m @@ -0,0 +1,108 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@implementation GDTCORTransport + +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target { + GDTCORAssert(mappingID.length > 0, @"A mapping ID cannot be nil or empty"); + GDTCORAssert(target > 0, @"A target cannot be negative or 0"); + if (mappingID == nil || mappingID.length == 0 || target <= 0) { + return nil; + } + self = [super init]; + if (self) { + _mappingID = mappingID; + _transformers = transformers; + _target = target; + _transformerInstance = [GDTCORTransformer sharedInstance]; + } + GDTCORLogDebug(@"Transport object created. mappingID:%@ transformers:%@ target:%ld", mappingID, + transformers, (long)target); + return self; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete: + (void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + event.qosTier = GDTCOREventQoSTelemetry; + [self sendEvent:event onComplete:completion]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + GDTCORAssert(event.qosTier != GDTCOREventQoSTelemetry, @"Use -sendTelemetryEvent, please."); + [self sendEvent:event onComplete:completion]; +} + +- (void)sendTelemetryEvent:(GDTCOREvent *)event { + [self sendTelemetryEvent:event onComplete:nil]; +} + +- (void)sendDataEvent:(GDTCOREvent *)event { + [self sendDataEvent:event onComplete:nil]; +} + +- (GDTCOREvent *)eventForTransport { + return [[GDTCOREvent alloc] initWithMappingID:_mappingID target:_target]; +} + +- (GDTCOREvent *)eventForTransportWithProductData:(GDTCORProductData *)productData { + return [[GDTCOREvent alloc] initWithMappingID:_mappingID productData:productData target:_target]; +} + +#pragma mark - Private helper methods + +/** Sends the given event through the transport pipeline. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion { + // TODO: Determine if sending an event before registration is allowed. + GDTCORAssert(event, @"You can't send a nil event"); + GDTCOREvent *copiedEvent = [event copy]; + copiedEvent.clockSnapshot = [GDTCORClock snapshot]; + [self.transformerInstance transformEvent:copiedEvent + withTransformers:_transformers + onComplete:completion]; +} + +#pragma mark - Force Category Linking + +extern void GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(void); + +/// Does nothing when called, and not meant to be called. +/// +/// This method forces the linker to include categories even if +/// users do not include the '-ObjC' linker flag in their project. ++ (void)noop { + GDTCORInclude_GDTCORLogSourceMetrics_Internal_Category(); +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m new file mode 100644 index 0000000..7d2abe2 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadBatch.m @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h" + +@implementation GDTCORUploadBatch + +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events { + self = [super init]; + if (self) { + _batchID = batchID; + _events = events; + } + return self; +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m new file mode 100644 index 0000000..cdc108a --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m @@ -0,0 +1,176 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h" + +@implementation GDTCORUploadCoordinator + ++ (instancetype)sharedInstance { + static GDTCORUploadCoordinator *sharedUploader; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + sharedUploader = [[GDTCORUploadCoordinator alloc] init]; + [sharedUploader startTimer]; + }); + return sharedUploader; +} + +- (instancetype)init { + self = [super init]; + if (self) { + _coordinationQueue = + dispatch_queue_create("com.google.GDTCORUploadCoordinator", DISPATCH_QUEUE_SERIAL); + _registrar = [GDTCORRegistrar sharedInstance]; + _timerInterval = 30 * NSEC_PER_SEC; + _timerLeeway = 5 * NSEC_PER_SEC; + } + return self; +} + +- (void)forceUploadForTarget:(GDTCORTarget)target { + dispatch_async(_coordinationQueue, ^{ + GDTCORLogDebug(@"Forcing an upload of target %ld", (long)target); + GDTCORUploadConditions conditions = [self uploadConditions]; + conditions |= GDTCORUploadConditionHighPriority; + [self uploadTargets:@[ @(target) ] conditions:conditions]; + }); +} + +#pragma mark - Private helper methods + +/** Starts a timer that checks whether or not events can be uploaded at regular intervals. It will + * check the next-upload clocks of all targets to determine if an upload attempt can be made. + */ +- (void)startTimer { + dispatch_async(_coordinationQueue, ^{ + if (self->_timer) { + // The timer has been already started. + return; + } + + // Delay the timer slightly so it doesn't run while +load calls are still running. + dispatch_time_t deadline = dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC / 2); + + self->_timer = + dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, self->_coordinationQueue); + dispatch_source_set_timer(self->_timer, deadline, self->_timerInterval, self->_timerLeeway); + + dispatch_source_set_event_handler(self->_timer, ^{ + if (![[GDTCORApplication sharedApplication] isRunningInBackground]) { + GDTCORUploadConditions conditions = [self uploadConditions]; + GDTCORLogDebug(@"%@", @"Upload timer fired"); + [self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions]; + } + }); + GDTCORLogDebug(@"%@", @"Upload timer started"); + dispatch_resume(self->_timer); + }); +} + +/** Stops the currently running timer. */ +- (void)stopTimer { + if (_timer) { + dispatch_source_cancel(_timer); + _timer = nil; + } +} + +/** Triggers the uploader implementations for the given targets to upload. + * + * @param targets An array of targets to trigger. + * @param conditions The set of upload conditions. + */ +- (void)uploadTargets:(NSArray *)targets conditions:(GDTCORUploadConditions)conditions { + dispatch_async(_coordinationQueue, ^{ + // TODO: The reachability signal may be not reliable enough to prevent an upload attempt. + // See https://developer.apple.com/videos/play/wwdc2019/712/ (49:40) for more details. + if ((conditions & GDTCORUploadConditionNoNetwork) == GDTCORUploadConditionNoNetwork) { + return; + } + for (NSNumber *target in targets) { + id uploader = self->_registrar.targetToUploader[target]; + [uploader uploadTarget:target.intValue withConditions:conditions]; + } + }); +} + +- (void)signalToStoragesToCheckExpirations { + // The same storage may be associated with several targets. Make sure to check for expirations + // only once per storage. + NSSet> *storages = + [NSSet setWithArray:[_registrar.targetToStorage allValues]]; + for (id storage in storages) { + [storage checkForExpirations]; + } +} + +/** Returns the registered storage for the given NSNumber wrapped GDTCORTarget. + * + * @param target The NSNumber wrapping of a GDTCORTarget to find the storage instance of. + * @return The storage instance for the given target. + */ +- (nullable id)storageForTarget:(NSNumber *)target { + id storage = [GDTCORRegistrar sharedInstance].targetToStorage[target]; + GDTCORAssert(storage, @"A storage must be registered for target %@", target); + return storage; +} + +/** Returns the current upload conditions after making determinations about the network connection. + * + * @return The current upload conditions. + */ +- (GDTCORUploadConditions)uploadConditions { + GDTCORNetworkReachabilityFlags currentFlags = [GDTCORReachability currentFlags]; + BOOL networkConnected = GDTCORReachabilityFlagsReachable(currentFlags); + if (!networkConnected) { + return GDTCORUploadConditionNoNetwork; + } + BOOL isWWAN = GDTCORReachabilityFlagsContainWWAN(currentFlags); + if (isWWAN) { + return GDTCORUploadConditionMobileData; + } else { + return GDTCORUploadConditionWifiData; + } +} + +#pragma mark - GDTCORLifecycleProtocol + +- (void)appWillForeground:(GDTCORApplication *)app { + // -startTimer is thread-safe. + [self startTimer]; + [self signalToStoragesToCheckExpirations]; +} + +- (void)appWillBackground:(GDTCORApplication *)app { + dispatch_async(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +- (void)appWillTerminate:(GDTCORApplication *)application { + dispatch_async(_coordinationQueue, ^{ + [self stopTimer]; + }); +} + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h new file mode 100644 index 0000000..e158a5a --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORAssert.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +/** A block type that could be run instead of normal assertion logging. No return type, no params. + */ +typedef void (^GDTCORAssertionBlock)(void); + +/** Returns the result of executing a soft-linked method present in unit tests that allows a block + * to be run instead of normal assertion logging. This helps ameliorate issues with catching + * exceptions that occur on a dispatch_queue. + * + * @return A block that can be run instead of normal assert printing. + */ +FOUNDATION_EXPORT GDTCORAssertionBlock _Nullable GDTCORAssertionBlockToRunInstead(void); + +#if defined(NS_BLOCK_ASSERTIONS) + +#define GDTCORAssert(condition, ...) \ + do { \ + } while (0); + +#define GDTCORFatalAssert(condition, ...) \ + do { \ + } while (0); + +#else // defined(NS_BLOCK_ASSERTIONS) + +/** Asserts using a console log, unless a block was specified to be run instead. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(NO, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +/** Asserts by logging to the console and throwing an exception if NS_BLOCK_ASSERTIONS is not + * defined. + * + * @param condition The condition you'd expect to be YES. + */ +#define GDTCORFatalAssert(condition, format, ...) \ + do { \ + __PRAGMA_PUSH_NO_EXTRA_ARG_WARNINGS \ + if (__builtin_expect(!(condition), 0)) { \ + GDTCORAssertionBlock assertionBlock = GDTCORAssertionBlockToRunInstead(); \ + if (assertionBlock) { \ + assertionBlock(); \ + } else { \ + NSString *__assert_file__ = [NSString stringWithUTF8String:__FILE__]; \ + __assert_file__ = __assert_file__ ? __assert_file__ : @""; \ + GDTCORLogAssert(YES, __assert_file__, __LINE__, format, ##__VA_ARGS__); \ + [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd \ + object:self \ + file:__assert_file__ \ + lineNumber:__LINE__ \ + description:format, ##__VA_ARGS__]; \ + __PRAGMA_POP_NO_EXTRA_ARG_WARNINGS \ + } \ + } \ + } while (0); + +#endif // defined(NS_BLOCK_ASSERTIONS) + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h new file mode 100644 index 0000000..a6fa8a3 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORDirectorySizeTracker.h @@ -0,0 +1,66 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The class calculates and caches the specified directory content size and uses add/remove signals + * from client the client to keep the size up to date without accessing file system. + * This is an internal class designed to be used by `GDTCORFlatFileStorage`. + * NOTE: The class is not thread-safe. The client must take care of synchronization. + */ +@interface GDTCORDirectorySizeTracker : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the object with a directory path. + * @param path The directory path to track content size. + */ +- (instancetype)initWithDirectoryPath:(NSString *)path; + +/** Returns a cached or calculates (if there is no cached) directory content size. + * @return The directory content size in bytes calculated based on `NSURLFileSizeKey`. + */ +- (GDTCORStorageSizeBytes)directoryContentSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * added to the tracked directory. + * @param path The path to the added file. If the path is outside the tracked directory then the + * @param fileSize The size of the added file. + * method is no-op. + */ +- (void)fileWasAddedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** The client must call this method or `resetCachedSize` method each time a file or directory is + * removed from the tracked directory. + * @param path The path to the removed file. If the path is outside the tracked directory then the + * @param fileSize The size of the removed file. + * method is no-op. + */ +- (void)fileWasRemovedAtPath:(NSString *)path withSize:(GDTCORStorageSizeBytes)fileSize; + +/** Invalidates cached directory size. */ +- (void)resetCachedSize; + +/** Returns URL resource value for `NSURLFileSizeKey` key for the specified URL. */ +- (GDTCORStorageSizeBytes)fileSizeAtURL:(NSURL *)fileURL; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h new file mode 100644 index 0000000..791678b --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h @@ -0,0 +1,27 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/// The reason the event was "dropped". An event is considered "dropped" when it is no longer +/// tracked by the SDK (i.e. deleted). +typedef NS_ENUM(NSInteger, GDTCOREventDropReason) { + GDTCOREventDropReasonUnknown = 0, + GDTCOREventDropReasonMessageTooOld, + GDTCOREventDropReasonStorageFull, + GDTCOREventDropReasonPayloadTooBig, + GDTCOREventDropReasonMaxRetriesReached, + GDTCOREventDropReasonInvalidPayload, + GDTCOREventDropReasonServerError +}; diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h new file mode 100644 index 0000000..9316e5c --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h @@ -0,0 +1,63 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** A protocol defining the lifecycle events objects in the library must respond to immediately. */ +@protocol GDTCORLifecycleProtocol + +@optional + +/** Indicates an imminent app termination in the rare occurrence when -applicationWillTerminate: has + * been called. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillTerminate:(GDTCORApplication *)app; + +/** Indicates that the app is moving to background and eventual suspension or the current UIScene is + * deactivating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillBackground:(GDTCORApplication *)app; + +/** Indicates that the app is resuming operation or a UIScene is activating. + * + * @param app The GDTCORApplication instance. + */ +- (void)appWillForeground:(GDTCORApplication *)app; + +@end + +/** This class manages the library's response to app lifecycle events. + * + * When backgrounding, the library doesn't stop processing events, it's just that several background + * tasks will end up being created for every event that's sent, and the stateful objects of the + * library (GDTCORStorage and GDTCORUploadCoordinator instances) will deserialize themselves from + * and to disk before and after every operation, respectively. + */ +@interface GDTCORLifecycle : NSObject + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h new file mode 100644 index 0000000..b4a9f86 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +@class FBLPromise; +@class GDTCOREvent; +@class GDTCORMetrics; + +NS_ASSUME_NONNULL_BEGIN + +/// A storage delegate that can perform metrics related tasks. +@protocol GDTCORMetricsControllerProtocol + +/// Updates the corresponding log source metricss for the given events dropped for a given +/// reason. +/// @param reason The reason why the events are being dropped. +/// @param events The events that being dropped. +- (FBLPromise *)logEventsDroppedForReason:(GDTCOREventDropReason)reason + events:(NSSet *)events; + +/// Gets and resets the currently stored metrics. +/// @return A promise resolving with the metrics retrieved before the reset. +- (FBLPromise *)getAndResetMetrics; + +/// Offers metrics for re-storing in storage. +/// @note If the metrics are determined to be from the future, they will be ignored. +/// @param metrics The metrics to offer for storage. +- (FBLPromise *)offerMetrics:(GDTCORMetrics *)metrics; + +@end + +/// Returns a metrics controller instance for the given target. +/// @param target The target to retrieve a corresponding metrics controller from. +/// @return The given target's corresponding metrics controller instance, or `nil` if it does not +/// have one. +FOUNDATION_EXPORT +id _Nullable GDTCORMetricsControllerInstanceForTarget( + GDTCORTarget target); + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h new file mode 100644 index 0000000..89df0bc --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h @@ -0,0 +1,232 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if !TARGET_OS_WATCH +#import +#endif + +#if TARGET_OS_IOS || TARGET_OS_TV +#import +#elif TARGET_OS_OSX +#import +#elif TARGET_OS_WATCH +#import +#endif // TARGET_OS_IOS || TARGET_OS_TV + +// TODO(Xcode 15): When Xcode 15 is the minimum supported Xcode version, +// it will be unnecessary to check if `TARGET_OS_VISION` is defined. +#if TARGET_OS_IOS && (!defined(TARGET_OS_VISION) || !TARGET_OS_VISION) +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/** The GoogleDataTransport library version. */ +FOUNDATION_EXPORT NSString *const kGDTCORVersion; + +/** A notification sent out if the app is backgrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationDidEnterBackgroundNotification; + +/** A notification sent out if the app is foregrounding. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillEnterForegroundNotification; + +/** A notification sent out if the app is terminating. */ +FOUNDATION_EXPORT NSString *const kGDTCORApplicationWillTerminateNotification; + +/** The different possible network connection type. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkType) { + GDTCORNetworkTypeUNKNOWN = 0, + GDTCORNetworkTypeWIFI = 1, + GDTCORNetworkTypeMobile = 2, +}; + +/** The different possible network connection mobile subtype. */ +typedef NS_ENUM(NSInteger, GDTCORNetworkMobileSubtype) { + GDTCORNetworkMobileSubtypeUNKNOWN = 0, + GDTCORNetworkMobileSubtypeGPRS = 1, + GDTCORNetworkMobileSubtypeEdge = 2, + GDTCORNetworkMobileSubtypeWCDMA = 3, + GDTCORNetworkMobileSubtypeHSDPA = 4, + GDTCORNetworkMobileSubtypeHSUPA = 5, + GDTCORNetworkMobileSubtypeCDMA1x = 6, + GDTCORNetworkMobileSubtypeCDMAEVDORev0 = 7, + GDTCORNetworkMobileSubtypeCDMAEVDORevA = 8, + GDTCORNetworkMobileSubtypeCDMAEVDORevB = 9, + GDTCORNetworkMobileSubtypeHRPD = 10, + GDTCORNetworkMobileSubtypeLTE = 11, +}; + +#if !TARGET_OS_WATCH +/** Define SCNetworkReachabilityFlags as GDTCORNetworkReachabilityFlags on non-watchOS. */ +typedef SCNetworkReachabilityFlags GDTCORNetworkReachabilityFlags; + +/** Define SCNetworkReachabilityRef as GDTCORNetworkReachabilityRef on non-watchOS. */ +typedef SCNetworkReachabilityRef GDTCORNetworkReachabilityRef; + +#else +/** The different possible reachabilityFlags option on watchOS. */ +typedef NS_OPTIONS(uint32_t, GDTCORNetworkReachabilityFlags) { + kGDTCORNetworkReachabilityFlagsReachable = 1 << 1, + // TODO(doudounan): Add more options on watchOS if watchOS network connection information relative + // APIs available in the future. +}; + +/** Define a struct as GDTCORNetworkReachabilityRef on watchOS to store network connection + * information. */ +typedef struct { + // TODO(doudounan): Store network connection information on watchOS if watchOS network connection + // information relative APIs available in the future. +} GDTCORNetworkReachabilityRef; +#endif + +/** Returns a URL to the root directory under which all GDT-associated data must be saved. + * + * @return A URL to the root directory under which all GDT-associated data must be saved. + */ +NSURL *GDTCORRootDirectory(void); + +/** Compares flags with the reachable flag (on non-watchos with both reachable and + * connectionRequired flags), if available, and returns YES if network reachable. + * + * @param flags The set of reachability flags. + * @return YES if the network is reachable, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsReachable(GDTCORNetworkReachabilityFlags flags); + +/** Compares flags with the WWAN reachability flag, if available, and returns YES if present. + * + * @param flags The set of reachability flags. + * @return YES if the WWAN flag is set, NO otherwise. + */ +BOOL GDTCORReachabilityFlagsContainWWAN(GDTCORNetworkReachabilityFlags flags); + +/** Generates an enum message GDTCORNetworkType representing network connection type. + * + * @return A GDTCORNetworkType representing network connection type. + */ +GDTCORNetworkType GDTCORNetworkTypeMessage(void); + +/** Generates an enum message GDTCORNetworkMobileSubtype representing network connection mobile + * subtype. + * + * @return A GDTCORNetworkMobileSubtype representing network connection mobile subtype. + */ +GDTCORNetworkMobileSubtype GDTCORNetworkMobileSubTypeMessage(void); + +/** Identifies the model of the device on which the library is currently working on. + * + * @return A NSString representing the device model. + */ +NSString *_Nonnull GDTCORDeviceModel(void); + +/** Writes the given object to the given fileURL and populates the given error if it fails. + * + * @param obj The object to encode. + * @param filePath The path to write the object to. Can be nil if you just need the data. + * @param error The error to populate if something goes wrong. + * @return The data of the archive. If error is nil, it's been written to disk. + */ +NSData *_Nullable GDTCOREncodeArchive(id obj, + NSString *_Nullable filePath, + NSError *_Nullable *error); + +/// Decodes an object of the given class from the given archive path and populates the given error +/// if it fails. +/// @param archiveClass The class of the archive's root object. +/// @param archivePath The path to the archived data. +/// @param error The error to populate if something goes wrong. +id _Nullable GDTCORDecodeArchiveAtPath(Class archiveClass, + NSString *_Nonnull archivePath, + NSError **_Nonnull error); + +/// Decodes an object of the given class from the given data and populates the given error if it +/// fails. +/// @param archiveClass The class of the archive's root object. +/// @param archiveData The data to decode. +/// @param error The error to populate if something goes wrong. +id _Nullable GDTCORDecodeArchive(Class archiveClass, + NSData *_Nonnull archiveData, + NSError **_Nonnull error); + +/** Writes the provided data to a file at the provided path. Intermediate directories will be + * created as needed. + * @param data The file content. + * @param filePath The path to the file to write the provided data. + * @param outError The error to populate if something goes wrong. + * @return `YES` in the case of success, `NO` otherwise. + */ +BOOL GDTCORWriteDataToFile(NSData *data, NSString *filePath, NSError *_Nullable *outError); + +/** A typedef identify background identifiers. */ +typedef volatile NSUInteger GDTCORBackgroundIdentifier; + +/** A background task's invalid sentinel value. */ +FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInvalid; + +#if TARGET_OS_IOS || TARGET_OS_TV +/** A protocol that wraps UIApplicationDelegate, WKExtensionDelegate or NSObject protocol, depending + * on the platform. + */ +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_OSX +@protocol GDTCORApplicationDelegate +#elif TARGET_OS_WATCH +@protocol GDTCORApplicationDelegate +#else +@protocol GDTCORApplicationDelegate +#endif // TARGET_OS_IOS || TARGET_OS_TV + +@end + +@protocol GDTCORApplicationProtocol + +@required + +/** Flag to determine if the application is running in the background. */ +@property(atomic, readonly) BOOL isRunningInBackground; + +/** Creates a background task with the returned identifier if on a suitable platform. + * + * @name name The name of the task, useful for debugging which background tasks are running. + * @param handler The handler block that is called if the background task expires. + * @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one + * couldn't be created. + */ +- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name + expirationHandler:(void (^__nullable)(void))handler; + +/** Ends the background task if the identifier is valid. + * + * @param bgID The background task to end. + */ +- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID; + +@end + +/** A cross-platform application class. */ +@interface GDTCORApplication : NSObject + +/** Creates and/or returns the shared application instance. + * + * @return The shared application instance. + */ ++ (nullable GDTCORApplication *)sharedApplication; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h new file mode 100644 index 0000000..eb89832 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h @@ -0,0 +1,31 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORPlatform.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class helps determine upload conditions by determining connectivity. */ +@interface GDTCORReachability : NSObject + +/** The current set flags indicating network conditions */ ++ (GDTCORNetworkReachabilityFlags)currentFlags; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h new file mode 100644 index 0000000..d5e50bb --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the registration of targets with the transport SDK. */ +@interface GDTCORRegistrar : NSObject + +/** Creates and/or returns the singleton instance. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** Registers a backend implementation with the GoogleDataTransport infrastructure. + * + * @param backend The backend object to register with the given target. + * @param target The target this backend object will be responsible for. + */ +- (void)registerUploader:(id)backend target:(GDTCORTarget)target; + +/** Registers a storage implementation with the GoogleDataTransport infrastructure. + * + * @param storage The storage object to register with the given target. + * @param target The target this storage object will be responsible for. + */ +- (void)registerStorage:(id)storage target:(GDTCORTarget)target; + +/** Registers a metrics controller implementation with the GoogleDataTransport infrastructure. + * + * @param metricsController The metrics controller object to register with the given target. + * @param target The target this metrics controller object will be responsible for. + */ +- (void)registerMetricsController:(id)metricsController + target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h new file mode 100644 index 0000000..7662d8b --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h @@ -0,0 +1,61 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** This class enables the finding of events by matching events with the properties of this class. + */ +@interface GDTCORStorageEventSelector : NSObject + +/** The target to find events for. Required. */ +@property(readonly, nonatomic) GDTCORTarget selectedTarget; + +/** Finds a specific event. */ +@property(nullable, readonly, nonatomic) NSSet *selectedEventIDs; + +/** Finds all events of a mappingID. */ +@property(nullable, readonly, nonatomic) NSSet *selectedMappingIDs; + +/** Finds all events matching the qosTiers in this list. */ +@property(nullable, readonly, nonatomic) NSSet *selectedQosTiers; + +/** Initializes an event selector that will find all events for the given target. + * + * @param target The selected target. + * @return An immutable event selector instance. + */ ++ (instancetype)eventSelectorForTarget:(GDTCORTarget)target; + +/** Instantiates an event selector. + * + * @param target The selected target. + * @param eventIDs Optional param to find an event matching this eventID. + * @param mappingIDs Optional param to find events matching this mappingID. + * @param qosTiers Optional param to find events matching the given QoS tiers. + * @return An immutable event selector instance. + */ +- (instancetype)initWithTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + mappingIDs:(nullable NSSet *)mappingIDs + qosTiers:(nullable NSSet *)qosTiers; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h new file mode 100644 index 0000000..2a3ae0e --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h @@ -0,0 +1,210 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +@class GDTCOREvent; +@class GDTCORClock; +@class GDTCORUploadBatch; + +@class FBLPromise; + +@protocol GDTCORStorageDelegate; + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GDTCORStorageBatchBlock)(NSNumber *_Nullable newBatchID, + NSSet *_Nullable batchEvents); + +#pragma mark - GDTCORStorageProtocol + +/** Defines the interface a storage subsystem is expected to implement. */ +@protocol GDTCORStorageProtocol + +/// The object that acts as the delegate of the storage instance. +@property(nonatomic, weak, nullable) id delegate; + +@required + +/** Stores an event and calls onComplete with a non-nil error if anything went wrong. + * + * @param event The event to store + * @param completion The completion block to call after an attempt to store the event has been made. + */ +- (void)storeEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Returns YES if some events have been stored for the given target, NO otherwise. + * + * @param onComplete The completion block to invoke when determining if there are events is done. + */ +- (void)hasEventsForTarget:(GDTCORTarget)target onComplete:(void (^)(BOOL hasEvents))onComplete; + +/** Constructs an event batch with the given event selector. Events in this batch will not be + * returned in any queries or other batches until the batch is removed. + * + * @param eventSelector The event selector used to find the events. + * @param expiration The expiration time of the batch. If removeBatchWithID:deleteEvents:onComplete: + * is not called within this time frame, the batch will be removed with its events deleted. + * @param onComplete The completion handler to be called when the events have been fetched. + */ +- (void)batchWithEventSelector:(nonnull GDTCORStorageEventSelector *)eventSelector + batchExpiration:(nonnull NSDate *)expiration + onComplete:(nonnull GDTCORStorageBatchBlock)onComplete; + +/** Removes the event batch. + * + * @param batchID The batchID to remove. + * @param deleteEvents If YES, the events in this batch are deleted. + * @param onComplete The completion handler to call when the batch removal process has completed. + */ +- (void)removeBatchWithID:(NSNumber *)batchID + deleteEvents:(BOOL)deleteEvents + onComplete:(void (^_Nullable)(void))onComplete; + +/** Finds the batchIDs for the given target and calls the callback block. + * + * @param target The target. + * @param onComplete The block to invoke with the set of current batchIDs. + */ +- (void)batchIDsForTarget:(GDTCORTarget)target + onComplete:(void (^)(NSSet *_Nullable batchIDs))onComplete; + +/** Checks the storage for expired events and batches, deletes them if they're expired. */ +- (void)checkForExpirations; + +/** Persists the given data with the given key. + * + * @param data The data to store. + * @param key The unique key to store it to. + * @param onComplete An block to be run when storage of the data is complete. + */ +- (void)storeLibraryData:(NSData *)data + forKey:(NSString *)key + onComplete:(nullable void (^)(NSError *_Nullable error))onComplete; + +/** Retrieves the stored data for the given key and optionally sets a new value. + * + * @param key The key corresponding to the desired data. + * @param onFetchComplete The callback to invoke with the data once it's retrieved. + * @param setValueBlock This optional block can provide a new value to set. + */ +- (void)libraryDataForKey:(nonnull NSString *)key + onFetchComplete:(nonnull void (^)(NSData *_Nullable data, + NSError *_Nullable error))onFetchComplete + setNewValue:(NSData *_Nullable (^_Nullable)(void))setValueBlock; + +/** Removes data from storage and calls the callback when complete. + * + * @param key The key of the data to remove. + * @param onComplete The callback that will be invoked when removing the data is complete. + */ +- (void)removeLibraryDataForKey:(NSString *)key + onComplete:(void (^)(NSError *_Nullable error))onComplete; + +/** Calculates and returns the total disk size that this storage consumes. + * + * @param onComplete The callback that will be invoked once storage size calculation is complete. + */ +- (void)storageSizeWithCallback:(void (^)(GDTCORStorageSizeBytes storageSize))onComplete; + +@end + +#pragma mark - GDTCORStoragePromiseProtocol + +// TODO(ncooke3): Consider complete replacing block based API by promise API. + +@class GDTCORMetricsMetadata; +@class GDTCORStorageMetadata; + +/** Promise based version of API defined in GDTCORStorageProtocol. See API docs for corresponding + * methods in GDTCORStorageProtocol. */ +@protocol GDTCORStoragePromiseProtocol + +- (FBLPromise *> *)batchIDsForTarget:(GDTCORTarget)target; + +- (FBLPromise *)removeBatchWithID:(NSNumber *)batchID deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeBatchesWithIDs:(NSSet *)batchIDs + deleteEvents:(BOOL)deleteEvents; + +- (FBLPromise *)removeAllBatchesForTarget:(GDTCORTarget)target + deleteEvents:(BOOL)deleteEvents; + +/// Fetches metrics metadata from storage, passes them to the given handler, and writes the +/// resulting metrics metadata from the given handler to storage. +/// @note This API is thread-safe. +/// @param handler A handler to process the fetch result and return an updated value to store. +/// @return A promise that is fulfilled if the update is successful, and rejected otherwise. +- (FBLPromise *)fetchAndUpdateMetricsWithHandler: + (GDTCORMetricsMetadata * (^)(GDTCORMetricsMetadata *_Nullable fetchedMetadata, + NSError *_Nullable fetchError))handler; + +/// Fetches and returns storage metadata. +- (FBLPromise *)fetchStorageMetadata; + +/** See `hasEventsForTarget:onComplete:`. + * @return A promise object that is resolved with @YES if there are events for the specified target + * and @NO otherwise. + */ +- (FBLPromise *)hasEventsForTarget:(GDTCORTarget)target; + +/** See `batchWithEventSelector:batchExpiration:onComplete:` + * The promise is rejected when there are no events for the specified selector. + */ +- (FBLPromise *)batchWithEventSelector: + (GDTCORStorageEventSelector *)eventSelector + batchExpiration:(NSDate *)expiration; + +@end + +/** Retrieves the storage instance for the given target. + * + * @param target The target. + * * @return The storage instance registered for the target, or nil if there is none. + */ +FOUNDATION_EXPORT +id _Nullable GDTCORStorageInstanceForTarget(GDTCORTarget target); + +FOUNDATION_EXPORT +id _Nullable GDTCORStoragePromiseInstanceForTarget( + GDTCORTarget target); + +#pragma mark - GDTCORStorageDelegate + +/// A type that can be delegated actions from a storage instance. +@protocol GDTCORStorageDelegate + +/// Tells the delegate that the storage instance has removed a set of expired events. +/// @param storage The storage instance informing the delegate of this impending event. +/// @param events A set of events that were removed from storage due to their expiration. +- (void)storage:(id)storage + didRemoveExpiredEvents:(NSSet *)events; + +/// Tells the delegate that the storage instance has dropped an event due to the event cache being +/// full. +/// @param storage The storage instance informing the delegate of this impending event. +/// @param event An event that was dropped due to the event cache being full. +- (void)storage:(id)storage didDropEvent:(GDTCOREvent *)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h new file mode 100644 index 0000000..4b24f95 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h @@ -0,0 +1,18 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +/// The data type to represent storage size. +typedef uint64_t GDTCORStorageSizeBytes; diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h new file mode 100644 index 0000000..9b5343d --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Internal/GDTCORUploader.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/** Options that define a set of upload conditions. This is used to help minimize end user data + * consumption impact. + */ +typedef NS_OPTIONS(NSInteger, GDTCORUploadConditions) { + + /** An upload shouldn't be attempted, because there's no network. */ + GDTCORUploadConditionNoNetwork = 1 << 0, + + /** An upload would likely use mobile data. */ + GDTCORUploadConditionMobileData = 1 << 1, + + /** An upload would likely use wifi data. */ + GDTCORUploadConditionWifiData = 1 << 2, + + /** An upload uses some sort of network connection, but it's unclear which. */ + GDTCORUploadConditionUnclearConnection = 1 << 3, + + /** A high priority event has occurred. */ + GDTCORUploadConditionHighPriority = 1 << 4, +}; + +/** This protocol defines the common interface for uploader implementations. */ +@protocol GDTCORUploader + +@required + +/** Uploads events to the backend using this specific backend's chosen format. + * + * @param conditions The conditions that the upload attempt is likely to occur under. + */ +- (void)uploadTarget:(GDTCORTarget)target withConditions:(GDTCORUploadConditions)conditions; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h new file mode 100644 index 0000000..4b1a903 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREndpoints_Private.h @@ -0,0 +1,27 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h" + +@interface GDTCOREndpoints () + +/** Returns the list of all the upload URLs used by the transport library. + * + * @return Map of the transport target and the URL used for uploading the events for that target. + */ ++ (NSDictionary *)uploadURLs; + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h new file mode 100644 index 0000000..e97eb31 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCOREvent_Private.h @@ -0,0 +1,33 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h" + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCOREvent () + +/** The unique ID of the event. This property is for testing only. */ +@property(nonatomic, readwrite) NSString *eventID; + +/** Generates a unique event ID. */ ++ (NSString *)nextEventID; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h new file mode 100644 index 0000000..66ea857 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage+Promises.h @@ -0,0 +1,28 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h" + +@class FBLPromise; + +NS_ASSUME_NONNULL_BEGIN + +/// The category extends `GDTCORFlatFileStorage` API with `GDTCORStoragePromiseProtocol` methods. +@interface GDTCORFlatFileStorage (Promises) + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h new file mode 100644 index 0000000..09f1dae --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORFlatFileStorage.h @@ -0,0 +1,158 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageEventSelector.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageProtocol.h" + +@class GDTCOREvent; +@class GDTCORUploadCoordinator; + +NS_ASSUME_NONNULL_BEGIN + +/** The event components eventID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsEventIDKey; + +/** The event components qosTier dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsQoSTierKey; + +/** The event components mappingID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsMappingIDKey; + +/** The event components expirationDate dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCOREventComponentsExpirationKey; + +/** The batch components target dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsTargetKey; + +/** The batch components batchID dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsBatchIDKey; + +/** The batch components expiration dictionary key. */ +FOUNDATION_EXPORT NSString *const kGDTCORBatchComponentsExpirationKey; + +/** The maximum allowed disk space taken by the stored data. */ +FOUNDATION_EXPORT const uint64_t kGDTCORFlatFileStorageSizeLimit; + +FOUNDATION_EXPORT NSString *const GDTCORFlatFileStorageErrorDomain; + +typedef NS_ENUM(NSInteger, GDTCORFlatFileStorageError) { + GDTCORFlatFileStorageErrorSizeLimitReached = 0 +}; + +/** Manages the storage of events. This class is thread-safe. + * + * Event files will be stored as follows: + * /google-sdk-events//gdt_event_data//.. + * + * Library data will be stored as follows: + * /google-sdk-events//gdt_library_data/ + * + * Batch data will be stored as follows: + * /google-sdk-events//gdt_batch_data/./.. + */ +@interface GDTCORFlatFileStorage : NSObject + +/** The queue on which all storage work will occur. */ +@property(nonatomic) dispatch_queue_t storageQueue; + +/** The upload coordinator instance used by this storage instance. */ +@property(nonatomic) GDTCORUploadCoordinator *uploadCoordinator; + +/** Creates and/or returns the storage singleton. + * + * @return The storage singleton. + */ ++ (instancetype)sharedInstance; + +/** Returns the base directory under which all events will be stored. + * + * @return The base directory under which all events will be stored. + */ ++ (NSString *)eventDataStoragePath; + +/** Returns the base directory under which all library data will be stored. + * + * @return The base directory under which all library data will be stored. + */ ++ (NSString *)libraryDataStoragePath; + +/** Returns the base directory under which all batch data will be stored. + * + * @return The base directory under which all batch data will be stored. + */ ++ (NSString *)batchDataStoragePath; + +/** */ ++ (NSString *)batchPathForTarget:(GDTCORTarget)target + batchID:(NSNumber *)batchID + expirationDate:(NSDate *)expirationDate; + +/** Returns a constructed storage path based on the given values. This path may not exist. + * + * @param target The target, which is necessary to be given a path. + * @param eventID The eventID. + * @param qosTier The qosTier. + * @param expirationDate The expirationDate as a 1970-relative time interval. + * @param mappingID The mappingID. + * @return The path representing the combination of the given parameters. + */ ++ (NSString *)pathForTarget:(GDTCORTarget)target + eventID:(NSString *)eventID + qosTier:(NSNumber *)qosTier + expirationDate:(NSDate *)expirationDate + mappingID:(NSString *)mappingID; + +/** Returns extant paths that match all of the given parameters. + * + * @param eventIDs The list of eventIDs to look for, or nil for any. + * @param qosTiers The list of qosTiers to look for, or nil for any. + * @param mappingIDs The list of mappingIDs to look for, or nil for any. + * @param onComplete The completion to call once the paths have been discovered. + */ +- (void)pathsForTarget:(GDTCORTarget)target + eventIDs:(nullable NSSet *)eventIDs + qosTiers:(nullable NSSet *)qosTiers + mappingIDs:(nullable NSSet *)mappingIDs + onComplete:(void (^)(NSSet *paths))onComplete; + +/** Fetches the current batchID counter value from library storage, increments it, and sets the new + * value. Returns nil if a batchID was not able to be created for some reason. + * + * @param onComplete A block to execute when creating the next batchID is complete. + */ +- (void)nextBatchID:(void (^)(NSNumber *_Nullable batchID))onComplete; + +/** Constructs a dictionary of event filename components. + * + * @param fileName The event filename to split. + * @return The dictionary of event component keys to their values. + */ +- (nullable NSDictionary *)eventComponentsFromFilename:(NSString *)fileName; + +/** Constructs a dictionary of batch filename components. + * + * @param fileName The batch folder name to split. + * @return The dictionary of batch component keys to their values. + */ +- (nullable NSDictionary *)batchComponentsFromFilename:(NSString *)fileName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h new file mode 100644 index 0000000..8722073 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORLogSourceMetrics.h @@ -0,0 +1,53 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/// A model object that tracks, per log source, the number of events dropped for a variety of +/// reasons. An event is considered "dropped" when the event is no longer persisted by the SDK. +@interface GDTCORLogSourceMetrics : NSObject + +/// Creates an empty log source metrics instance. ++ (instancetype)metrics; + +/// Creates a log source metrics for a collection of events that were dropped for a given reason. +/// @param events The collection of events that were dropped. +/// @param reason The reason for which given events were dropped. ++ (instancetype)metricsWithEvents:(NSArray *)events + droppedForReason:(GDTCOREventDropReason)reason; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +/// Returns a log source metrics instance created by merging the receiving log +/// source metrics with the given log source metrics. +/// @param logSourceMetrics The given log source metrics to merge with. +- (GDTCORLogSourceMetrics *)logSourceMetricsByMergingWithLogSourceMetrics: + (GDTCORLogSourceMetrics *)logSourceMetrics; + +/// Returns a Boolean value that indicates whether the receiving log source metrics is equal to +/// the given log source metrics. +/// @param otherLogSourceMetrics The log source metrics with which to compare the +/// receiving log source metrics. +- (BOOL)isEqualToLogSourceMetrics:(GDTCORLogSourceMetrics *)otherLogSourceMetrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h new file mode 100644 index 0000000..2f3c38f --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetrics.h @@ -0,0 +1,61 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h" + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +@class GDTCORLogSourceMetrics; +@class GDTCORMetricsMetadata; +@class GDTCORStorageMetadata; + +NS_ASSUME_NONNULL_BEGIN + +/// An object representing metrics that represent a snapshot of the SDK's state and performance. +@interface GDTCORMetrics : NSObject + +/// The start of the time window over which the metrics were collected. +@property(nonatomic, readonly) NSDate *collectionStartDate; + +/// The log source metrics associated with the metrics. +@property(nonatomic, readonly) GDTCORLogSourceMetrics *logSourceMetrics; + +/// The end of the time window over which the metrics were collected. +@property(nonatomic, readonly) NSDate *collectionEndDate; + +/// The number of bytes the event cache was consuming in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes currentCacheSize; + +/// The maximum number of bytes that the event cache is allowed to grow. +@property(nonatomic, readonly) GDTCORStorageSizeBytes maxCacheSize; + +/// The bundle ID associated with the metrics being collected. +@property(nonatomic, readonly) NSString *bundleID; + +/// Creates a metrics instance with the provided metadata. +/// @param metricsMetadata The provided metrics metadata. +/// @param storageMetadata The provided storage metadata. ++ (instancetype)metricsWithMetricsMetadata:(GDTCORMetricsMetadata *)metricsMetadata + storageMetadata:(GDTCORStorageMetadata *)storageMetadata; + +/// Returns a Boolean value that indicates whether the receiving metrics is equal to the given +/// metrics. +/// @param otherMetrics The metrics with which to compare the receiving metrics. +- (BOOL)isEqualToMetrics:(GDTCORMetrics *)otherMetrics; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h new file mode 100644 index 0000000..a47da52 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsController.h @@ -0,0 +1,37 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORMetricsControllerProtocol.h" + +@protocol GDTCORStoragePromiseProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORMetricsController : NSObject + +/// Returns the event metrics controller singleton. ++ (instancetype)sharedInstance; + +/// Designated initializer. +/// @param storage The storage object to read and write metrics data from. +- (instancetype)initWithStorage:(id)storage NS_DESIGNATED_INITIALIZER; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h new file mode 100644 index 0000000..8214c41 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORMetricsMetadata.h @@ -0,0 +1,50 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCOREventDropReason.h" + +@class GDTCORLogSourceMetrics; + +NS_ASSUME_NONNULL_BEGIN + +/// An encodable model object that contains metadata that is persisted in storage until ready to be +/// used to create a ``GDTCORMetrics`` instance. +@interface GDTCORMetricsMetadata : NSObject + +/// The start of the time window over which the metrics were collected. +@property(nonatomic, copy, readonly) NSDate *collectionStartDate; + +/// The log source metrics associated with the metrics. +@property(nonatomic, copy, readonly) GDTCORLogSourceMetrics *logSourceMetrics; + +/// Creates a metrics metadata object with the provided information. +/// @param collectedSinceDate The start of the time window over which the metrics were collected. +/// @param logSourceMetrics The metrics object that tracks metrics for each log source. ++ (instancetype)metadataWithCollectionStartDate:(NSDate *)collectedSinceDate + logSourceMetrics:(GDTCORLogSourceMetrics *)logSourceMetrics; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +/// Returns a Boolean value that indicates whether the receiving metrics metadata is equal to +/// the given metrics metadata. +/// @param otherMetricsMetadata The metrics metadata with which to compare the +/// receiving metrics metadata. +- (BOOL)isEqualToMetricsMetadata:(GDTCORMetricsMetadata *)otherMetricsMetadata; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h new file mode 100644 index 0000000..06b1f67 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORReachability_Private.h @@ -0,0 +1,30 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORReachability.h" + +@interface GDTCORReachability () + +/** Allows manually setting the flags for testing purposes. */ +@property(nonatomic, readwrite) GDTCORNetworkReachabilityFlags flags; + +/** Creates/returns the singleton instance of this class. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h new file mode 100644 index 0000000..9f45548 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORRegistrar_Private.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@interface GDTCORRegistrar () + +NS_ASSUME_NONNULL_BEGIN + +/** The concurrent queue on which all registration occurs. */ +@property(nonatomic, readonly) dispatch_queue_t registrarQueue; + +/** A map of targets to backend implementations. */ +@property(atomic, readonly) NSMutableDictionary> *targetToUploader; + +/** A map of targets to storage instances. */ +@property(atomic, readonly) + NSMutableDictionary> *targetToStorage; + +/** A map of targets to metrics controller instances. */ +@property(atomic, readonly) + NSMutableDictionary> *targetToMetricsController; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h new file mode 100644 index 0000000..90b529e --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorageMetadata.h @@ -0,0 +1,41 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORStorageSizeBytes.h" + +NS_ASSUME_NONNULL_BEGIN + +/// A model object that contains metadata about the current state of the SDK's storage container. +@interface GDTCORStorageMetadata : NSObject + +/// The number of bytes the event cache is consuming in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes currentCacheSize; + +/// The maximum number of bytes that the event cache may consume in storage. +@property(nonatomic, readonly) GDTCORStorageSizeBytes maxCacheSize; + +/// Creates a storage metadata object with the provided information. +/// @param currentCacheSize The current number of bytes the event cache is consuming. +/// @param maxCacheSize The current maximum capacity (in bytes) that the event cache may consume. ++ (instancetype)metadataWithCurrentCacheSize:(GDTCORStorageSizeBytes)currentCacheSize + maxCacheSize:(GDTCORStorageSizeBytes)maxCacheSize; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h new file mode 100644 index 0000000..ccca628 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h @@ -0,0 +1,57 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" + +@class GDTCOREvent; + +@protocol GDTCOREventTransformer; + +NS_ASSUME_NONNULL_BEGIN + +/** Manages the transforming of events. It's desirable for this to be its own class + * because running all events through a single instance ensures that transformers are thread-safe. + * Having a per-transport queue to run on isn't sufficient because transformer objects could + * maintain state (or at least, there's nothing to stop them from doing that) and the same instances + * may be used across multiple instances. + */ +@interface GDTCORTransformer : NSObject + +/** Instantiates or returns the event transformer singleton. + * + * @return The singleton instance of the event transformer. + */ ++ (instancetype)sharedInstance; + +/** Writes the result of applying the given transformers' `transformGDTEvent:` method on the given + * event. + * + * @note If the app is suspended, a background task will be created to complete work in-progress, + * but this method will not send any further events until the app is resumed. + * + * @param event The event to apply transformers on. + * @param transformers The list of transformers to apply. + * @param completion A block to run when an event was written to disk or dropped. + */ +- (void)transformEvent:(GDTCOREvent *)event + withTransformers:(nullable NSArray> *)transformers + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h new file mode 100644 index 0000000..bb86407 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer.h" + +@protocol GDTCORApplicationProtocol; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransformer () + +/** The queue on which all work will occur. */ +@property(nonatomic) dispatch_queue_t eventWritingQueue; + +/** The application instance that is used to begin/end background tasks. */ +@property(nonatomic, readonly) id application; + +/** The internal initializer. Should be used in tests only to create an instance with a + * particular(fake) application instance. */ +- (instancetype)initWithApplication:(id)application; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h new file mode 100644 index 0000000..41a1224 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransport_Private.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h" + +@class GDTCORTransformer; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport () + +/** The mapping identifier that the target backend will use to map the transport bytes to proto. */ +@property(nonatomic) NSString *mappingID; + +/** The transformers that will operate on events sent by this transport. */ +@property(nonatomic) NSArray> *transformers; + +/** The target backend of this transport. */ +@property(nonatomic) NSInteger target; + +/** The transformer instance to used to transform events. Allows injecting a fake during testing. */ +@property(nonatomic) GDTCORTransformer *transformerInstance; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h new file mode 100644 index 0000000..8d1fd11 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadBatch.h @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/// A data object representing a batch of events scheduled for upload. +@interface GDTCORUploadBatch : NSObject + +/// An ID used to identify the batch in the storage. +@property(nonatomic, readonly) NSNumber *batchID; + +/// The collection of the events in the batch. +@property(nonatomic, readonly) NSSet *events; + +/// The default initializer. See also docs for the corresponding properties. +- (instancetype)initWithBatchID:(NSNumber *)batchID events:(NSSet *)events; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h new file mode 100644 index 0000000..bdac3f3 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h @@ -0,0 +1,68 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORLifecycle.h" +#import "GoogleDataTransport/GDTCORLibrary/Internal/GDTCORRegistrar.h" + +@class GDTCORClock; + +NS_ASSUME_NONNULL_BEGIN + +/** This class connects storage and uploader implementations, providing events to an uploader + * and informing the storage what events were successfully uploaded or not. + */ +@interface GDTCORUploadCoordinator : NSObject + +/** The queue on which all upload coordination will occur. Also used by a dispatch timer. */ +/** Creates and/or returrns the singleton. + * + * @return The singleton instance of this class. + */ ++ (instancetype)sharedInstance; + +/** The queue on which all upload coordination will occur. */ +@property(nonatomic, readonly) dispatch_queue_t coordinationQueue; + +/** A timer that will causes regular checks for events to upload. */ +@property(nonatomic, readonly, nullable) dispatch_source_t timer; + +/** The interval the timer will fire. */ +@property(nonatomic, readonly) uint64_t timerInterval; + +/** Some leeway given to libdispatch for the timer interval event. */ +@property(nonatomic, readonly) uint64_t timerLeeway; + +/** The registrar object the coordinator will use. Generally used for testing. */ +@property(nonatomic) GDTCORRegistrar *registrar; + +/** Forces the backend specified by the target to upload the provided set of events. This should + * only ever happen when the QoS tier of an event requires it. + * + * @param target The target that should force an upload. + */ +- (void)forceUploadForTarget:(GDTCORTarget)target; + +/** Starts the upload timer. */ +- (void)startTimer; + +/** Stops the upload timer from running. */ +- (void)stopTimer; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h new file mode 100644 index 0000000..8c75b50 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORClock.h @@ -0,0 +1,66 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This class manages the device clock and produces snapshots of the current time. */ +@interface GDTCORClock : NSObject + +/** The wallclock time, UTC, in milliseconds. */ +@property(nonatomic, readonly) int64_t timeMillis; + +/** The offset from UTC in seconds. */ +@property(nonatomic, readonly) int64_t timezoneOffsetSeconds; + +/** The kernel boot time when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t kernelBootTimeNanoseconds; + +/** The device uptime when this clock was created in nanoseconds. */ +@property(nonatomic, readonly) int64_t uptimeNanoseconds; + +@property(nonatomic, readonly) int64_t kernelBootTime DEPRECATED_MSG_ATTRIBUTE( + "Please use `kernelBootTimeNanoseconds` instead"); + +@property(nonatomic, readonly) + int64_t uptime DEPRECATED_MSG_ATTRIBUTE("Please use `uptimeNanoseconds` instead"); + +/** Creates a GDTCORClock object using the current time and offsets. + * + * @return A new GDTCORClock object representing the current time state. + */ ++ (instancetype)snapshot; + +/** Creates a GDTCORClock object representing a time in the future, relative to now. + * + * @param millisInTheFuture The millis in the future from now this clock should represent. + * @return An instance representing a future time. + */ ++ (instancetype)clockSnapshotInTheFuture:(uint64_t)millisInTheFuture; + +/** Compares one clock with another, returns YES if the caller is after the parameter. + * + * @return YES if the calling clock's time is after the given clock's time. + */ +- (BOOL)isAfter:(GDTCORClock *)otherClock; + +/** Returns value of `uptime` property in milliseconds. */ +- (int64_t)uptimeMilliseconds; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h new file mode 100644 index 0000000..1fdf732 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORConsoleLogger.h @@ -0,0 +1,144 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** The current logging level. This value and higher will be printed. Declared as volatile to make + * getting and setting atomic. + */ +FOUNDATION_EXPORT volatile NSInteger GDTCORConsoleLoggerLoggingLevel; + +/** A list of logging levels that GDT supports. */ +typedef NS_ENUM(NSInteger, GDTCORLoggingLevel) { + + /** Causes all logs to be printed. */ + GDTCORLoggingLevelDebug = 1, + + /** Causes all non-debug logs to be printed. */ + GDTCORLoggingLevelVerbose = 2, + + /** Causes warnings and errors to be printed. */ + GDTCORLoggingLevelWarnings = 3, + + /** Causes errors to be printed. This is the default value. */ + GDTCORLoggingLevelErrors = 4 +}; + +/** A list of message codes to print in the logger that help to correspond printed messages with + * code locations. + * + * Prefixes: + * - MCD => MessageCodeDebug + * - MCW => MessageCodeWarning + * - MCE => MessageCodeError + */ +typedef NS_ENUM(NSInteger, GDTCORMessageCode) { + + /** For debug logs. */ + GDTCORMCDDebugLog = 0, + + /** For warning messages concerning transportBytes: not being implemented by a data object. */ + GDTCORMCWDataObjectMissingBytesImpl = 1, + + /** For warning messages concerning a failed event upload. */ + GDTCORMCWUploadFailed = 2, + + /** For warning messages concerning a forced event upload. */ + GDTCORMCWForcedUpload = 3, + + /** For warning messages concerning a failed reachability call. */ + GDTCORMCWReachabilityFailed = 4, + + /** For warning messages concerning a database warning. */ + GDTCORMCWDatabaseWarning = 5, + + /** For warning messages concerning the reading of a event file. */ + GDTCORMCWFileReadError = 6, + + /** For error messages concerning transformGDTEvent: not being implemented by an event + transformer. */ + GDTCORMCETransformerDoesntImplementTransform = 1000, + + /** For error messages concerning the creation of a directory failing. */ + GDTCORMCEDirectoryCreationError = 1001, + + /** For error messages concerning the writing of a event file. */ + GDTCORMCEFileWriteError = 1002, + + /** For error messages concerning the lack of a prioritizer for a given backend. */ + GDTCORMCEPrioritizerError = 1003, + + /** For error messages concerning a package delivery API violation. */ + GDTCORMCEDeliverTwice = 1004, + + /** For error messages concerning an error in an implementation of -transportBytes. */ + GDTCORMCETransportBytesError = 1005, + + /** For general purpose error messages in a dependency. */ + GDTCORMCEGeneralError = 1006, + + /** For fatal errors. Please go to https://github.com/firebase/firebase-ios-sdk/issues and open + * an issue if you encounter an error with this code. + */ + GDTCORMCEFatalAssertion = 1007, + + /** For error messages concerning the reading of a event file. */ + GDTCORMCEFileReadError = 1008, + + /** For errors related to running sqlite. */ + GDTCORMCEDatabaseError = 1009, +}; + +/** Prints the given code and format string to the console. + * + * @param code The message code describing the nature of the log. + * @param logLevel The log level of this log. + * @param format The format string. + */ +FOUNDATION_EXPORT +void GDTCORLog(GDTCORMessageCode code, GDTCORLoggingLevel logLevel, NSString *_Nonnull format, ...) + NS_FORMAT_FUNCTION(3, 4); + +/** Prints an assert log to the console. + * + * @param wasFatal Send YES if the assertion should be fatal, NO otherwise. + * @param file The file in which the failure occurred. + * @param line The line number of the failure. + * @param format The format string. + */ +FOUNDATION_EXPORT void GDTCORLogAssert(BOOL wasFatal, + NSString *_Nonnull file, + NSInteger line, + NSString *_Nullable format, + ...) NS_FORMAT_FUNCTION(4, 5); + +/** Returns the string that represents some message code. + * + * @param code The code to convert to a string. + * @return The string representing the message code. + */ +FOUNDATION_EXPORT NSString *_Nonnull GDTCORMessageCodeEnumToString(GDTCORMessageCode code); + +#define GDTCORLogDebug(MESSAGE_FORMAT, ...) \ + GDTCORLog(GDTCORMCDDebugLog, GDTCORLoggingLevelDebug, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogWarning with slightly more convenient usage. +#define GDTCORLogWarning(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelWarnings, MESSAGE_FORMAT, __VA_ARGS__); + +// A define to wrap GULLogError with slightly more convenient usage and a failing assert. +#define GDTCORLogError(MESSAGE_CODE, MESSAGE_FORMAT, ...) \ + GDTCORLog(MESSAGE_CODE, GDTCORLoggingLevelErrors, MESSAGE_FORMAT, __VA_ARGS__); diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h new file mode 100644 index 0000000..836a454 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREndpoints.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GDTCORTargets.h" + +NS_ASSUME_NONNULL_BEGIN + +/* Class that manages the endpoints used by Google data transport library. */ +@interface GDTCOREndpoints : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Returns the upload URL for a target specified. If the target is not available, returns nil. + * + * @param target GoogleDataTransport target for which the upload URL is being looked up for. + * @return URL that will be used for uploading the events for the provided target. + */ ++ (nullable NSURL *)uploadURLForTarget:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h new file mode 100644 index 0000000..8ab3601 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREvent.h @@ -0,0 +1,102 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GDTCOREventDataObject.h" +#import "GDTCORTargets.h" + +@class GDTCORClock; +@class GDTCORProductData; + +NS_ASSUME_NONNULL_BEGIN + +/** The different possible quality of service specifiers. High values indicate high priority. */ +typedef NS_ENUM(NSInteger, GDTCOREventQoS) { + /** The QoS tier wasn't set, and won't ever be sent. */ + GDTCOREventQoSUnknown = 0, + + /** This event is internal telemetry data that should not be sent on its own if possible. */ + GDTCOREventQoSTelemetry = 1, + + /** This event should be sent, but in a batch only roughly once per day. */ + GDTCOREventQoSDaily = 2, + + /** This event should be sent when requested by the uploader. */ + GDTCOREventQosDefault = 3, + + /** This event should be sent immediately along with any other data that can be batched. */ + GDTCOREventQoSFast = 4, + + /** This event should only be uploaded on wifi. */ + GDTCOREventQoSWifiOnly = 5, +}; + +@interface GDTCOREvent : NSObject + +/** The unique ID of the event. */ +@property(readonly, nonatomic) NSString *eventID; + +/** The mapping identifier, to allow backends to map the transport bytes to a proto. */ +@property(nullable, readonly, nonatomic) NSString *mappingID; + +/** The identifier for the backend this event will eventually be sent to. */ +@property(readonly, nonatomic) GDTCORTarget target; + +/** The data object encapsulated in the transport of your choice, as long as it implements + * the GDTCOREventDataObject protocol. */ +@property(nullable, nonatomic) id dataObject; + +/** The serialized bytes from calling [dataObject transportBytes]. */ +@property(nullable, readonly, nonatomic) NSData *serializedDataObjectBytes; + +/** The quality of service tier this event belongs to. */ +@property(nonatomic) GDTCOREventQoS qosTier; + +/** The clock snapshot at the time of the event. */ +@property(nonatomic) GDTCORClock *clockSnapshot; + +/** The expiration date of the event. Default is 604800 seconds (7 days) from creation. */ +@property(nonatomic) NSDate *expirationDate; + +/** Bytes that can be used by an uploader later on. */ +@property(nullable, nonatomic) NSData *customBytes; + +/** The product data that the event is associated with, if any. */ +@property(nullable, readonly, nonatomic) GDTCORProductData *productData; + +/** Initializes an instance using the given mapping ID and target. + * + * @param mappingID The mapping identifier. + * @param target The event's target identifier. + * @return An instance of this class. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID target:(GDTCORTarget)target; + +/** Initializes an instance using the given mapping ID, product data, and target. + * + * @param mappingID The mapping identifier. + * @param productData The product data to associate this event with. + * @param target The event's target identifier. + * @return An instance of this class. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + productData:(nullable GDTCORProductData *)productData + target:(GDTCORTarget)target; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h new file mode 100644 index 0000000..34ef624 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventDataObject.h @@ -0,0 +1,36 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This protocol defines the common interface that event protos should implement regardless of the + * underlying transport technology (protobuf, nanopb, etc). + */ +@protocol GDTCOREventDataObject + +@required + +/** Returns the serialized proto bytes of the implementing event proto. + * + * @return the serialized proto bytes of the implementing event proto. + */ +- (NSData *)transportBytes; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h new file mode 100644 index 0000000..80dee7d --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCOREventTransformer.h @@ -0,0 +1,38 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +@class GDTCOREvent; + +NS_ASSUME_NONNULL_BEGIN + +/** Defines the API that event transformers must adopt. */ +@protocol GDTCOREventTransformer + +@required + +/** Transforms an event by applying some logic to it. Events returned can be nil, for example, in + * instances where the event should be sampled. + * + * @param event The event to transform. + * @return A transformed event, or nil if the transformation dropped the event. + */ +- (nullable GDTCOREvent *)transformGDTEvent:(GDTCOREvent *)event; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h new file mode 100644 index 0000000..ff99822 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORProductData.h @@ -0,0 +1,29 @@ +// Copyright 2023 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +@interface GDTCORProductData : NSObject + +/// The product ID. +@property(nonatomic, readonly) int32_t productID; + +/// Initializes an instance using the given product ID. +/// - Parameter productID: A 32-bit integer. +- (instancetype)initWithProductID:(int32_t)productID; + +/// This API is unavailable. +- (instancetype)init NS_UNAVAILABLE; + +@end diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h new file mode 100644 index 0000000..3163b55 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTargets.h @@ -0,0 +1,39 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +/** The list of targets supported by the shared transport infrastructure. + * These targets map to a specific backend designed to accept GDT payloads. If + * adding a new target, please use the previous value +1. + */ +typedef NS_ENUM(NSInteger, GDTCORTarget) { + + /** Target used for testing purposes. */ + kGDTCORTargetTest = 999, + + /** Target used by internal clients. See go/firelog for more information. */ + kGDTCORTargetCCT = 1000, + + /** Target mapping to the Firelog backend. See go/firelog for more information. */ + kGDTCORTargetFLL = 1001, + + /** Special-purpose Crashlytics target. Please do not use it without permission. */ + kGDTCORTargetCSH = 1002, + + /** Target used for integration testing. */ + kGDTCORTargetINT = 1003, +}; diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h new file mode 100644 index 0000000..33d1ba2 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GDTCORTransport.h @@ -0,0 +1,101 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GDTCOREventTransformer.h" +#import "GDTCORTargets.h" + +@class GDTCOREvent; +@class GDTCORProductData; + +NS_ASSUME_NONNULL_BEGIN + +@interface GDTCORTransport : NSObject + +// Please use the designated initializer. +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes a new transport that will send events to the given target backend. + * + * @param mappingID The mapping identifier used by the backend to map the data object transport + * bytes to a proto. + * @param transformers A list of transformers to be applied to events that are sent. + * @param target The target backend of this transport. + * @return A transport that will send events. + */ +- (nullable instancetype)initWithMappingID:(NSString *)mappingID + transformers: + (nullable NSArray> *)transformers + target:(GDTCORTarget)target NS_DESIGNATED_INITIALIZER; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an internal telemetry event. Events sent using this API are lower in priority, + * and sometimes won't be sent on their own. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendTelemetryEvent:(GDTCOREvent *)event; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + * @param completion A block that will be called when the event has been written or dropped. + */ +- (void)sendDataEvent:(GDTCOREvent *)event + onComplete:(void (^_Nullable)(BOOL wasWritten, NSError *_Nullable error))completion; + +/** Copies and sends an SDK service data event. Events send using this API are higher in priority, + * and will cause a network request at some point in the relative near future. + * + * @note This will convert the event's data object to data and release the original event. + * + * @param event The event to send. + */ +- (void)sendDataEvent:(GDTCOREvent *)event; + +/** Creates an event for use by this transport. + * + * @return An event that is suited for use by this transport. + */ +- (GDTCOREvent *)eventForTransport; + +/** + * Creates an event with the given product data for use by this transport. + * + * @param productData The given product data to associate with the created event. + * @return An event that is suited for use by this transport. + */ +- (GDTCOREvent *)eventForTransportWithProductData:(nonnull GDTCORProductData *)productData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h new file mode 100644 index 0000000..b5e83d1 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/GDTCORLibrary/Public/GoogleDataTransport/GoogleDataTransport.h @@ -0,0 +1,25 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORProductData.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" diff --git a/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy b/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1e83fa6 --- /dev/null +++ b/Pods/GoogleDataTransport/GoogleDataTransport/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,30 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyCollectedDataType + NSPrivacyCollectedDataTypeOtherDiagnosticData + NSPrivacyCollectedDataTypeLinked + + NSPrivacyCollectedDataTypeTracking + + NSPrivacyCollectedDataTypePurposes + + NSPrivacyCollectedDataTypePurposeAnalytics + + + + NSPrivacyAccessedAPITypes + + + + + diff --git a/Pods/GoogleDataTransport/LICENSE b/Pods/GoogleDataTransport/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/GoogleDataTransport/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/GoogleDataTransport/README.md b/Pods/GoogleDataTransport/README.md new file mode 100644 index 0000000..084c2c0 --- /dev/null +++ b/Pods/GoogleDataTransport/README.md @@ -0,0 +1,236 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![License](https://img.shields.io/cocoapods/l/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) +[![Platform](https://img.shields.io/cocoapods/p/GoogleDataTransport.svg?style=flat)](https://cocoapods.org/pods/GoogleDataTransport) + +[![Actions Status][gh-datatransport-badge]][gh-actions] + +# GoogleDataTransport + +This library is for internal Google use only. It allows the logging of data and +telemetry from Google SDKs. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleDataTransport/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date. + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleDataTransport.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GDT is intended to launch **before or with** the next Firebase release: +
+ Push to SpecsStaging + + ```console + pod repo push --skip-tests --use-json staging GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests --use-json dev GoogleDataTransport.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, create a workspace and new CL. Then copybara and run a global TAP. +
+  /google/data/ro/teams/copybara/copybara third_party/firebase/ios/Releases/GoogleDataTransport/copy.bara.sky \
+  --piper-description-behavior=OVERWRITE \
+  --destination-cl=YOUR_CL gdt
+  
+ +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleDataTransport/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleDataTransport` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleDataTransport.podspec` in `staging` to make sure the correct spec is being published. + + > [!WARNING] + > Manually update your local SpecsStaging clone or run `pod repo update` + > before proceeding. + + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleDataTransport/{version}/GoogleDataTransport.podspec.json --skip-tests + ``` + + The pod push was successful if the above command logs: `🚀 GoogleDataTransport ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleDataTransport's CocoaPods page](https://cocoapods.org/pods/GoogleDataTransport). + +### [Create GitHub Release](https://github.com/google/GoogleDataTransport/releases/new/) + Update the [release template](https://github.com/google/GoogleDataTransport/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleDataTransport/releases/edit/9.0.1) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleDataTransport/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Set logging level + +### Swift + +- Import `GoogleDataTransport` module: + ```swift + import GoogleDataTransport + ``` +- Set logging level global variable to the desired value before calling `FirebaseApp.configure()`: + ```swift + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevel.debug.rawValue + ``` +### Objective-C + +- Import `GoogleDataTransport`: + ```objective-c + #import + ``` +- Set logging level global variable to the desired value before calling `-[FIRApp configure]`: + ```objective-c + GDTCORConsoleLoggerLoggingLevel = GDTCORLoggingLevelDebug; + ``` + +## Prereqs + +- `gem install --user cocoapods cocoapods-generate` +- `brew install protobuf nanopb-generator` +- `easy_install --user protobuf` + +## To develop + +- Run `./GoogleDataTransport/generate_project.sh` after installing the prereqs + +## When adding new logging endpoint + +- Use commands similar to: + - `python -c "line='https://www.firebase.com'; print line[0::2]" ` + - `python -c "line='https://www.firebase.com'; print line[1::2]" ` + +## When adding internal code that shouldn't be easily usable on github + +- Consider using go/copybara-library/scrubbing#cc_scrub + +## Development + +Ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleDataTransport.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +### Development for Catalyst +* `pod gen GoogleDataTransport.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md) for more information on contributing to the Firebase +iOS SDK. + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-datatransport-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/datatransport/badge.svg diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m new file mode 100644 index 0000000..3b7280e --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULAppDelegateSwizzler.m @@ -0,0 +1,1023 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import +#import + +// Implementations need to be typed before calling the implementation directly to cast the +// arguments and the return types correctly. Otherwise, it will crash the app. +typedef BOOL (*GULRealOpenURLSourceApplicationAnnotationIMP)( + id, SEL, GULApplication *, NSURL *, NSString *, id); + +typedef BOOL (*GULRealOpenURLOptionsIMP)( + id, SEL, GULApplication *, NSURL *, NSDictionary *); + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +typedef void (*GULRealHandleEventsForBackgroundURLSessionIMP)( + id, SEL, GULApplication *, NSString *, void (^)()); +#pragma clang diagnostic pop + +typedef BOOL (*GULRealContinueUserActivityIMP)( + id, SEL, GULApplication *, NSUserActivity *, void (^)(NSArray *restorableObjects)); + +typedef void (*GULRealDidRegisterForRemoteNotificationsIMP)(id, SEL, GULApplication *, NSData *); + +typedef void (*GULRealDidFailToRegisterForRemoteNotificationsIMP)(id, + SEL, + GULApplication *, + NSError *); + +typedef void (*GULRealDidReceiveRemoteNotificationIMP)(id, SEL, GULApplication *, NSDictionary *); + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +typedef void (*GULRealDidReceiveRemoteNotificationWithCompletionIMP)( + id, SEL, GULApplication *, NSDictionary *, void (^)(UIBackgroundFetchResult)); +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + +typedef void (^GULAppDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; + +static NSString *const kGULAppDelegateKeyPath = @"delegate"; + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/AppDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseAppDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the App Delegate. */ +static NSString *const kGULAppDelegatePrefix = @"GUL_"; + +/** The original instance of App Delegate. */ +static id gOriginalAppDelegate; + +/** The original App Delegate class */ +static Class gOriginalAppDelegateClass; + +/** The subclass of the original App Delegate. */ +static Class gAppDelegateSubclass; + +/** Remote notification methods selectors + * + * We have to opt out of referencing APNS related App Delegate methods directly to prevent + * an Apple review warning email about missing Push Notification Entitlement + * (like here: https://github.com/firebase/firebase-ios-sdk/issues/2807). From our experience, the + * warning is triggered when any of the symbols is present in the application sent to review, even + * if the code is never executed. Because GULAppDelegateSwizzler may be used by applications that + * are not using APNS we have to refer to the methods indirectly using selector constructed from + * string. + * + * NOTE: None of the methods is proxied unless it is explicitly requested by calling the method + * +[GULAppDelegateSwizzler proxyOriginalDelegateIncludingAPNSMethods] + */ +static NSString *const kGULDidRegisterForRemoteNotificationsSEL = + @"application:didRegisterForRemoteNotificationsWithDeviceToken:"; +static NSString *const kGULDidFailToRegisterForRemoteNotificationsSEL = + @"application:didFailToRegisterForRemoteNotificationsWithError:"; +static NSString *const kGULDidReceiveRemoteNotificationWithCompletionSEL = + @"application:didReceiveRemoteNotification:fetchCompletionHandler:"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULZeroingWeakContainer +@end + +@interface GULAppDelegateObserver : NSObject +@end + +@implementation GULAppDelegateObserver { + BOOL _isObserving; +} + ++ (GULAppDelegateObserver *)sharedInstance { + static GULAppDelegateObserver *instance; + static dispatch_once_t once; + dispatch_once(&once, ^{ + instance = [[GULAppDelegateObserver alloc] init]; + }); + return instance; +} + +- (void)observeUIApplication { + if (_isObserving) { + return; + } + [[GULAppDelegateSwizzler sharedApplication] + addObserver:self + forKeyPath:kGULAppDelegateKeyPath + options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld + context:nil]; + _isObserving = YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context { + if ([keyPath isEqual:kGULAppDelegateKeyPath]) { + id newValue = change[NSKeyValueChangeNewKey]; + id oldValue = change[NSKeyValueChangeOldKey]; + if ([newValue isEqual:oldValue]) { + return; + } + // Free the stored app delegate instance because it has been changed to a different instance to + // avoid keeping it alive forever. + if ([oldValue isEqual:gOriginalAppDelegate]) { + gOriginalAppDelegate = nil; + // Remove the observer. Parse it to NSObject to avoid warning. + [[GULAppDelegateSwizzler sharedApplication] removeObserver:self + forKeyPath:kGULAppDelegateKeyPath]; + _isObserving = NO; + } + } +} + +@end + +@implementation GULAppDelegateSwizzler + +static dispatch_once_t sProxyAppDelegateOnceToken; +static dispatch_once_t sProxyAppDelegateRemoteNotificationOnceToken; + +#pragma mark - Public methods + ++ (BOOL)isAppDelegateProxyEnabled { + NSDictionary *infoDictionary = [NSBundle mainBundle].infoDictionary; + + id isFirebaseProxyEnabledPlistValue = infoDictionary[kGULFirebaseAppDelegateProxyEnabledPlistKey]; + id isGoogleProxyEnabledPlistValue = + infoDictionary[kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey]; + + // Enabled by default. + BOOL isFirebaseAppDelegateProxyEnabled = YES; + BOOL isGoogleUtilitiesAppDelegateProxyEnabled = YES; + + if ([isFirebaseProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isFirebaseAppDelegateProxyEnabled = [isFirebaseProxyEnabledPlistValue boolValue]; + } + + if ([isGoogleProxyEnabledPlistValue isKindOfClass:[NSNumber class]]) { + isGoogleUtilitiesAppDelegateProxyEnabled = [isGoogleProxyEnabledPlistValue boolValue]; + } + + // Only deactivate the proxy if it is explicitly disabled by app developers using either one of + // the plist flags. + return isFirebaseAppDelegateProxyEnabled && isGoogleUtilitiesAppDelegateProxyEnabled; +} + ++ (GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor { + NSAssert(interceptor, @"AppDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(GULApplicationDelegate)], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling000], + @"AppDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling001], + @"AppDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = [NSString stringWithFormat:@"%@%p", kGULAppDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling002], + @"AppDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULZeroingWeakContainer *weakObject = [[GULZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULAppDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"AppDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"AppDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling003], + @"AppDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULZeroingWeakContainer *weakContainer = [GULAppDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling004], + @"AppDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + ++ (void)proxyOriginalDelegate { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + dispatch_once(&sProxyAppDelegateOnceToken, ^{ + id originalDelegate = + [GULAppDelegateSwizzler sharedApplication].delegate; + [GULAppDelegateSwizzler proxyAppDelegate:originalDelegate]; + }); +} + ++ (void)proxyOriginalDelegateIncludingAPNSMethods { + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + [self proxyOriginalDelegate]; + + dispatch_once(&sProxyAppDelegateRemoteNotificationOnceToken, ^{ + id appDelegate = [GULAppDelegateSwizzler sharedApplication].delegate; + + NSMutableDictionary *realImplementationsBySelector = + [objc_getAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey) mutableCopy]; + + [self proxyRemoteNotificationsMethodsWithAppDelegateSubClass:gAppDelegateSubclass + realClass:gOriginalAppDelegateClass + appDelegate:appDelegate + realImplementationsBySelector:realImplementationsBySelector]; + + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN); + [self reassignAppDelegate]; + }); +} + +#pragma mark - Create proxy + ++ (GULApplication *)sharedApplication { + if ([GULAppEnvironmentUtil isAppExtension]) { + return nil; + } + id sharedApplication = nil; + Class uiApplicationClass = NSClassFromString(kGULApplicationClassName); + if (uiApplicationClass && + [uiApplicationClass respondsToSelector:(NSSelectorFromString(@"sharedApplication"))]) { + sharedApplication = [uiApplicationClass sharedApplication]; + } + return sharedApplication; +} + +#pragma mark - Override default methods + +/** Creates a new subclass of the class of the given object and sets the isa value of the given + * object to the new subclass. Additionally this copies methods to that new subclass that allow us + * to intercept UIApplicationDelegate methods. This is better known as isa swizzling. + * + * @param appDelegate The object to which you want to isa swizzle. This has to conform to the + * UIApplicationDelegate subclass. + * @return Returns the new subclass. + */ ++ (nullable Class)createSubclassWithObject:(id)appDelegate { + Class realClass = [appDelegate class]; + + // Create GUL__ + NSString *classNameWithPrefix = + [kGULAppDelegatePrefix stringByAppendingString:NSStringFromClass(realClass)]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling005], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: %@", + NSStringFromClass(realClass), newClassName); + return nil; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class appDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (appDelegateSubClass == Nil) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling006], + @"Cannot create a proxy for App Delegate. Subclass already exists. Original Class: " + @"%@, subclass: Nil", + NSStringFromClass(realClass)); + return nil; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For application:continueUserActivity:restorationHandler: + SEL continueUserActivitySEL = @selector(application:continueUserActivity:restorationHandler:); + [self proxyDestinationSelector:continueUserActivitySEL + implementationsFromSourceSelector:continueUserActivitySEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + +#if TARGET_OS_IOS || TARGET_OS_TV + // Add the following methods from GULAppDelegate class, and store the real implementation so it + // can forward to the real one. + // For application:openURL:options: + SEL applicationOpenURLOptionsSEL = @selector(application:openURL:options:); + if ([appDelegate respondsToSelector:applicationOpenURLOptionsSEL]) { + // Only add the application:openURL:options: method if the original AppDelegate implements it. + // This fixes a bug if an app only implements application:openURL:sourceApplication:annotation: + // (if we add the `options` method, iOS sees that one exists and does not call the + // `sourceApplication` method, which in this case is the only one the app implements). + + [self proxyDestinationSelector:applicationOpenURLOptionsSEL + implementationsFromSourceSelector:applicationOpenURLOptionsSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + } + + // For application:handleEventsForBackgroundURLSession:completionHandler: + SEL handleEventsForBackgroundURLSessionSEL = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + [self proxyDestinationSelector:handleEventsForBackgroundURLSessionSEL + implementationsFromSourceSelector:handleEventsForBackgroundURLSessionSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + // For application:openURL:sourceApplication:annotation: + SEL openURLSourceApplicationAnnotationSEL = @selector(application: + openURL:sourceApplication:annotation:); + + [self proxyDestinationSelector:openURLSourceApplicationAnnotationSEL + implementationsFromSourceSelector:openURLSourceApplicationAnnotationSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // TARGET_OS_IOS + + // Override the description too so the custom class name will not show up. + [GULAppDelegateSwizzler addInstanceMethodWithDestinationSelector:@selector(description) + withImplementationFromSourceSelector:@selector(fakeDescription) + fromClass:[self class] + toClass:appDelegateSubClass]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(appDelegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(appDelegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(appDelegateSubClass)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling007], + @"Cannot create subclass of App Delegate, because the created subclass is not the " + @"same size. %@", + NSStringFromClass(realClass)); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return nil; + } + + // Make the newly created class to be the subclass of the real App Delegate class. + objc_registerClassPair(appDelegateSubClass); + if (object_setClass(appDelegate, appDelegateSubClass)) { + GULOSLogDebug(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling008], + @"Successfully created App Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULAppDelegateSwizzler correctAppDelegateProxyKey]); + } + + return appDelegateSubClass; +} + ++ (void)proxyRemoteNotificationsMethodsWithAppDelegateSubClass:(Class)appDelegateSubClass + realClass:(Class)realClass + appDelegate:(id)appDelegate + realImplementationsBySelector: + (NSMutableDictionary *)realImplementationsBySelector { + if (realClass == nil || appDelegateSubClass == nil || appDelegate == nil || + realImplementationsBySelector == nil) { + // The App Delegate has not been swizzled. + return; + } + + // For application:didRegisterForRemoteNotificationsWithDeviceToken: + SEL didRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + SEL didRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didRegisterForRemoteNotificationsWithDeviceToken:); + + [self proxyDestinationSelector:didRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didFailToRegisterForRemoteNotificationsWithError: + SEL didFailToRegisterForRemoteNotificationsSEL = + NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + SEL didFailToRegisterForRemoteNotificationsDonorSEL = @selector(application: + donor_didFailToRegisterForRemoteNotificationsWithError:); + + [self proxyDestinationSelector:didFailToRegisterForRemoteNotificationsSEL + implementationsFromSourceSelector:didFailToRegisterForRemoteNotificationsDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // For application:didReceiveRemoteNotification:fetchCompletionHandler: +#if !TARGET_OS_WATCH && !TARGET_OS_OSX + SEL didReceiveRemoteNotificationWithCompletionSEL = + NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + SEL didReceiveRemoteNotificationWithCompletionDonorSEL = + @selector(application:donor_didReceiveRemoteNotification:fetchCompletionHandler:); + [self proxyDestinationSelector:didReceiveRemoteNotificationWithCompletionSEL + implementationsFromSourceSelector:didReceiveRemoteNotificationWithCompletionDonorSEL + fromClass:[GULAppDelegateSwizzler class] + toClass:appDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX +} + +/// We have to do this to invalidate the cache that caches the original respondsToSelector of +/// openURL handlers. Without this, it won't call the default implementations because the system +/// checks and caches them. +/// Register KVO only once. Otherwise, the observing method will be called as many times as +/// being registered. ++ (void)reassignAppDelegate { +#if !TARGET_OS_WATCH + id delegate = [self sharedApplication].delegate; + [self sharedApplication].delegate = nil; + [self sharedApplication].delegate = delegate; + gOriginalAppDelegate = delegate; + [[GULAppDelegateObserver sharedInstance] observeUIApplication]; +#endif +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULAppDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULAppDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULAppDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULAppDelegateInterceptorCallback)callback { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULAppDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeAppDelegateSwizzling010], + @"AppDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULAppDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + +// The methods below are donor methods which are added to the dynamic subclass of the App Delegate. +// They are called within the scope of the real App Delegate so |self| does not refer to the +// GULAppDelegateSwizzler instance but the real App Delegate instance. + +#pragma mark - [Donor Methods] Overridden instance description method + +- (NSString *)fakeDescription { + Class realClass = objc_getAssociatedObject(self, &kGULRealClassKey); + return [NSString stringWithFormat:@"<%@: %p>", realClass, self]; +} + +#pragma mark - [Donor Methods] URL overridden handler methods +#if TARGET_OS_IOS || TARGET_OS_TV + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + options:(NSDictionary *)options { + SEL methodSelector = @selector(application:openURL:options:); + // Call the real implementation if the real App Delegate has any. + NSValue *openURLIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLOptionsIMP openURLOptionsIMP = [openURLIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + +// This is needed to for the library to be warning free on iOS versions < 9. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunguarded-availability" + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + openURL:url + options:options]; + }]; +#pragma clang diagnostic pop + if (openURLOptionsIMP) { + returnedValue |= openURLOptionsIMP(self, methodSelector, application, url, options); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#if TARGET_OS_IOS + +- (BOOL)application:(GULApplication *)application + openURL:(NSURL *)url + sourceApplication:(NSString *)sourceApplication + annotation:(id)annotation { + SEL methodSelector = @selector(application:openURL:sourceApplication:annotation:); + + // Call the real implementation if the real App Delegate has any. + NSValue *openURLSourceAppAnnotationIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealOpenURLSourceApplicationAnnotationIMP openURLSourceApplicationAnnotationIMP = + [openURLSourceAppAnnotationIMPPointer pointerValue]; + + __block BOOL returnedValue = NO; + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + returnedValue |= [interceptor application:application + openURL:url + sourceApplication:sourceApplication + annotation:annotation]; +#pragma clang diagnostic pop + }]; + if (openURLSourceApplicationAnnotationIMP) { + returnedValue |= openURLSourceApplicationAnnotationIMP(self, methodSelector, application, url, + sourceApplication, annotation); + } + return returnedValue; +} + +#endif // TARGET_OS_IOS + +#pragma mark - [Donor Methods] Network overridden handler methods + +#if TARGET_OS_IOS || TARGET_OS_TV + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrict-prototypes" +- (void)application:(GULApplication *)application + handleEventsForBackgroundURLSession:(NSString *)identifier + completionHandler:(void (^)())completionHandler { +#pragma clang diagnostic pop + SEL methodSelector = @selector(application: + handleEventsForBackgroundURLSession:completionHandler:); + NSValue *handleBackgroundSessionPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealHandleEventsForBackgroundURLSessionIMP handleBackgroundSessionIMP = + [handleBackgroundSessionPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + [interceptor application:application + handleEventsForBackgroundURLSession:identifier + completionHandler:completionHandler]; + }]; + // Call the real implementation if the real App Delegate has any. + if (handleBackgroundSessionIMP) { + handleBackgroundSessionIMP(self, methodSelector, application, identifier, completionHandler); + } +} + +#endif // TARGET_OS_IOS || TARGET_OS_TV + +#pragma mark - [Donor Methods] User Activities overridden handler methods + +- (BOOL)application:(GULApplication *)application + continueUserActivity:(NSUserActivity *)userActivity + restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { + SEL methodSelector = @selector(application:continueUserActivity:restorationHandler:); + NSValue *continueUserActivityIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealContinueUserActivityIMP continueUserActivityIMP = + continueUserActivityIMPPointer.pointerValue; + + __block BOOL returnedValue = NO; +#if !TARGET_OS_WATCH + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + returnedValue |= [interceptor application:application + continueUserActivity:userActivity + restorationHandler:restorationHandler]; + }]; +#endif + // Call the real implementation if the real App Delegate has any. + if (continueUserActivityIMP) { + returnedValue |= continueUserActivityIMP(self, methodSelector, application, userActivity, + restorationHandler); + } + return returnedValue; +} + +#pragma mark - [Donor Methods] Remote Notifications + +- (void)application:(GULApplication *)application + donor_didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { + SEL methodSelector = NSSelectorFromString(kGULDidRegisterForRemoteNotificationsSEL); + + NSValue *didRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidRegisterForRemoteNotificationsIMP didRegisterForRemoteNotificationsIMP = + [didRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&deviceToken) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didRegisterForRemoteNotificationsIMP) { + didRegisterForRemoteNotificationsIMP(self, methodSelector, application, deviceToken); + } +} + +- (void)application:(GULApplication *)application + donor_didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { + SEL methodSelector = NSSelectorFromString(kGULDidFailToRegisterForRemoteNotificationsSEL); + NSValue *didFailToRegisterForRemoteNotificationsIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidFailToRegisterForRemoteNotificationsIMP didFailToRegisterForRemoteNotificationsIMP = + [didFailToRegisterForRemoteNotificationsIMPPointer pointerValue]; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&error) atIndex:3]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didFailToRegisterForRemoteNotificationsIMP) { + didFailToRegisterForRemoteNotificationsIMP(self, methodSelector, application, error); + } +} + +#if !TARGET_OS_WATCH && !TARGET_OS_OSX +- (void)application:(GULApplication *)application + donor_didReceiveRemoteNotification:(NSDictionary *)userInfo + fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { + SEL methodSelector = NSSelectorFromString(kGULDidReceiveRemoteNotificationWithCompletionSEL); + NSValue *didReceiveRemoteNotificationWithCompletionIMPPointer = + [GULAppDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULRealDidReceiveRemoteNotificationWithCompletionIMP + didReceiveRemoteNotificationWithCompletionIMP = + [didReceiveRemoteNotificationWithCompletionIMPPointer pointerValue]; + + dispatch_group_t __block callbackGroup = dispatch_group_create(); + NSMutableArray *__block fetchResults = [NSMutableArray array]; + + void (^localCompletionHandler)(UIBackgroundFetchResult) = + ^void(UIBackgroundFetchResult fetchResult) { + [fetchResults addObject:[NSNumber numberWithInt:(int)fetchResult]]; + dispatch_group_leave(callbackGroup); + }; + + // Notify interceptors. + [GULAppDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + dispatch_group_enter(callbackGroup); + + NSInvocation *invocation = [GULAppDelegateSwizzler + appDelegateInvocationForSelector:methodSelector]; + [invocation setTarget:interceptor]; + [invocation setSelector:methodSelector]; + [invocation setArgument:(void *)(&application) atIndex:2]; + [invocation setArgument:(void *)(&userInfo) atIndex:3]; + [invocation setArgument:(void *)(&localCompletionHandler) + atIndex:4]; + [invocation invoke]; + }]; + // Call the real implementation if the real App Delegate has any. + if (didReceiveRemoteNotificationWithCompletionIMP) { + dispatch_group_enter(callbackGroup); + + didReceiveRemoteNotificationWithCompletionIMP(self, methodSelector, application, userInfo, + localCompletionHandler); + } + + dispatch_group_notify(callbackGroup, dispatch_get_main_queue(), ^() { + BOOL allFetchesFailed = YES; + BOOL anyFetchHasNewData = NO; + + for (NSNumber *oneResult in fetchResults) { + UIBackgroundFetchResult result = oneResult.intValue; + + switch (result) { + case UIBackgroundFetchResultNoData: + allFetchesFailed = NO; + break; + case UIBackgroundFetchResultNewData: + allFetchesFailed = NO; + anyFetchHasNewData = YES; + break; + case UIBackgroundFetchResultFailed: + + break; + } + } + + UIBackgroundFetchResult finalFetchResult = UIBackgroundFetchResultNoData; + + if (allFetchesFailed) { + finalFetchResult = UIBackgroundFetchResultFailed; + } else if (anyFetchHasNewData) { + finalFetchResult = UIBackgroundFetchResultNewData; + } else { + finalFetchResult = UIBackgroundFetchResultNoData; + } + + completionHandler(finalFetchResult); + }); +} +#endif // !TARGET_OS_WATCH && !TARGET_OS_OSX + ++ (nullable NSInvocation *)appDelegateInvocationForSelector:(SEL)selector { + struct objc_method_description methodDescription = + protocol_getMethodDescription(@protocol(GULApplicationDelegate), selector, NO, YES); + if (methodDescription.types == NULL) { + return nil; + } + + NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:methodDescription.types]; + return [NSInvocation invocationWithMethodSignature:signature]; +} + ++ (void)proxyAppDelegate:(id)appDelegate { + if (![appDelegate conformsToProtocol:@protocol(GULApplicationDelegate)]) { + GULOSLogNotice( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate], + @"App Delegate does not conform to UIApplicationDelegate protocol. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + id originalDelegate = appDelegate; + // Do not create a subclass if it is not enabled. + if (![GULAppDelegateSwizzler isAppDelegateProxyEnabled]) { + GULOSLogNotice(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling011], + @"App Delegate Proxy is disabled. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + // Do not accept nil delegate. + if (!originalDelegate) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling012], + @"Cannot create App Delegate Proxy because App Delegate instance is nil. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } + + @try { + gOriginalAppDelegateClass = [originalDelegate class]; + gAppDelegateSubclass = [self createSubclassWithObject:originalDelegate]; + [self reassignAppDelegate]; + } @catch (NSException *exception) { + GULOSLogError(kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeAppDelegateSwizzling013], + @"Cannot create App Delegate Proxy. %@", + [GULAppDelegateSwizzler correctAlternativeWhenAppDelegateProxyNotCreated]); + return; + } +} + +#pragma mark - Methods to print correct debug logs + ++ (NSString *)correctAppDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseAppDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesAppDelegateProxyEnabledPlistKey; +} + ++ (NSString *)correctAlternativeWhenAppDelegateProxyNotCreated { + return NSClassFromString(@"FIRCore") + ? @"To log deep link campaigns manually, call the methods in " + @"FIRAnalytics+AppDelegate.h." + : @""; +} + +#pragma mark - Private Methods for Testing + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (void)resetProxyOriginalDelegateOnceToken { + sProxyAppDelegateOnceToken = 0; + sProxyAppDelegateRemoteNotificationOnceToken = 0; +} + ++ (id)originalDelegate { + return gOriginalAppDelegate; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m new file mode 100644 index 0000000..87adac4 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/GULSceneDelegateSwizzler.m @@ -0,0 +1,444 @@ +// Copyright 2019 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" + +#import "GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h" +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +#import + +#if UISCENE_SUPPORTED +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (*GULOpenURLContextsIMP)(id, SEL, UIScene *, NSSet *); + +API_AVAILABLE(ios(13.0), tvos(13.0)) +typedef void (^GULSceneDelegateInterceptorCallback)(id); + +// The strings below are the keys for associated objects. +static char const *const kGULRealIMPBySelectorKey = "GUL_realIMPBySelector"; +static char const *const kGULRealClassKey = "GUL_realClass"; +#endif // UISCENE_SUPPORTED + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/SceneDelegateSwizzler]"; + +// Since Firebase SDKs also use this for app delegate proxying, in order to not be a breaking change +// we disable App Delegate proxying when either of these two flags are set to NO. + +/** Plist key that allows Firebase developers to disable App and Scene Delegate Proxying. */ +static NSString *const kGULFirebaseSceneDelegateProxyEnabledPlistKey = + @"FirebaseAppDelegateProxyEnabled"; + +/** Plist key that allows developers not using Firebase to disable App and Scene Delegate Proxying. + */ +static NSString *const kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey = + @"GoogleUtilitiesAppDelegateProxyEnabled"; + +/** The prefix of the Scene Delegate. */ +static NSString *const kGULSceneDelegatePrefix = @"GUL_"; + +/** + * This class is necessary to store the delegates in an NSArray without retaining them. + * [NSValue valueWithNonRetainedObject] also provides this functionality, but does not provide a + * zeroing pointer. This will cause EXC_BAD_ACCESS when trying to access the object after it is + * dealloced. Instead, this container stores a weak, zeroing reference to the object, which + * automatically is set to nil by the runtime when the object is dealloced. + */ +@interface GULSceneZeroingWeakContainer : NSObject + +/** Stores a weak object. */ +@property(nonatomic, weak) id object; + +@end + +@implementation GULSceneZeroingWeakContainer +@end + +@implementation GULSceneDelegateSwizzler + +#pragma mark - Public methods + ++ (BOOL)isSceneDelegateProxyEnabled { + return [GULAppDelegateSwizzler isAppDelegateProxyEnabled]; +} + ++ (void)proxyOriginalSceneDelegate { +#if UISCENE_SUPPORTED + if ([GULAppEnvironmentUtil isAppExtension]) { + return; + } + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + if (@available(iOS 13.0, tvOS 13.0, *)) { + if (![GULSceneDelegateSwizzler isSceneDelegateProxyEnabled]) { + return; + } + [[NSNotificationCenter defaultCenter] + addObserver:self + selector:@selector(handleSceneWillConnectToNotification:) + name:UISceneWillConnectNotification + object:nil]; + } + }); +#endif // UISCENE_SUPPORTED +} + +#if UISCENE_SUPPORTED ++ (GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor:(id)interceptor { + NSAssert(interceptor, @"SceneDelegateProxy cannot add nil interceptor"); + NSAssert([interceptor conformsToProtocol:@protocol(UISceneDelegate)], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + + if (!interceptor) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling000], + @"SceneDelegateProxy cannot add nil interceptor."); + return nil; + } + if (![interceptor conformsToProtocol:@protocol(UISceneDelegate)]) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling001], + @"SceneDelegateProxy interceptor does not conform to UIApplicationDelegate"); + return nil; + } + + // The ID should be the same given the same interceptor object. + NSString *interceptorID = + [NSString stringWithFormat:@"%@%p", kGULSceneDelegatePrefix, interceptor]; + if (!interceptorID.length) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling002], + @"SceneDelegateProxy cannot create Interceptor ID."); + return nil; + } + GULSceneZeroingWeakContainer *weakObject = [[GULSceneZeroingWeakContainer alloc] init]; + weakObject.object = interceptor; + [GULSceneDelegateSwizzler interceptors][interceptorID] = weakObject; + return interceptorID; +} + ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID { + NSAssert(interceptorID, @"SceneDelegateProxy cannot unregister nil interceptor ID."); + NSAssert(((NSString *)interceptorID).length != 0, + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + + if (!interceptorID) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling003], + @"SceneDelegateProxy cannot unregister empty interceptor ID."); + return; + } + + GULSceneZeroingWeakContainer *weakContainer = + [GULSceneDelegateSwizzler interceptors][interceptorID]; + if (!weakContainer.object) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling004], + @"SceneDelegateProxy cannot unregister interceptor that was not registered. " + "Interceptor ID %@", + interceptorID); + return; + } + + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:interceptorID]; +} + +#pragma mark - Helper methods + ++ (GULMutableDictionary *)interceptors { + static dispatch_once_t onceToken; + static GULMutableDictionary *sInterceptors; + dispatch_once(&onceToken, ^{ + sInterceptors = [[GULMutableDictionary alloc] init]; + }); + return sInterceptors; +} + ++ (void)clearInterceptors { + [[self interceptors] removeAllObjects]; +} + ++ (nullable NSValue *)originalImplementationForSelector:(SEL)selector object:(id)object { + NSDictionary *realImplementationBySelector = + objc_getAssociatedObject(object, &kGULRealIMPBySelectorKey); + return realImplementationBySelector[NSStringFromSelector(selector)]; +} + ++ (void)proxyDestinationSelector:(SEL)destinationSelector + implementationsFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)sourceClass + toClass:(Class)destinationClass + realClass:(Class)realClass + storeDestinationImplementationTo: + (NSMutableDictionary *)destinationImplementationsBySelector { + [self addInstanceMethodWithDestinationSelector:destinationSelector + withImplementationFromSourceSelector:sourceSelector + fromClass:sourceClass + toClass:destinationClass]; + IMP sourceImplementation = + [GULSceneDelegateSwizzler implementationOfMethodSelector:destinationSelector + fromClass:realClass]; + NSValue *sourceImplementationPointer = [NSValue valueWithPointer:sourceImplementation]; + + NSString *destinationSelectorString = NSStringFromSelector(destinationSelector); + destinationImplementationsBySelector[destinationSelectorString] = sourceImplementationPointer; +} + +/** Copies a method identified by the methodSelector from one class to the other. After this method + * is called, performing [toClassInstance methodSelector] will be similar to calling + * [fromClassInstance methodSelector]. This method does nothing if toClass already has a method + * identified by methodSelector. + * + * @param methodSelector The SEL that identifies both the method on the fromClass as well as the + * one on the toClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithSelector:(SEL)methodSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + [self addInstanceMethodWithDestinationSelector:methodSelector + withImplementationFromSourceSelector:methodSelector + fromClass:fromClass + toClass:toClass]; +} + +/** Copies a method identified by the sourceSelector from the fromClass as a method for the + * destinationSelector on the toClass. After this method is called, performing + * [toClassInstance destinationSelector] will be similar to calling + * [fromClassInstance sourceSelector]. This method does nothing if toClass already has a method + * identified by destinationSelector. + * + * @param destinationSelector The SEL that identifies the method on the toClass. + * @param sourceSelector The SEL that identifies the method on the fromClass. + * @param fromClass The class from which a method is sourced. + * @param toClass The class to which the method is added. If the class already has a method with + * the same selector, this has no effect. + */ ++ (void)addInstanceMethodWithDestinationSelector:(SEL)destinationSelector + withImplementationFromSourceSelector:(SEL)sourceSelector + fromClass:(Class)fromClass + toClass:(Class)toClass { + Method method = class_getInstanceMethod(fromClass, sourceSelector); + IMP methodIMP = method_getImplementation(method); + const char *types = method_getTypeEncoding(method); + if (!class_addMethod(toClass, destinationSelector, methodIMP, types)) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling009], + @"Cannot copy method to destination selector %@ as it already exists", + NSStringFromSelector(destinationSelector)); + } +} + +/** Gets the IMP of the instance method on the class identified by the selector. + * + * @param selector The selector of which the IMP is to be fetched. + * @param aClass The class from which the IMP is to be fetched. + * @return The IMP of the instance method identified by selector and aClass. + */ ++ (IMP)implementationOfMethodSelector:(SEL)selector fromClass:(Class)aClass { + Method aMethod = class_getInstanceMethod(aClass, selector); + return method_getImplementation(aMethod); +} + +/** Enumerates through all the interceptors and if they respond to a given selector, executes a + * GULSceneDelegateInterceptorCallback with the interceptor. + * + * @param methodSelector The SEL to check if an interceptor responds to. + * @param callback the GULSceneDelegateInterceptorCallback. + */ ++ (void)notifyInterceptorsWithMethodSelector:(SEL)methodSelector + callback:(GULSceneDelegateInterceptorCallback)callback + API_AVAILABLE(ios(13.0)) { + if (!callback) { + return; + } + + NSDictionary *interceptors = [GULSceneDelegateSwizzler interceptors].dictionary; + [interceptors enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { + GULSceneZeroingWeakContainer *interceptorContainer = obj; + id interceptor = interceptorContainer.object; + if (!interceptor) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString stringWithFormat:@"I-SWZ%06ld", + (long)kGULSwizzlerMessageCodeSceneDelegateSwizzling010], + @"SceneDelegateProxy cannot find interceptor with ID %@. Removing the interceptor.", key); + [[GULSceneDelegateSwizzler interceptors] removeObjectForKey:key]; + return; + } + if ([interceptor respondsToSelector:methodSelector]) { + callback(interceptor); + } + }]; +} + ++ (void)handleSceneWillConnectToNotification:(NSNotification *)notification { + if (@available(iOS 13.0, tvOS 13.0, *)) { + if ([notification.object isKindOfClass:[UIScene class]]) { + UIScene *scene = (UIScene *)notification.object; + [GULSceneDelegateSwizzler proxySceneDelegateIfNeeded:scene]; + } + } +} + +#pragma mark - [Donor Methods] UISceneDelegate URL handler + +- (void)scene:(UIScene *)scene + openURLContexts:(NSSet *)URLContexts API_AVAILABLE(ios(13.0), tvos(13.0)) { + if (@available(iOS 13.0, tvOS 13.0, *)) { + SEL methodSelector = @selector(scene:openURLContexts:); + // Call the real implementation if the real Scene Delegate has any. + NSValue *openURLContextsIMPPointer = + [GULSceneDelegateSwizzler originalImplementationForSelector:methodSelector object:self]; + GULOpenURLContextsIMP openURLContextsIMP = [openURLContextsIMPPointer pointerValue]; + + [GULSceneDelegateSwizzler + notifyInterceptorsWithMethodSelector:methodSelector + callback:^(id interceptor) { + if ([interceptor + conformsToProtocol:@protocol(UISceneDelegate)]) { + id sceneInterceptor = + (id)interceptor; + [sceneInterceptor scene:scene openURLContexts:URLContexts]; + } + }]; + + if (openURLContextsIMP) { + openURLContextsIMP(self, methodSelector, scene, URLContexts); + } + } +} + ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene { + Class realClass = [scene.delegate class]; + NSString *className = NSStringFromClass(realClass); + + // Skip proxying if failed to get the delegate class name for some reason (e.g. `delegate == nil`) + // or the class has a prefix of kGULAppDelegatePrefix, which means it has been proxied before. + if (className == nil || [className hasPrefix:kGULSceneDelegatePrefix]) { + return; + } + + NSString *classNameWithPrefix = [kGULSceneDelegatePrefix stringByAppendingString:className]; + NSString *newClassName = + [NSString stringWithFormat:@"%@-%@", classNameWithPrefix, [NSUUID UUID].UUIDString]; + + if (NSClassFromString(newClassName)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: %@", + className, newClassName); + return; + } + + // Register the new class as subclass of the real one. Do not allocate more than the real class + // size. + Class sceneDelegateSubClass = objc_allocateClassPair(realClass, newClassName.UTF8String, 0); + if (sceneDelegateSubClass == Nil) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create a proxy for Scene Delegate. Subclass already exists. Original Class" + @": %@, subclass: Nil", + className); + return; + } + + NSMutableDictionary *realImplementationsBySelector = + [[NSMutableDictionary alloc] init]; + + // For scene:openURLContexts: + SEL openURLContextsSEL = @selector(scene:openURLContexts:); + [self proxyDestinationSelector:openURLContextsSEL + implementationsFromSourceSelector:openURLContextsSEL + fromClass:[GULSceneDelegateSwizzler class] + toClass:sceneDelegateSubClass + realClass:realClass + storeDestinationImplementationTo:realImplementationsBySelector]; + + // Store original implementations to a fake property of the original delegate. + objc_setAssociatedObject(scene.delegate, &kGULRealIMPBySelectorKey, + [realImplementationsBySelector copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + objc_setAssociatedObject(scene.delegate, &kGULRealClassKey, realClass, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); + + // The subclass size has to be exactly the same size with the original class size. The subclass + // cannot have more ivars/properties than its superclass since it will cause an offset in memory + // that can lead to overwriting the isa of an object in the next frame. + if (class_getInstanceSize(realClass) != class_getInstanceSize(sceneDelegateSubClass)) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Cannot create subclass of Scene Delegate, because the created subclass is not the " + @"same size. %@", + className); + NSAssert(NO, @"Classes must be the same size to swizzle isa"); + return; + } + + // Make the newly created class to be the subclass of the real Scene Delegate class. + objc_registerClassPair(sceneDelegateSubClass); + if (object_setClass(scene.delegate, sceneDelegateSubClass)) { + GULOSLogDebug( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", + (long) + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate], + @"Successfully created Scene Delegate Proxy automatically. To disable the " + @"proxy, set the flag %@ to NO (Boolean) in the Info.plist", + [GULSceneDelegateSwizzler correctSceneDelegateProxyKey]); + } +} + ++ (NSString *)correctSceneDelegateProxyKey { + return NSClassFromString(@"FIRCore") ? kGULFirebaseSceneDelegateProxyEnabledPlistKey + : kGULGoogleUtilitiesSceneDelegateProxyEnabledPlistKey; +} + +#endif // UISCENE_SUPPORTED + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h new file mode 100644 index 0000000..38e9315 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULAppDelegateSwizzler_Private.h @@ -0,0 +1,55 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@class GULApplication; + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppDelegateSwizzler () + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param appDelegate The object that needs to be isa swizzled. This should conform to the + * application delegate protocol. + */ ++ (void)proxyAppDelegate:(id)appDelegate; + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** Resets the token that prevents the app delegate proxy from being isa swizzled multiple times. */ ++ (void)resetProxyOriginalDelegateOnceToken; + +/** Returns the original app delegate that was proxied. + * + * @return The original app delegate instance that was proxied. + */ ++ (id)originalDelegate; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h new file mode 100644 index 0000000..89896f7 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Internal/GULSceneDelegateSwizzler_Private.h @@ -0,0 +1,48 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import "GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface GULSceneDelegateSwizzler () + +#if UISCENE_SUPPORTED + +/** Returns a dictionary containing interceptor IDs mapped to a GULZeroingWeakContainer. + * + * @return A dictionary of the form {NSString : GULZeroingWeakContainer}, where the NSString is + * the interceptorID. + */ ++ (GULMutableDictionary *)interceptors; + +/** Deletes all the registered interceptors. */ ++ (void)clearInterceptors; + +/** ISA Swizzles the given appDelegate as the original app delegate would be. + * + * @param scene The scene whose delegate needs to be isa swizzled. This should conform to the + * scene delegate protocol. + */ ++ (void)proxySceneDelegateIfNeeded:(UIScene *)scene API_AVAILABLE(ios(13.0), tvos(13.0)); + +#endif // UISCENE_SUPPORTED + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h new file mode 100644 index 0000000..58dec49 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULAppDelegateSwizzler.h @@ -0,0 +1,107 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULApplication.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULAppDelegateInterceptorID; + +/** This class contains methods that isa swizzle the app delegate. */ +@interface GULAppDelegateSwizzler : NSProxy + +/** Registers an app delegate interceptor whose methods will be invoked as they're invoked on the + * original app delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULAppDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULAppDelegateInterceptorID)registerAppDelegateInterceptor: + (id)interceptor; + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterAppDelegateInterceptorWithID:(GULAppDelegateInterceptorID)interceptorID; + +/** This method ensures that the original app delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the app delegate once). + * + * This method doesn't proxy APNS related methods: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * To proxy these methods use +[GULAppDelegateSwizzler + * proxyOriginalDelegateIncludingAPNSMethods]. The methods have to be proxied separately to + * avoid potential warnings from Apple review about missing Push Notification Entitlement (e.g. + * https://github.com/firebase/firebase-ios-sdk/issues/2807) + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegateIncludingAPNSMethods + */ ++ (void)proxyOriginalDelegate; + +/** This method ensures that the original app delegate has been proxied including APNS related + * methods. Call this before registering your interceptor. This method is safe to call multiple + * times (but it only proxies the app delegate once) or + * after +[GULAppDelegateSwizzler proxyOriginalDelegate] + * + * This method calls +[GULAppDelegateSwizzler proxyOriginalDelegate] under the hood. + * After calling this method the following App Delegate methods will be proxied in addition to + * the methods proxied by proxyOriginalDelegate: + * @code + * - application:didRegisterForRemoteNotificationsWithDeviceToken: + * - application:didFailToRegisterForRemoteNotificationsWithError: + * - application:didReceiveRemoteNotification:fetchCompletionHandler: + * - application:didReceiveRemoteNotification: + * @endcode + * + * The method has no effect for extensions. + * + * @see proxyOriginalDelegate + */ ++ (void)proxyOriginalDelegateIncludingAPNSMethods; + +/** Indicates whether app delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if AppDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isAppDelegateProxyEnabled; + +/** Returns the current sharedApplication. + * + * @return the current application instance if in an app, or nil if in extension or if it doesn't + * exist. + */ ++ (nullable GULApplication *)sharedApplication; + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h new file mode 100644 index 0000000..9311a17 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULApplication.h @@ -0,0 +1,50 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + +#import + +#define GULApplication UIApplication +#define GULApplicationDelegate UIApplicationDelegate +#define GULUserActivityRestoring UIUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"UIApplication"; + +#elif TARGET_OS_OSX + +#import + +#define GULApplication NSApplication +#define GULApplicationDelegate NSApplicationDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"NSApplication"; + +#elif TARGET_OS_WATCH + +#import + +// We match the according watchOS API but swizzling should not work in watch +#define GULApplication WKExtension +#define GULApplicationDelegate WKExtensionDelegate +#define GULUserActivityRestoring NSUserActivityRestoring + +static NSString *const kGULApplicationClassName = @"WKExtension"; + +#endif diff --git a/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h new file mode 100644 index 0000000..d6d8937 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/AppDelegateSwizzler/Public/GoogleUtilities/GULSceneDelegateSwizzler.h @@ -0,0 +1,76 @@ +/* + * Copyright 2019 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#import + +#if __has_include() +#import +#endif + +#if TARGET_OS_IOS || TARGET_OS_TV +#define UISCENE_SUPPORTED 1 +#endif + +NS_ASSUME_NONNULL_BEGIN + +typedef NSString *const GULSceneDelegateInterceptorID; + +/** This class contains methods that isa swizzle the scene delegate. */ +@interface GULSceneDelegateSwizzler : NSProxy + +#if UISCENE_SUPPORTED + +/** Registers a scene delegate interceptor whose methods will be invoked as they're invoked on the + * original scene delegate. + * + * @param interceptor An instance of a class that conforms to the application delegate protocol. + * The interceptor is NOT retained. + * @return A unique GULSceneDelegateInterceptorID if interceptor was successfully registered; nil + * if it fails. + */ ++ (nullable GULSceneDelegateInterceptorID)registerSceneDelegateInterceptor: + (id)interceptor API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Unregisters an interceptor with the given ID if it exists. + * + * @param interceptorID The object that was generated when the interceptor was registered. + */ ++ (void)unregisterSceneDelegateInterceptorWithID:(GULSceneDelegateInterceptorID)interceptorID + API_AVAILABLE(ios(13.0), tvos(13.0)); + +/** Do not initialize this class. */ +- (instancetype)init NS_UNAVAILABLE; + +#endif // UISCENE_SUPPORTED + +/** This method ensures that the original scene delegate has been proxied. Call this before + * registering your interceptor. This method is safe to call multiple times (but it only proxies + * the scene delegate once). + * + * The method has no effect for extensions. + */ ++ (void)proxyOriginalSceneDelegate; + +/** Indicates whether scene delegate proxy is explicitly disabled or enabled. Enabled by default. + * + * @return YES if SceneDelegateProxy is Enabled, NO otherwise. + */ ++ (BOOL)isSceneDelegateProxyEnabled; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h b/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h new file mode 100644 index 0000000..053ce84 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Common/GULLoggerCodes.h @@ -0,0 +1,56 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +typedef NS_ENUM(NSInteger, GULSwizzlerMessageCode) { + // App Delegate Swizzling. + kGULSwizzlerMessageCodeAppDelegateSwizzling000 = 1000, // I-SWZ001000 + kGULSwizzlerMessageCodeAppDelegateSwizzling001 = 1001, // I-SWZ001001 + kGULSwizzlerMessageCodeAppDelegateSwizzling002 = 1002, // I-SWZ001002 + kGULSwizzlerMessageCodeAppDelegateSwizzling003 = 1003, // I-SWZ001003 + kGULSwizzlerMessageCodeAppDelegateSwizzling004 = 1004, // I-SWZ001004 + kGULSwizzlerMessageCodeAppDelegateSwizzling005 = 1005, // I-SWZ001005 + kGULSwizzlerMessageCodeAppDelegateSwizzling006 = 1006, // I-SWZ001006 + kGULSwizzlerMessageCodeAppDelegateSwizzling007 = 1007, // I-SWZ001007 + kGULSwizzlerMessageCodeAppDelegateSwizzling008 = 1008, // I-SWZ001008 + kGULSwizzlerMessageCodeAppDelegateSwizzling009 = 1009, // I-SWZ001009 + kGULSwizzlerMessageCodeAppDelegateSwizzling010 = 1010, // I-SWZ001010 + kGULSwizzlerMessageCodeAppDelegateSwizzling011 = 1011, // I-SWZ001011 + kGULSwizzlerMessageCodeAppDelegateSwizzling012 = 1012, // I-SWZ001012 + kGULSwizzlerMessageCodeAppDelegateSwizzling013 = 1013, // I-SWZ001013 + kGULSwizzlerMessageCodeAppDelegateSwizzlingInvalidAppDelegate = 1014, // I-SWZ001014 + + // Scene Delegate Swizzling. + kGULSwizzlerMessageCodeSceneDelegateSwizzling000 = 1100, // I-SWZ001100 + kGULSwizzlerMessageCodeSceneDelegateSwizzling001 = 1101, // I-SWZ001101 + kGULSwizzlerMessageCodeSceneDelegateSwizzling002 = 1102, // I-SWZ001102 + kGULSwizzlerMessageCodeSceneDelegateSwizzling003 = 1103, // I-SWZ001103 + kGULSwizzlerMessageCodeSceneDelegateSwizzling004 = 1104, // I-SWZ001104 + kGULSwizzlerMessageCodeSceneDelegateSwizzling005 = 1105, // I-SWZ001105 + kGULSwizzlerMessageCodeSceneDelegateSwizzling006 = 1106, // I-SWZ001106 + kGULSwizzlerMessageCodeSceneDelegateSwizzling007 = 1107, // I-SWZ001107 + kGULSwizzlerMessageCodeSceneDelegateSwizzling008 = 1108, // I-SWZ001108 + kGULSwizzlerMessageCodeSceneDelegateSwizzling009 = 1109, // I-SWZ001109 + kGULSwizzlerMessageCodeSceneDelegateSwizzling010 = 1110, // I-SWZ001110 + kGULSwizzlerMessageCodeSceneDelegateSwizzling011 = 1111, // I-SWZ001111 + kGULSwizzlerMessageCodeSceneDelegateSwizzling012 = 1112, // I-SWZ001112 + kGULSwizzlerMessageCodeSceneDelegateSwizzling013 = 1113, // I-SWZ001113 + kGULSwizzlerMessageCodeSceneDelegateSwizzlingInvalidSceneDelegate = 1114, // I-SWZ001114 + + // Method Swizzling. + kGULSwizzlerMessageCodeMethodSwizzling000 = 2000, // I-SWZ002000 +}; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m new file mode 100644 index 0000000..7aa5840 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/GULAppEnvironmentUtil.m @@ -0,0 +1,281 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" + +#import +#import +#import +#import + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" + +#if TARGET_OS_IOS +#import +#endif // TARGET_OS_IOS + +@implementation GULAppEnvironmentUtil + +/// A key for the Info.plist to enable or disable checking if the App Store is running in a sandbox. +/// This will affect your data integrity when using Firebase Analytics, as it will disable some +/// necessary checks. +static NSString *const kFIRAppStoreReceiptURLCheckEnabledKey = + @"FirebaseAppStoreReceiptURLCheckEnabled"; + +/// The file name of the sandbox receipt. This is available on iOS >= 8.0 +static NSString *const kFIRAIdentitySandboxReceiptFileName = @"sandboxReceipt"; + +static BOOL HasSCInfoFolder(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + NSString *bundlePath = [NSBundle mainBundle].bundlePath; + NSString *scInfoPath = [bundlePath stringByAppendingPathComponent:@"SC_Info"]; + return [[NSFileManager defaultManager] fileExistsAtPath:scInfoPath]; +#elif TARGET_OS_OSX + return NO; +#endif +} + +static BOOL HasEmbeddedMobileProvision(void) { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + return [[NSBundle mainBundle] pathForResource:@"embedded" ofType:@"mobileprovision"].length > 0; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (BOOL)isFromAppStore { + static dispatch_once_t isEncryptedOnce; + static BOOL isEncrypted = NO; + + dispatch_once(&isEncryptedOnce, ^{ + isEncrypted = IsAppEncrypted(); + }); + + if ([GULAppEnvironmentUtil isSimulator]) { + return NO; + } + + // If an app contain the sandboxReceipt file, it means its coming from TestFlight + // This must be checked before the SCInfo Folder check below since TestFlight apps may + // also have an SCInfo folder. + if ([GULAppEnvironmentUtil isAppStoreReceiptSandbox]) { + return NO; + } + + if (HasSCInfoFolder()) { + // When iTunes downloads a .ipa, it also gets a customized .sinf file which is added to the + // main SC_Info directory. + return YES; + } + + // For iOS >= 8.0, iTunesMetadata.plist is moved outside of the sandbox. Any attempt to read + // the iTunesMetadata.plist outside of the sandbox will be rejected by Apple. + // If the app does not contain the embedded.mobileprovision which is stripped out by Apple when + // the app is submitted to store, then it is highly likely that it is from Apple Store. + return isEncrypted && !HasEmbeddedMobileProvision(); +} + ++ (BOOL)isAppStoreReceiptSandbox { + // Since checking the App Store's receipt URL can be memory intensive, check the option in the + // Info.plist if developers opted out of this check. + id enableSandboxCheck = + [[NSBundle mainBundle] objectForInfoDictionaryKey:kFIRAppStoreReceiptURLCheckEnabledKey]; + if (enableSandboxCheck && [enableSandboxCheck isKindOfClass:[NSNumber class]] && + ![enableSandboxCheck boolValue]) { + return NO; + } + + NSURL *appStoreReceiptURL = [NSBundle mainBundle].appStoreReceiptURL; + NSString *appStoreReceiptFileName = appStoreReceiptURL.lastPathComponent; + return [appStoreReceiptFileName isEqualToString:kFIRAIdentitySandboxReceiptFileName]; +} + ++ (BOOL)isSimulator { +#if TARGET_OS_SIMULATOR + return YES; +#elif TARGET_OS_MACCATALYST + return NO; +#elif TARGET_OS_IOS || TARGET_OS_TV + NSString *platform = [GULAppEnvironmentUtil deviceModel]; + return [platform isEqual:@"x86_64"] || [platform isEqual:@"i386"]; +#elif TARGET_OS_OSX + return NO; +#endif + return NO; +} + ++ (NSString *)getSysctlEntry:(const char *)sysctlKey { + static NSString *entryValue; + size_t size; + sysctlbyname(sysctlKey, NULL, &size, NULL, 0); + if (size > 0) { + char *entryValueCStr = malloc(size); + sysctlbyname(sysctlKey, entryValueCStr, &size, NULL, 0); + entryValue = [NSString stringWithCString:entryValueCStr encoding:NSUTF8StringEncoding]; + free(entryValueCStr); + return entryValue; + } else { + return nil; + } +} + ++ (NSString *)deviceModel { + static dispatch_once_t once; + static NSString *deviceModel; + +#if TARGET_OS_OSX || TARGET_OS_MACCATALYST + dispatch_once(&once, ^{ + // The `uname` function only returns x86_64 for Macs. Use `sysctlbyname` instead, but fall back + // to the `uname` function if it fails. + deviceModel = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; + if (deviceModel.length == 0) { + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + } + }); +#else + dispatch_once(&once, ^{ + struct utsname systemInfo; + if (uname(&systemInfo) == 0) { + deviceModel = [NSString stringWithUTF8String:systemInfo.machine]; + } + }); +#endif // TARGET_OS_OSX || TARGET_OS_MACCATALYST + return deviceModel; +} + ++ (NSString *)deviceSimulatorModel { + static dispatch_once_t once; + static NSString *model = nil; + + dispatch_once(&once, ^{ +#if TARGET_OS_SIMULATOR +#if TARGET_OS_WATCH + model = @"watchOS Simulator"; +#elif TARGET_OS_TV + model = @"tvOS Simulator"; +#elif TARGET_OS_VISION + model = @"visionOS Simulator"; +#elif TARGET_OS_IOS + switch ([[UIDevice currentDevice] userInterfaceIdiom]) { + case UIUserInterfaceIdiomPhone: + model = @"iOS Simulator (iPhone)"; + break; + case UIUserInterfaceIdiomPad: + model = @"iOS Simulator (iPad)"; + break; + default: + model = @"iOS Simulator (Unknown)"; + break; + } +#endif +#elif TARGET_OS_EMBEDDED + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.machine"]; +#else + model = [GULAppEnvironmentUtil getSysctlEntry:"hw.model"]; +#endif + }); + + return model; +} + ++ (NSString *)systemVersion { +#if TARGET_OS_IOS + return [UIDevice currentDevice].systemVersion; +#elif TARGET_OS_OSX || TARGET_OS_TV || TARGET_OS_WATCH || TARGET_OS_VISION + // Assemble the systemVersion, excluding the patch version if it's 0. + NSOperatingSystemVersion osVersion = [NSProcessInfo processInfo].operatingSystemVersion; + NSMutableString *versionString = [[NSMutableString alloc] + initWithFormat:@"%ld.%ld", (long)osVersion.majorVersion, (long)osVersion.minorVersion]; + if (osVersion.patchVersion != 0) { + [versionString appendFormat:@".%ld", (long)osVersion.patchVersion]; + } + return versionString; +#endif +} + ++ (BOOL)isAppExtension { +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH + // Documented by Apple + BOOL appExtension = [[[NSBundle mainBundle] bundlePath] hasSuffix:@".appex"]; + return appExtension; +#elif TARGET_OS_OSX + return NO; +#endif +} + ++ (NSString *)applePlatform { + NSString *applePlatform = @"unknown"; + + // When a Catalyst app is run on macOS then both `TARGET_OS_MACCATALYST` and `TARGET_OS_IOS` are + // `true`, which means the condition list is order-sensitive. +#if TARGET_OS_MACCATALYST + applePlatform = @"maccatalyst"; +#elif TARGET_OS_IOS + if (@available(iOS 14.0, *)) { + // Early iOS 14 betas do not include isiOSAppOnMac (#6969) + applePlatform = ([[NSProcessInfo processInfo] respondsToSelector:@selector(isiOSAppOnMac)] && + [NSProcessInfo processInfo].isiOSAppOnMac) + ? @"ios_on_mac" + : @"ios"; + } else { + applePlatform = @"ios"; + } +#elif TARGET_OS_TV + applePlatform = @"tvos"; +#elif TARGET_OS_OSX + applePlatform = @"macos"; +#elif TARGET_OS_WATCH + applePlatform = @"watchos"; +#elif TARGET_OS_VISION + applePlatform = @"visionos"; +#endif // TARGET_OS_MACCATALYST + + return applePlatform; +} + ++ (NSString *)appleDevicePlatform { + NSString *firebasePlatform = [GULAppEnvironmentUtil applePlatform]; +#if TARGET_OS_IOS + // This check is necessary because iOS-only apps running on iPad + // will report UIUserInterfaceIdiomPhone via UI_USER_INTERFACE_IDIOM(). + if ([firebasePlatform isEqualToString:@"ios"] && + ([[UIDevice currentDevice].model.lowercaseString containsString:@"ipad"] || + [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad)) { + return @"ipados"; + } +#endif + + return firebasePlatform; +} + ++ (NSString *)deploymentType { +#if SWIFT_PACKAGE + NSString *deploymentType = @"swiftpm"; +#elif FIREBASE_BUILD_CARTHAGE + NSString *deploymentType = @"carthage"; +#elif FIREBASE_BUILD_ZIP_FILE + NSString *deploymentType = @"zip"; +#elif COCOAPODS + NSString *deploymentType = @"cocoapods"; +#else + NSString *deploymentType = @"unknown"; +#endif + + return deploymentType; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m new file mode 100644 index 0000000..fa3b878 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/NetworkInfo/GULNetworkInfo.m @@ -0,0 +1,80 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h" + +#import + +#import +#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \ + !TARGET_OS_OSX && !TARGET_OS_TV && !TARGET_OS_WATCH +#define TARGET_HAS_MOBILE_CONNECTIVITY +#import +#import +#endif + +@implementation GULNetworkInfo + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY ++ (CTTelephonyNetworkInfo *)getNetworkInfo { + static CTTelephonyNetworkInfo *networkInfo; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + networkInfo = [[CTTelephonyNetworkInfo alloc] init]; + }); + return networkInfo; +} +#endif + ++ (GULNetworkType)getNetworkType { + GULNetworkType networkType = GULNetworkTypeNone; + +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + static SCNetworkReachabilityRef reachabilityRef = 0; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com"); + }); + + if (!reachabilityRef) { + return GULNetworkTypeNone; + } + + SCNetworkReachabilityFlags reachabilityFlags = 0; + SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags); + + // Parse the network flags to set the network type. + if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) { + if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) { + networkType = GULNetworkTypeMobile; + } else { + networkType = GULNetworkTypeWIFI; + } + } +#endif + + return networkType; +} + ++ (NSString *)getNetworkRadioType { +#ifdef TARGET_HAS_MOBILE_CONNECTIVITY + CTTelephonyNetworkInfo *networkInfo = [GULNetworkInfo getNetworkInfo]; + if (networkInfo.serviceCurrentRadioAccessTechnology.count) { + return networkInfo.serviceCurrentRadioAccessTechnology.allValues[0] ?: @""; + } +#endif + return @""; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h new file mode 100644 index 0000000..dbce363 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface GULAppEnvironmentUtil : NSObject + +/// Indicates whether the app is from Apple Store or not. Returns NO if the app is on simulator, +/// development environment or sideloaded. ++ (BOOL)isFromAppStore; + +/// Indicates whether the app is a Testflight app. Returns YES if the app has sandbox receipt. +/// Returns NO otherwise. ++ (BOOL)isAppStoreReceiptSandbox; + +/// Indicates whether the app is on simulator or not at runtime depending on the device +/// architecture. ++ (BOOL)isSimulator; + +/// The current device model. Returns an empty string if device model cannot be retrieved. ++ (nullable NSString *)deviceModel; + +/// The current device model, with simulator-specific values. Returns an empty string if device +/// model cannot be retrieved. ++ (nullable NSString *)deviceSimulatorModel; + +/// The current operating system version. Returns an empty string if the system version cannot be +/// retrieved. ++ (NSString *)systemVersion; + +/// Indicates whether it is running inside an extension or an app. ++ (BOOL)isAppExtension; + +/// @return An Apple platform. Possible values "ios", "tvos", "macos", "watchos", "maccatalyst", and +/// "visionos". ++ (NSString *)applePlatform; + +/// @return An Apple Device platform. Same possible values as `applePlatform`, with the addition of +/// "ipados". ++ (NSString *)appleDevicePlatform; + +/// @return The way the library was added to the app, e.g. "swiftpm", "cocoapods", etc. ++ (NSString *)deploymentType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h new file mode 100644 index 0000000..eb90ea3 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h @@ -0,0 +1,84 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The class provides a convenient, multiplatform abstraction of the Keychain. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainStorage : NSObject + +- (instancetype)init NS_UNAVAILABLE; + +/** Initializes the keychain storage with Keychain Service name. + * @param service A Keychain Service name that will be used to store and retrieve objects. See also + * `kSecAttrService`. + */ +- (instancetype)initWithService:(NSString *)service; + +/// Get an object by key. +/// @param key The key. +/// @param objectClass The expected object class required by `NSSecureCoding`. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain read is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object stored in +/// the keychain, or `nil` if it does not exist, is passed to the completion +/// handler. +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; + +/// Saves the given object by the given key. +/// @param object The object to store. +/// @param key The key to store the object. If there is an existing object by the key, it will be +/// overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain write is complete. An error is passed to the +/// completion handler if the keychain read fails. Else, the object written to +/// the keychain is passed to the completion handler. +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler; + +/// Removes the object by the given key. +/// @param key The key to store the object. If there is an existing object by +/// the key, it will be overridden. +/// @param accessGroup The Keychain Access Group. +/// @param completionHandler The completion handler to call when the +/// synchronized keychain removal is complete. An error is passed to the +/// completion handler if the keychain removal fails. +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler; + +#if TARGET_OS_OSX +/// If not `nil`, then only this keychain will be used to save and read data (see +/// `kSecMatchSearchList` and `kSecUseKeychain`. It is mostly intended to be used by unit tests. +@property(nonatomic, nullable) SecKeychainRef keychainRef; +#endif // TARGET_OS_OSX + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h new file mode 100644 index 0000000..9c17356 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h @@ -0,0 +1,64 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXPORT NSString *const kGULKeychainUtilsErrorDomain; + +/// A collection of helper functions that abstract away common Keychain operations. +/// +/// When using this API on macOS, the corresponding target must be signed with a provisioning +/// profile that has the Keychain Sharing capability enabled. +@interface GULKeychainUtils : NSObject + +/** Fetches a keychain item data matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemCopyMatching` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns Data for the first Keychain Item matching the provided query or `nil` if there is not + * such an item (`outError` will be `nil` in this case) or an error occurred. + */ ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Stores data to a Keychain Item matching to the provided query. An existing Keychain Item + * matching the query parameters will be updated or a new will be created. + * @param item A Keychain Item data to store. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemAdd` and + * `SecItemUpdate` for details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` when data was successfully stored, `NO` otherwise. + */ ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError; + +/** Removes a Keychain Item matching to the provided query. + * @param query A dictionary with Keychain query parameters. See docs for `SecItemDelete` for + * details. + * @param outError A pointer to `NSError` instance or `NULL`. The instance at `outError` will be + * assigned with an error if there is. + * @returns `YES` if the item was removed successfully or doesn't exist, `NO` otherwise. + */ ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h new file mode 100644 index 0000000..0613941 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/Public/GoogleUtilities/GULNetworkInfo.h @@ -0,0 +1,43 @@ +// Copyright 2022 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The type of network that the device is running with. Values should correspond to the NetworkType +/// values in android/play/playlog/proto/clientanalytics.proto +typedef NS_ENUM(NSInteger, GULNetworkType) { + GULNetworkTypeNone = -1, + GULNetworkTypeMobile = 0, + GULNetworkTypeWIFI = 1, +}; + +/// Collection of utilities to read network status information +@interface GULNetworkInfo : NSObject + +/// Returns an enum indicating the network type. The enum values should be easily transferrable to +/// the NetworkType value in android/play/playlog/proto/clientanalytics.proto. Right now this always +/// returns None on platforms other than iOS. This should be updated in the future to return Wi-Fi +/// values for the other platforms when applicable. ++ (GULNetworkType)getNetworkType; + +/// Returns a string indicating the radio access technology used by the app. The return value will +/// be one of CTRadioAccess constants defined in +/// https://developer.apple.com/documentation/coretelephony/cttelephonynetworkinfo/radio_access_technology_constants ++ (NSString *)getNetworkRadioType; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m new file mode 100644 index 0000000..e6aa69a --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainStorage.m @@ -0,0 +1,196 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainStorage.h" +#import + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +@interface GULKeychainStorage () +@property(nonatomic, readonly) dispatch_queue_t keychainQueue; +@property(nonatomic, readonly) dispatch_queue_t inMemoryCacheQueue; +@property(nonatomic, readonly) NSString *service; +@property(nonatomic, readonly) NSCache> *inMemoryCache; +@end + +@implementation GULKeychainStorage + +- (instancetype)initWithService:(NSString *)service { + NSCache *cache = [[NSCache alloc] init]; + // Cache up to 5 installations. + cache.countLimit = 5; + return [self initWithService:service cache:cache]; +} + +- (instancetype)initWithService:(NSString *)service cache:(NSCache *)cache { + self = [super init]; + if (self) { + _keychainQueue = + dispatch_queue_create("com.gul.KeychainStorage.Keychain", DISPATCH_QUEUE_SERIAL); + _inMemoryCacheQueue = + dispatch_queue_create("com.gul.KeychainStorage.InMemoryCache", DISPATCH_QUEUE_SERIAL); + _service = [service copy]; + _inMemoryCache = cache; + } + return self; +} + +#pragma mark - Public + +- (void)getObjectForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Return cached object or fail otherwise. + id object = [self.inMemoryCache objectForKey:key]; + if (object) { + completionHandler(object, nil); + } else { + // Look for the object in the keychain. + [self getObjectFromKeychainForKey:key + objectClass:objectClass + accessGroup:accessGroup + completionHandler:completionHandler]; + } + }); +} + +- (void)setObject:(id)object + forKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler: + (void (^)(id _Nullable obj, NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save to the in-memory cache first. + [self.inMemoryCache setObject:object forKey:[key copy]]; + + dispatch_async(self.keychainQueue, ^{ + // Then store the object to the keychain. + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object + requiringSecureCoding:YES + error:&error]; + if (!encodedObject) { + completionHandler(nil, error); + return; + } + + if (![GULKeychainUtils setItem:encodedObject withQuery:query error:&error]) { + completionHandler(nil, error); + return; + } + + completionHandler(object, nil); + }); + }); +} + +- (void)removeObjectForKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(NSError *_Nullable error))completionHandler { + dispatch_async(self.inMemoryCacheQueue, ^{ + [self.inMemoryCache removeObjectForKey:key]; + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + + NSError *error; + if (![GULKeychainUtils removeItemWithQuery:query error:&error]) { + completionHandler(error); + } else { + completionHandler(nil); + } + }); + }); +} + +#pragma mark - Private + +- (void)getObjectFromKeychainForKey:(NSString *)key + objectClass:(Class)objectClass + accessGroup:(nullable NSString *)accessGroup + completionHandler:(void (^)(id _Nullable obj, + NSError *_Nullable error))completionHandler { + // Look for the object in the keychain. + dispatch_async(self.keychainQueue, ^{ + NSDictionary *query = [self keychainQueryWithKey:key accessGroup:accessGroup]; + NSError *error; + NSData *encodedObject = [GULKeychainUtils getItemWithQuery:query error:&error]; + + if (error) { + completionHandler(nil, error); + return; + } + if (!encodedObject) { + completionHandler(nil, nil); + return; + } + id object = [NSKeyedUnarchiver unarchivedObjectOfClass:objectClass + fromData:encodedObject + error:&error]; + if (error) { + completionHandler(nil, error); + return; + } + + dispatch_async(self.inMemoryCacheQueue, ^{ + // Save object to the in-memory cache if exists and return the object. + if (object) { + [self.inMemoryCache setObject:object forKey:[key copy]]; + } + + completionHandler(object, nil); + }); + }); +} + +- (void)resetInMemoryCache { + [self.inMemoryCache removeAllObjects]; +} + +#pragma mark - Keychain + +- (NSMutableDictionary *)keychainQueryWithKey:(NSString *)key + accessGroup:(nullable NSString *)accessGroup { + NSMutableDictionary *query = [NSMutableDictionary dictionary]; + + query[(__bridge NSString *)kSecClass] = (__bridge NSString *)kSecClassGenericPassword; + query[(__bridge NSString *)kSecAttrService] = self.service; + query[(__bridge NSString *)kSecAttrAccount] = key; + + if (accessGroup) { + query[(__bridge NSString *)kSecAttrAccessGroup] = accessGroup; + } + + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + // Ensures that the keychain query behaves the same across all platforms. + // See go/firebase-macos-keychain-popups for details. + query[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + +#if TARGET_OS_OSX + if (self.keychainRef) { + query[(__bridge NSString *)kSecUseKeychain] = (__bridge id)(self.keychainRef); + query[(__bridge NSString *)kSecMatchSearchList] = @[ (__bridge id)(self.keychainRef) ]; + } +#endif // TARGET_OS_OSX + + return query; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m new file mode 100644 index 0000000..57855a0 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Environment/SecureStorage/GULKeychainUtils.m @@ -0,0 +1,133 @@ +/* + * Copyright 2019 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULKeychainUtils.h" + +NSString *const kGULKeychainUtilsErrorDomain = @"com.gul.keychain.ErrorDomain"; + +@implementation GULKeychainUtils + ++ (nullable NSData *)getItemWithQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSMutableDictionary *mutableGetItemQuery = + [[[self class] multiplatformQueryWithQuery:query] mutableCopy]; + + mutableGetItemQuery[(__bridge id)kSecReturnData] = @YES; + mutableGetItemQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne; + + CFDataRef result = NULL; + OSStatus status = + SecItemCopyMatching((__bridge CFDictionaryRef)mutableGetItemQuery, (CFTypeRef *)&result); + + if (status == errSecSuccess && result != NULL) { + if (outError) { + *outError = nil; + } + + return (__bridge_transfer NSData *)result; + } + + if (status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + } else { + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemCopyMatching" status:status]; + } + } + return nil; +} + ++ (BOOL)setItem:(NSData *)item + withQuery:(NSDictionary *)query + error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *multiplatformQuery = [[self class] multiplatformQueryWithQuery:query]; + + NSData *existingItem = [self getItemWithQuery:multiplatformQuery error:outError]; + if (outError && *outError) { + return NO; + } + + OSStatus status; + if (!existingItem) { + NSMutableDictionary *mutableAddItemQuery = [multiplatformQuery mutableCopy]; + mutableAddItemQuery[(__bridge id)kSecAttrAccessible] = + (__bridge id)kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly; + mutableAddItemQuery[(__bridge id)kSecValueData] = item; + + status = SecItemAdd((__bridge CFDictionaryRef)mutableAddItemQuery, NULL); + } else { + NSDictionary *attributes = @{(__bridge id)kSecValueData : item}; + status = SecItemUpdate((__bridge CFDictionaryRef)multiplatformQuery, + (__bridge CFDictionaryRef)attributes); + } + + if (status == noErr) { + if (outError) { + *outError = nil; + } + return YES; + } + + NSString *function = existingItem ? @"SecItemUpdate" : @"SecItemAdd"; + if (outError) { + *outError = [self keychainErrorWithFunction:function status:status]; + } + return NO; +} + ++ (BOOL)removeItemWithQuery:(NSDictionary *)query error:(NSError *_Nullable *_Nullable)outError { + NSDictionary *deleteItemQuery = [[self class] multiplatformQueryWithQuery:query]; + + OSStatus status = SecItemDelete((__bridge CFDictionaryRef)deleteItemQuery); + + if (status == noErr || status == errSecItemNotFound) { + if (outError) { + *outError = nil; + } + return YES; + } + + if (outError) { + *outError = [self keychainErrorWithFunction:@"SecItemDelete" status:status]; + } + return NO; +} + +#pragma mark - Private + +/// Returns a `NSDictionary` query that behaves the same across all platforms. +/// - Note: In practice, this API only makes a difference to keychain queries on macOS. +/// See go/firebase-macos-keychain-popups for details. +/// - Parameter query: A query to create the protected keychain query with. ++ (NSDictionary *)multiplatformQueryWithQuery:(NSDictionary *)query { + NSMutableDictionary *multiplatformQuery = [query mutableCopy]; + if (@available(iOS 13.0, macOS 10.15, macCatalyst 13.0, tvOS 13.0, watchOS 6.0, *)) { + multiplatformQuery[(__bridge id)kSecUseDataProtectionKeychain] = (__bridge id)kCFBooleanTrue; + } + return [multiplatformQuery copy]; +} + +#pragma mark - Errors + ++ (NSError *)keychainErrorWithFunction:(NSString *)keychainFunction status:(OSStatus)status { + NSString *failureReason = [NSString stringWithFormat:@"%@ (%li)", keychainFunction, (long)status]; + NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey : failureReason}; + return [NSError errorWithDomain:kGULKeychainUtilsErrorDomain code:0 userInfo:userInfo]; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m b/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m new file mode 100644 index 0000000..a2eb29e --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/GULLogger.m @@ -0,0 +1,223 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +#import "GoogleUtilities/Environment/Public/GoogleUtilities/GULAppEnvironmentUtil.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h" + +static dispatch_once_t sGULLoggerOnceToken; + +static dispatch_queue_t sGULClientQueue; + +static BOOL sGULLoggerDebugMode; + +static GULLoggerLevel sGULLoggerMaximumLevel; + +// Allow clients to register a version to include in the log. +static NSString *sVersion = @""; + +NSString *const kGULLogSubsystem = @"com.google.utilities.logger"; + +static GULLoggerService kGULLoggerLogger = @"[GULLogger]"; + +static NSMutableDictionary *> + *sGULServiceLogs; + +#ifdef DEBUG +/// The regex pattern for the message code. +static NSString *const kMessageCodePattern = @"^I-[A-Z]{3}[0-9]{6}$"; +static NSRegularExpression *sMessageCodeRegex; +#endif + +void GULLoggerInitialize(void) { + dispatch_once(&sGULLoggerOnceToken, ^{ + sGULLoggerMaximumLevel = GULLoggerLevelNotice; + sGULClientQueue = dispatch_queue_create("GULLoggingClientQueue", DISPATCH_QUEUE_SERIAL); + dispatch_set_target_queue(sGULClientQueue, + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)); + sGULServiceLogs = [NSMutableDictionary dictionary]; +#ifdef DEBUG + sMessageCodeRegex = [NSRegularExpression regularExpressionWithPattern:kMessageCodePattern + options:0 + error:NULL]; +#endif + }); +} + +void GULLoggerForceDebug(void) { + // We should enable debug mode if we're not running from App Store. + if (![GULAppEnvironmentUtil isFromAppStore]) { + sGULLoggerDebugMode = YES; + GULSetLoggerLevel(GULLoggerLevelDebug); + } +} + +GULLoggerLevel GULGetLoggerLevel(void) { + return sGULLoggerMaximumLevel; +} + +__attribute__((no_sanitize("thread"))) void GULSetLoggerLevel(GULLoggerLevel loggerLevel) { + if (loggerLevel < GULLoggerLevelMin || loggerLevel > GULLoggerLevelMax) { + GULOSLogError(kGULLogSubsystem, kGULLoggerLogger, YES, @"I-COR000023", + @"Invalid logger level, %ld", (long)loggerLevel); + return; + } + GULLoggerInitialize(); + // We should not raise the logger level if we are running from App Store. + if (loggerLevel >= GULLoggerLevelNotice && [GULAppEnvironmentUtil isFromAppStore]) { + return; + } + + sGULLoggerMaximumLevel = loggerLevel; +} + +/** + * Check if the level is high enough to be loggable. + */ +__attribute__((no_sanitize("thread"))) BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel) { + GULLoggerInitialize(); + if (sGULLoggerDebugMode) { + return YES; + } + return (BOOL)(loggerLevel <= sGULLoggerMaximumLevel); +} + +#ifdef DEBUG +void GULResetLogger(void) { + sGULLoggerOnceToken = 0; + sGULLoggerDebugMode = NO; + sGULLoggerMaximumLevel = GULLoggerLevelNotice; +} + +dispatch_queue_t getGULClientQueue(void) { + return sGULClientQueue; +} + +BOOL getGULLoggerDebugMode(void) { + return sGULLoggerDebugMode; +} +#endif + +void GULLoggerRegisterVersion(NSString *version) { + sVersion = version; +} + +os_log_type_t GULLoggerLevelToOSLogType(GULLoggerLevel level) { + switch (level) { + case GULLoggerLevelError: + return OS_LOG_TYPE_ERROR; + case GULLoggerLevelWarning: + case GULLoggerLevelNotice: + return OS_LOG_TYPE_DEFAULT; + case GULLoggerLevelInfo: + return OS_LOG_TYPE_INFO; + case GULLoggerLevelDebug: + return OS_LOG_TYPE_DEBUG; + } +} + +void GULOSLogBasic(GULLoggerLevel level, + NSString *subsystem, + NSString *category, + BOOL forceLog, + NSString *messageCode, + NSString *message, + va_list args_ptr) { + GULLoggerInitialize(); + if (!(level <= sGULLoggerMaximumLevel || sGULLoggerDebugMode || forceLog)) { + return; + } + +#ifdef DEBUG + NSCAssert(messageCode.length == 11, @"Incorrect message code length."); + NSRange messageCodeRange = NSMakeRange(0, messageCode.length); + NSUInteger __unused numberOfMatches = + [sMessageCodeRegex numberOfMatchesInString:messageCode options:0 range:messageCodeRange]; + NSCAssert(numberOfMatches == 1, @"Incorrect message code format."); +#endif + NSString *logMsg; + if (args_ptr == NULL) { + logMsg = message; + } else { + logMsg = [[NSString alloc] initWithFormat:message arguments:args_ptr]; + } + logMsg = [NSString stringWithFormat:@"%@ - %@[%@] %@", sVersion, category, messageCode, logMsg]; + dispatch_async(sGULClientQueue, ^{ + NSMutableDictionary *subsystemLogs = sGULServiceLogs[subsystem]; + if (!subsystemLogs) { + subsystemLogs = [NSMutableDictionary dictionary]; + sGULServiceLogs[subsystem] = subsystemLogs; + } + + os_log_t serviceLog = [subsystemLogs objectForKey:subsystem]; + if (!serviceLog) { + serviceLog = os_log_create(subsystem.UTF8String, category.UTF8String); + subsystemLogs[category] = serviceLog; + } + + os_log_with_type(serviceLog, GULLoggerLevelToOSLogType(level), "%{public}@", logMsg); + }); +} + +/** + * Generates the logging functions using macros. + * + * Calling GULLogError({service}, @"I-XYZ000001", @"Configure %@ failed.", @"blah") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure blah failed. + * Calling GULLogDebug({service}, @"I-XYZ000001", @"Configure succeed.") shows: + * yyyy-mm-dd hh:mm:ss.SSS sender[PID] [{service}][I-XYZ000001] Configure succeed. + */ +#define GUL_LOGGING_FUNCTION(level) \ + void GULOSLog##level(NSString *subsystem, NSString *category, BOOL force, NSString *messageCode, \ + NSString *message, ...) { \ + va_list args_ptr; \ + va_start(args_ptr, message); \ + GULOSLogBasic(GULLoggerLevel##level, subsystem, category, force, messageCode, message, \ + args_ptr); \ + va_end(args_ptr); \ + } + +GUL_LOGGING_FUNCTION(Error) +GUL_LOGGING_FUNCTION(Warning) +GUL_LOGGING_FUNCTION(Notice) +GUL_LOGGING_FUNCTION(Info) +GUL_LOGGING_FUNCTION(Debug) + +#undef GUL_LOGGING_FUNCTION + +#pragma mark - GULLoggerWrapper + +@implementation GULLoggerWrapper + ++ (void)logWithLevel:(GULLoggerLevel)level + subsystem:(NSString *)subsystem + category:(GULLoggerService)category + messageCode:(NSString *)messageCode + message:(NSString *)message + arguments:(va_list)args { + GULOSLogBasic(level, subsystem, category, NO, messageCode, message, args); +} + ++ (void)logWithLevel:(GULLoggerLevel)level + withService:(GULLoggerService)service + withCode:(NSString *)messageCode + withMessage:(NSString *)message + withArgs:(va_list)args { + GULOSLogBasic(level, kGULLogSubsystem, service, NO, messageCode, message, args); +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h new file mode 100644 index 0000000..30cc800 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h @@ -0,0 +1,165 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULLoggerLevel.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + * The services used in the logger. + * + * DEPRECATED; use NSString instead. + */ +typedef NSString *const GULLoggerService; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +/// Used for other GoogleUtilities logging. +extern NSString *const kGULLogSubsystem; + +/// Initialize GULLogger. +extern void GULLoggerInitialize(void); + +/// Override log level to Debug. +void GULLoggerForceDebug(void); + +/// Gets the current `GULLoggerLevel`. +extern GULLoggerLevel GULGetLoggerLevel(void); + +/** + * Changes the default logging level of GULLoggerLevelNotice to a user-specified level. + * The default level cannot be set above GULLoggerLevelNotice if the app is running from App Store. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern void GULSetLoggerLevel(GULLoggerLevel loggerLevel); + +/** + * Checks if the specified logger level is loggable given the current settings. + * (required) log level (one of the GULLoggerLevel enum values). + */ +extern BOOL GULIsLoggableLevel(GULLoggerLevel loggerLevel); + +/** + * Register version to include in logs. + * (required) version + */ +extern void GULLoggerRegisterVersion(NSString *version); + +/** + * Logs a message to the Xcode console and the device log. If running from AppStore, will + * not log any messages with a level higher than GULLoggerLevelNotice to avoid log spamming. + * (required) log level (one of the GULLoggerLevel enum values). + * (required) service name of type GULLoggerService. + * (required) message code starting with "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * (required) message string which can be a format string. + * (optional) variable arguments list obtained from calling va_start, used when message is a format + * string. + */ +extern void GULOSLogBasic(GULLoggerLevel level, + NSString *subsystem, + NSString *category, + BOOL forceLog, + NSString *messageCode, + NSString *message, +// On 64-bit simulators, va_list is not a pointer, so cannot be marked nullable +// See: http://stackoverflow.com/q/29095469 +#if __LP64__ && TARGET_OS_SIMULATOR || TARGET_OS_OSX + va_list args_ptr +#else + va_list _Nullable args_ptr +#endif +); + +/** + * The following functions accept the following parameters in order: + * (required) service name of type GULLoggerService. + * (required) message code starting from "I-" which means iOS, followed by a capitalized + * three-character service identifier and a six digit integer message ID that is unique + * within the service. + * An example of the message code is @"I-COR000001". + * See go/firebase-log-proposal for details. + * (required) message string which can be a format string. + * (optional) the list of arguments to substitute into the format string. + * Example usage: + * GULLogError(kGULLoggerCore, @"I-COR000001", @"Configuration of %@ failed.", app.name); + */ +extern void GULOSLogError(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogWarning(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogNotice(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogInfo(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); +extern void GULOSLogDebug(NSString *subsystem, + GULLoggerService category, + BOOL force, + NSString *messageCode, + NSString *message, + ...) NS_FORMAT_FUNCTION(5, 6); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus + +@interface GULLoggerWrapper : NSObject + +/// Objective-C wrapper for `GULOSLogBasic` to allow weak linking to `GULLogger`. +/// +/// - Parameters: +/// - level: The log level (one of the `GULLoggerLevel` enum values). +/// - subsystem: An identifier for the subsystem performing logging, e.g., `com.example.logger`. +/// - category: The category name within the `subsystem` to group related messages, e.g., +/// `[GoogleUtilities/Example]`. +/// - messageCode: The message code starting with "I-" which means iOS, followed by a capitalized +/// three-character service identifier and a six digit integer message ID that is unique within +/// the service. An example of the message code is @"I-COR000001". +/// - message: The message to log, which may be a format string. +/// - arguments: The variable arguments list obtained from calling va_start, used when message is +/// a format string; optional if `message` is not a format string. ++ (void)logWithLevel:(GULLoggerLevel)level + subsystem:(NSString *)subsystem + category:(NSString *)category + messageCode:(NSString *)messageCode + message:(NSString *)message + arguments:(va_list)args; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h new file mode 100644 index 0000000..6a68eb1 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Logger/Public/GoogleUtilities/GULLoggerLevel.h @@ -0,0 +1,47 @@ +/* + * Copyright 2018 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// The log levels used by internal logging. +typedef NS_ENUM(NSInteger, GULLoggerLevel) { + /// Error level, corresponding to `OS_LOG_TYPE_ERROR`. + GULLoggerLevelError = 3, // For backwards compatibility, the enum value matches `ASL_LEVEL_ERR`. + + /// Warning level, corresponding to `OS_LOG_TYPE_DEFAULT`. + /// + /// > Note: Since OSLog doesn't have a WARNING type, this is equivalent to `GULLoggerLevelNotice`. + GULLoggerLevelWarning = 4, // For backwards compatibility, the value matches `ASL_LEVEL_WARNING`. + + /// Notice level, corresponding to `OS_LOG_TYPE_DEFAULT`. + GULLoggerLevelNotice = 5, // For backwards compatibility, the value matches `ASL_LEVEL_NOTICE`. + + /// Info level, corresponding to `OS_LOG_TYPE_INFO`. + GULLoggerLevelInfo = 6, // For backwards compatibility, the enum value matches `ASL_LEVEL_INFO`. + + /// Debug level, corresponding to `OS_LOG_TYPE_DEBUG`. + GULLoggerLevelDebug = 7, // For backwards compatibility, the value matches `ASL_LEVEL_DEBUG`. + + /// The minimum (most severe) supported logging level. + GULLoggerLevelMin = GULLoggerLevelError, + + /// The maximum (least severe) supported logging level. + GULLoggerLevelMax = GULLoggerLevelDebug +} NS_SWIFT_NAME(GoogleLoggerLevel); + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m new file mode 100644 index 0000000..3b40b41 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/GULSwizzler.m @@ -0,0 +1,154 @@ +// Copyright 2018 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h" + +#import + +#ifdef DEBUG +#import "GoogleUtilities/Common/GULLoggerCodes.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerSwizzler = @"[GoogleUtilities/MethodSwizzler]"; +#endif + +dispatch_queue_t GetGULSwizzlingQueue(void) { + static dispatch_queue_t queue; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.GULSwizzler", DISPATCH_QUEUE_SERIAL); + }); + return queue; +} + +@implementation GULSwizzler + ++ (void)swizzleClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector + withBlock:(nullable id)block { + dispatch_sync(GetGULSwizzlingQueue(), ^{ + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + Class resolvedClass = aClass; + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + resolvedClass = object_getClass(aClass); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"You're attempting to swizzle a method that doesn't exist. (%@, %@)", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + IMP newImp = imp_implementationWithBlock(block); +#ifdef DEBUG + IMP currentImp = class_getMethodImplementation(resolvedClass, selector); + Class class = NSClassFromString(@"GULSwizzlingCache"); + if (class) { + SEL cacheSelector = NSSelectorFromString(@"cacheCurrentIMP:forNewIMP:forClass:withSelector:"); + NSMethodSignature *methodSignature = [class methodSignatureForSelector:cacheSelector]; + if (methodSignature != nil) { + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; + [inv setSelector:cacheSelector]; + [inv setTarget:class]; + [inv setArgument:&(currentImp) atIndex:2]; + [inv setArgument:&(newImp) atIndex:3]; + [inv setArgument:&(resolvedClass) atIndex:4]; + [inv setArgument:(void *_Nonnull)&(selector) atIndex:5]; + [inv invoke]; + } + } +#endif + + const char *typeEncoding = method_getTypeEncoding(method); + __unused IMP originalImpOfClass = + class_replaceMethod(resolvedClass, selector, newImp, typeEncoding); + +#ifdef DEBUG + // If !originalImpOfClass, then the IMP came from a superclass. + if (originalImpOfClass) { + SEL selector = NSSelectorFromString(@"originalIMPOfCurrentIMP:"); + NSMethodSignature *methodSignature = [class methodSignatureForSelector:selector]; + if (methodSignature != nil) { + NSInvocation *inv = [NSInvocation invocationWithMethodSignature:methodSignature]; + [inv setSelector:selector]; + [inv setTarget:class]; + [inv setArgument:&(currentImp) atIndex:2]; + [inv invoke]; + IMP testOriginal; + [inv getReturnValue:&testOriginal]; + if (originalImpOfClass != testOriginal) { + GULOSLogWarning( + kGULLogSubsystem, kGULLoggerSwizzler, NO, + [NSString + stringWithFormat:@"I-SWZ%06ld", (long)kGULSwizzlerMessageCodeMethodSwizzling000], + @"Swizzling class: %@ SEL:%@ after it has been previously been swizzled.", + NSStringFromClass(resolvedClass), NSStringFromSelector(selector)); + } + } + } +#endif + }); +} + ++ (nullable IMP)currentImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector { + NSAssert(selector, @"The selector cannot be NULL"); + NSAssert(aClass, @"The class cannot be Nil"); + if (selector == NULL || aClass == nil) { + return nil; + } + __block IMP currentIMP = nil; + dispatch_sync(GetGULSwizzlingQueue(), ^{ + Method method = nil; + if (isClassSelector) { + method = class_getClassMethod(aClass, selector); + } else { + method = class_getInstanceMethod(aClass, selector); + } + NSAssert(method, @"The Method for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + if (method == nil) { + return; + } + currentIMP = method_getImplementation(method); + NSAssert(currentIMP, @"The IMP for this class/selector combo doesn't exist (%@, %@).", + NSStringFromClass(aClass), NSStringFromSelector(selector)); + }); + return currentIMP; +} + ++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector { + Method method = isClassSelector ? class_getClassMethod(aClass, selector) + : class_getInstanceMethod(aClass, selector); + return method != nil; +} + ++ (NSArray *)ivarObjectsForObject:(id)object { + NSMutableArray *array = [NSMutableArray array]; + unsigned int count; + Ivar *vars = class_copyIvarList([object class], &count); + for (NSUInteger i = 0; i < count; i++) { + const char *typeEncoding = ivar_getTypeEncoding(vars[i]); + // Check to see if the ivar is an object. + if (strncmp(typeEncoding, "@", 1) == 0) { + id ivarObject = object_getIvar(object, vars[i]); + [array addObject:ivarObject]; + } + } + free(vars); + return array; +} +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h new file mode 100644 index 0000000..c340f85 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULOriginalIMPConvenienceMacros.h @@ -0,0 +1,213 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** + * GULOriginalIMPConvenienceMacros.h + * + * This header contains convenience macros for invoking the original IMP of a swizzled method. + */ + +/** + * Invokes original IMP when the original selector takes no arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + */ +#define GUL_INVOKE_ORIGINAL_IMP0(__receivingObject, __swizzledSEL, __returnType, __originalIMP) \ + ((__returnType(*)(id, SEL))__originalIMP)(__receivingObject, __swizzledSEL) + +/** + * Invokes original IMP when the original selector takes 1 argument. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP1(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1)))__originalIMP)(__receivingObject, __swizzledSEL, \ + __arg1) + +/** + * Invokes original IMP when the original selector takes 2 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP2(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2) + +/** + * Invokes original IMP when the original selector takes 3 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP3(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), \ + __typeof__(__arg3)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \ + __arg2, __arg3) + +/** + * Invokes original IMP when the original selector takes 4 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP4(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4)))__originalIMP)(__receivingObject, __swizzledSEL, __arg1, \ + __arg2, __arg3, __arg4) + +/** + * Invokes original IMP when the original selector takes 5 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP5(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5) + +/** + * Invokes original IMP when the original selector takes 6 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP6(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6) + +/** + * Invokes original IMP when the original selector takes 7 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP7(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7) + +/** + * Invokes original IMP when the original selector takes 8 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + * @param __arg8 The eighth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP8(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7), __typeof__(__arg8)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \ + __arg8) + +/** + * Invokes original IMP when the original selector takes 9 arguments. + * + * @param __receivingObject The object on which the IMP is invoked. + * @param __swizzledSEL The selector used for swizzling. + * @param __returnType The return type of the original implementation. + * @param __originalIMP The original IMP. + * @param __arg1 The first argument. + * @param __arg2 The second argument. + * @param __arg3 The third argument. + * @param __arg4 The fourth argument. + * @param __arg5 The fifth argument. + * @param __arg6 The sixth argument. + * @param __arg7 The seventh argument. + * @param __arg8 The eighth argument. + * @param __arg9 The ninth argument. + */ +#define GUL_INVOKE_ORIGINAL_IMP9(__receivingObject, __swizzledSEL, __returnType, __originalIMP, \ + __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, __arg8, \ + __arg9) \ + ((__returnType(*)(id, SEL, __typeof__(__arg1), __typeof__(__arg2), __typeof__(__arg3), \ + __typeof__(__arg4), __typeof__(__arg5), __typeof__(__arg6), \ + __typeof__(__arg7), __typeof__(__arg8), __typeof__(__arg9)))__originalIMP)( \ + __receivingObject, __swizzledSEL, __arg1, __arg2, __arg3, __arg4, __arg5, __arg6, __arg7, \ + __arg8, __arg9) + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h new file mode 100644 index 0000000..26949c8 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/MethodSwizzler/Public/GoogleUtilities/GULSwizzler.h @@ -0,0 +1,71 @@ +/* + * Copyright 2018 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/** This class handles the runtime manipulation necessary to instrument selectors. It stores the + * classes and selectors that have been swizzled, and runs all operations on its own queue. + */ +@interface GULSwizzler : NSObject + +/** Manipulates the Objective-C runtime to replace the original IMP with the supplied block. + * + * @param aClass The class to swizzle. + * @param selector The selector of the class to swizzle. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @param block The block that replaces the original IMP. + */ ++ (void)swizzleClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector + withBlock:(nullable id)block; + +/** Returns the current IMP for the given class and selector. + * + * @param aClass The class to use. + * @param selector The selector to find the implementation of. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @return The implementation of the selector in the runtime. + */ ++ (nullable IMP)currentImplementationForClass:(Class)aClass + selector:(SEL)selector + isClassSelector:(BOOL)isClassSelector; + +/** Checks the runtime to see if a selector exists on a class. If a property is declared as + * @dynamic, we have a reverse swizzling situation, where the implementation of a method exists + * only in concrete subclasses, and NOT in the superclass. We can detect that situation using + * this helper method. Similarly, we can detect situations where a class doesn't implement a + * protocol method. + * + * @param selector The selector to check for. + * @param aClass The class to check. + * @param isClassSelector A BOOL specifying whether the selector is a class or instance selector. + * @return YES if the method was found in this selector/class combination, NO otherwise. + */ ++ (BOOL)selector:(SEL)selector existsInClass:(Class)aClass isClassSelector:(BOOL)isClassSelector; + +/** Returns a list of all Objective-C (and not primitive) ivars contained by the given object. + * + * @param object The object whose ivars will be iterated. + * @return The list of ivar objects. + */ ++ (NSArray *)ivarObjectsForObject:(id)object; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m new file mode 100644 index 0000000..cec621e --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/GULNSData+zlib.m @@ -0,0 +1,207 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" + +#import + +#define kChunkSize 1024 +#define Z_DEFAULT_COMPRESSION (-1) + +NSString *const GULNSDataZlibErrorDomain = @"com.google.GULNSDataZlibErrorDomain"; +NSString *const GULNSDataZlibErrorKey = @"GULNSDataZlibErrorKey"; +NSString *const GULNSDataZlibRemainingBytesKey = @"GULNSDataZlibRemainingBytesKey"; + +@implementation NSData (GULGzip) + ++ (nullable NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + int windowBits = 15; // 15 to enable any window size + windowBits += 32; // and +32 to enable zlib or gzip header detection. + + int retCode; + if ((retCode = inflateInit2(&strm, windowBits)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 4x the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length * 4)]; + unsigned char output[kChunkSize]; + + // Loop to collect the data. + do { + // Update what we're passing in. + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = inflate(&strm, Z_NO_FLUSH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSMutableDictionary *userInfo = + [NSMutableDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + if (strm.msg) { + NSString *message = [NSString stringWithUTF8String:strm.msg]; + if (message) { + [userInfo setObject:message forKey:NSLocalizedDescriptionKey]; + } + } + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + inflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // Make sure there wasn't more data tacked onto the end of a valid compressed stream. + if (strm.avail_in != 0) { + if (error) { + NSDictionary *userInfo = + [NSDictionary dictionaryWithObject:[NSNumber numberWithUnsignedInt:strm.avail_in] + forKey:GULNSDataZlibRemainingBytesKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorDataRemaining + userInfo:userInfo]; + } + result = nil; + } + // The only way out of the loop was by hitting the end of the stream. + NSAssert(retCode == Z_STREAM_END, + @"Thought we finished inflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + inflateEnd(&strm); + + return result; +} + ++ (nullable NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error { + const void *bytes = [data bytes]; + NSUInteger length = [data length]; + + int level = Z_DEFAULT_COMPRESSION; + if (!bytes || !length) { + return nil; + } + +#if defined(__LP64__) && __LP64__ + // Don't support > 32bit length for 64 bit, see note in header. + if (length > UINT_MAX) { + if (error) { + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorGreaterThan32BitsToCompress + userInfo:nil]; + } + return nil; + } +#endif + + z_stream strm; + bzero(&strm, sizeof(z_stream)); + + int memLevel = 8; // Default. + int windowBits = 15 + 16; // Enable gzip header instead of zlib header. + + int retCode; + if ((retCode = deflateInit2(&strm, level, Z_DEFLATED, windowBits, memLevel, + Z_DEFAULT_STRATEGY)) != Z_OK) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + return nil; + } + + // Hint the size at 1/4 the input size. + NSMutableData *result = [NSMutableData dataWithCapacity:(length / 4)]; + unsigned char output[kChunkSize]; + + // Setup the input. + strm.avail_in = (unsigned int)length; + strm.next_in = (unsigned char *)bytes; + + // Collect the data. + do { + // update what we're passing in + strm.avail_out = kChunkSize; + strm.next_out = output; + retCode = deflate(&strm, Z_FINISH); + if ((retCode != Z_OK) && (retCode != Z_STREAM_END)) { + if (error) { + NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:retCode] + forKey:GULNSDataZlibErrorKey]; + *error = [NSError errorWithDomain:GULNSDataZlibErrorDomain + code:GULNSDataZlibErrorInternal + userInfo:userInfo]; + } + deflateEnd(&strm); + return nil; + } + // Collect what we got. + unsigned gotBack = kChunkSize - strm.avail_out; + if (gotBack > 0) { + [result appendBytes:output length:gotBack]; + } + + } while (retCode == Z_OK); + + // If the loop exits, it used all input and the stream ended. + NSAssert(strm.avail_in == 0, + @"Should have finished deflating without using all input, %u bytes left", strm.avail_in); + NSAssert(retCode == Z_STREAM_END, + @"thought we finished deflate w/o getting a result of stream end, code %d", retCode); + + // Clean up. + deflateEnd(&strm); + + return result; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h new file mode 100644 index 0000000..f195d57 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h @@ -0,0 +1,53 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// This is a copy of Google Toolbox for Mac library to avoid creating an extra framework. + +// NOTE: For 64bit, none of these apis handle input sizes >32bits, they will return nil when given +// such data. To handle data of that size you really should be streaming it rather then doing it all +// in memory. + +@interface NSData (GULGzip) + +/// Returns an data as the result of decompressing the payload of |data|.The data to decompress must +/// be a gzipped payloads. ++ (nullable NSData *)gul_dataByInflatingGzippedData:(NSData *)data error:(NSError **)error; + +/// Returns an compressed data with the result of gzipping the payload of |data|. Uses the default +/// compression level. ++ (nullable NSData *)gul_dataByGzippingData:(NSData *)data error:(NSError **)error; + +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorDomain; +FOUNDATION_EXPORT NSString *const GULNSDataZlibErrorKey; // NSNumber +FOUNDATION_EXPORT NSString *const GULNSDataZlibRemainingBytesKey; // NSNumber + +typedef NS_ENUM(NSInteger, GULNSDataZlibError) { + GULNSDataZlibErrorGreaterThan32BitsToCompress = 1024, + // An internal zlib error. + // GULNSDataZlibErrorKey will contain the error value. + // NSLocalizedDescriptionKey may contain an error string from zlib. + // Look in zlib.h for list of errors. + GULNSDataZlibErrorInternal, + // There was left over data in the buffer that was not used. + // GULNSDataZlibRemainingBytesKey will contain number of remaining bytes. + GULNSDataZlibErrorDataRemaining +}; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m new file mode 100644 index 0000000..7726d15 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULMutableDictionary.m @@ -0,0 +1,101 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" + +@implementation GULMutableDictionary { + /// The mutable dictionary. + NSMutableDictionary *_objects; + + /// Serial synchronization queue. All reads should use dispatch_sync, while writes use + /// dispatch_async. + dispatch_queue_t _queue; +} + +- (instancetype)init { + self = [super init]; + + if (self) { + _objects = [[NSMutableDictionary alloc] init]; + _queue = dispatch_queue_create("GULMutableDictionary", DISPATCH_QUEUE_SERIAL); + } + + return self; +} + +- (NSString *)description { + __block NSString *description; + dispatch_sync(_queue, ^{ + description = self->_objects.description; + }); + return description; +} + +- (id)objectForKey:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = [self->_objects objectForKey:key]; + }); + return object; +} + +- (void)setObject:(id)object forKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects setObject:object forKey:key]; + }); +} + +- (void)removeObjectForKey:(id)key { + dispatch_async(_queue, ^{ + [self->_objects removeObjectForKey:key]; + }); +} + +- (void)removeAllObjects { + dispatch_async(_queue, ^{ + [self->_objects removeAllObjects]; + }); +} + +- (NSUInteger)count { + __block NSUInteger count; + dispatch_sync(_queue, ^{ + count = self->_objects.count; + }); + return count; +} + +- (id)objectForKeyedSubscript:(id)key { + __block id object; + dispatch_sync(_queue, ^{ + object = self->_objects[key]; + }); + return object; +} + +- (void)setObject:(id)obj forKeyedSubscript:(id)key { + dispatch_async(_queue, ^{ + self->_objects[key] = obj; + }); +} + +- (NSDictionary *)dictionary { + __block NSDictionary *dictionary; + dispatch_sync(_queue, ^{ + dictionary = [self->_objects copy]; + }); + return dictionary; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m new file mode 100644 index 0000000..23b3bb0 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetwork.m @@ -0,0 +1,406 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/NSData+zlib/Public/GoogleUtilities/GULNSData+zlib.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +/// Constant string for request header Content-Encoding. +static NSString *const kGULNetworkContentCompressionKey = @"Content-Encoding"; + +/// Constant string for request header Content-Encoding value. +static NSString *const kGULNetworkContentCompressionValue = @"gzip"; + +/// Constant string for request header Content-Length. +static NSString *const kGULNetworkContentLengthKey = @"Content-Length"; + +/// Constant string for request header Content-Type. +static NSString *const kGULNetworkContentTypeKey = @"Content-Type"; + +/// Constant string for request header Content-Type value. +static NSString *const kGULNetworkContentTypeValue = @"application/x-www-form-urlencoded"; + +/// Constant string for GET request method. +static NSString *const kGULNetworkGETRequestMethod = @"GET"; + +/// Constant string for POST request method. +static NSString *const kGULNetworkPOSTRequestMethod = @"POST"; + +/// Default constant string as a prefix for network logger. +static NSString *const kGULNetworkLogTag = @"Google/Utilities/Network"; + +@interface GULNetwork () +@end + +@implementation GULNetwork { + /// Network reachability. + GULReachabilityChecker *_reachability; + + /// The dictionary of requests by session IDs { NSString : id }. + GULMutableDictionary *_requests; +} + +- (instancetype)init { + return [self initWithReachabilityHost:kGULNetworkReachabilityHost]; +} + +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost { + self = [super init]; + if (self) { + // Setup reachability. + _reachability = [[GULReachabilityChecker alloc] initWithReachabilityDelegate:self + withHost:reachabilityHost]; + if (![_reachability start]) { + return nil; + } + + _requests = [[GULMutableDictionary alloc] init]; + _timeoutInterval = kGULNetworkTimeOutInterval; + } + return self; +} + +- (void)dealloc { + _reachability.reachabilityDelegate = nil; + [_reachability stop]; +} + +#pragma mark - External Methods + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler { + [GULNetworkURLSession handleEventsForBackgroundURLSessionID:sessionID + completionHandler:completionHandler]; +} + +- (nullable NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + return [self postURL:url + headers:nil + payload:payload + queue:queue + usingBackgroundSession:usingBackgroundSession + completionHandler:handler]; +} + +- (nullable NSString *)postURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + request.allHTTPHeaderFields = headers; + + NSError *compressError = nil; + NSData *compressedData = [NSData gul_dataByGzippingData:payload error:&compressError]; + if (!compressedData || compressError) { + if (compressError || payload.length > 0) { + // If the payload is not empty but it fails to compress the payload, something has been wrong. + [self handleErrorWithCode:GULErrorCodeNetworkPayloadCompression + queue:queue + withHandler:handler]; + return nil; + } + compressedData = [[NSData alloc] init]; + } + + NSString *postLength = @(compressedData.length).stringValue; + + // Set up the request with the compressed data. + [request setValue:postLength forHTTPHeaderField:kGULNetworkContentLengthKey]; + request.HTTPBody = compressedData; + request.HTTPMethod = kGULNetworkPOSTRequestMethod; + [request setValue:kGULNetworkContentTypeValue forHTTPHeaderField:kGULNetworkContentTypeKey]; + [request setValue:kGULNetworkContentCompressionValue + forHTTPHeaderField:kGULNetworkContentCompressionKey]; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncPOSTRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, + NSString *sessionID, NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork000 + message:@"Uploading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (nullable NSString *)getURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler { + if (!url.absoluteString.length) { + [self handleErrorWithCode:GULErrorCodeNetworkInvalidURL queue:queue withHandler:handler]; + return nil; + } + + NSTimeInterval timeOutInterval = _timeoutInterval ?: kGULNetworkTimeOutInterval; + NSMutableURLRequest *request = + [[NSMutableURLRequest alloc] initWithURL:url + cachePolicy:NSURLRequestReloadIgnoringLocalCacheData + timeoutInterval:timeOutInterval]; + + if (!request) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + request.HTTPMethod = kGULNetworkGETRequestMethod; + request.allHTTPHeaderFields = headers; + + GULNetworkURLSession *fetcher = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:self]; + fetcher.backgroundNetworkEnabled = usingBackgroundSession; + + __weak GULNetwork *weakSelf = self; + NSString *requestID = [fetcher + sessionIDFromAsyncGETRequest:request + completionHandler:^(NSHTTPURLResponse *response, NSData *data, NSString *sessionID, + NSError *error) { + GULNetwork *strongSelf = weakSelf; + if (!strongSelf) { + return; + } + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + if (sessionID.length) { + [strongSelf->_requests removeObjectForKey:sessionID]; + } + if (handler) { + handler(response, data, error); + } + }); + }]; + + if (!requestID) { + [self handleErrorWithCode:GULErrorCodeNetworkSessionTaskCreation + queue:queue + withHandler:handler]; + return nil; + } + + [self GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeNetwork001 + message:@"Downloading data. Host" + context:url]; + _requests[requestID] = fetcher; + return requestID; +} + +- (BOOL)hasUploadInProgress { + return _requests.count > 0; +} + +#pragma mark - Network Reachability + +/// Tells reachability delegate to call reachabilityDidChangeToStatus: to notify the network +/// reachability has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status { + _networkConnected = (status == kGULReachabilityViaCellular || status == kGULReachabilityViaWifi); + [_reachabilityDelegate reachabilityDidChange]; +} + +#pragma mark - Network logger delegate + +- (void)setLoggerDelegate:(id)loggerDelegate { + // Explicitly check whether the delegate responds to the methods because conformsToProtocol does + // not work correctly even though the delegate does respond to the methods. + if (!loggerDelegate || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:contexts:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:context:)] || + ![loggerDelegate respondsToSelector:@selector(GULNetwork_logWithLevel: + messageCode:message:)]) { + GULOSLogError( + kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork002], + @"Cannot set the network logger delegate: delegate does not conform to the network " + "logger protocol."); + return; + } + _loggerDelegate = loggerDelegate; +} + +#pragma mark - Private methods + +/// Handles network error and calls completion handler with the error. +- (void)handleErrorWithCode:(NSInteger)code + queue:(dispatch_queue_t)queue + withHandler:(GULNetworkCompletionHandler)handler { + NSDictionary *userInfo = @{kGULNetworkErrorContext : @"Failed to create network request"}; + NSError *error = [[NSError alloc] initWithDomain:kGULNetworkErrorDomain + code:code + userInfo:userInfo]; + [self GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeNetwork002 + message:@"Failed to create network request. Code, error" + contexts:@[ @(code), error ]]; + if (handler) { + dispatch_queue_t queueToDispatch = queue ? queue : dispatch_get_main_queue(); + dispatch_async(queueToDispatch, ^{ + handler(nil, nil, error); + }); + } +} + +#pragma mark - Network logger + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts { + // Let the delegate log the message if there is a valid logger delegate. Otherwise, just log + // errors/warnings/info messages to the console log. + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + contexts:contexts]; + return; + } + if (_isDebugModeEnabled || logLevel == kGULNetworkLogLevelError || + logLevel == kGULNetworkLogLevelWarning || logLevel == kGULNetworkLogLevelInfo) { + NSString *formattedMessage = GULStringWithLogMessage(message, logLevel, contexts); + NSLog(@"%@", formattedMessage); + GULOSLogBasic((GULLoggerLevel)logLevel, kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)messageCode], formattedMessage, + NULL); + } +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel + messageCode:messageCode + message:message + context:context]; + return; + } + NSArray *contexts = context ? @[ context ] : @[]; + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:contexts]; +} + +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message { + if (_loggerDelegate) { + [_loggerDelegate GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message]; + return; + } + [self GULNetwork_logWithLevel:logLevel messageCode:messageCode message:message contexts:@[]]; +} + +/// Returns a string for the given log level (e.g. kGULNetworkLogLevelError -> @"ERROR"). +static NSString *GULLogLevelDescriptionFromLogLevel(GULNetworkLogLevel logLevel) { + static NSDictionary *levelNames = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + levelNames = @{ + @(kGULNetworkLogLevelError) : @"ERROR", + @(kGULNetworkLogLevelWarning) : @"WARNING", + @(kGULNetworkLogLevelInfo) : @"INFO", + @(kGULNetworkLogLevelDebug) : @"DEBUG" + }; + }); + return levelNames[@(logLevel)]; +} + +/// Returns a formatted string to be used for console logging. +static NSString *GULStringWithLogMessage(NSString *message, + GULNetworkLogLevel logLevel, + NSArray *contexts) { + if (!message) { + message = @"(Message was nil)"; + } else if (!message.length) { + message = @"(Message was empty)"; + } + NSMutableString *result = [[NSMutableString alloc] + initWithFormat:@"<%@/%@> %@", kGULNetworkLogTag, GULLogLevelDescriptionFromLogLevel(logLevel), + message]; + + if (!contexts.count) { + return result; + } + + NSMutableArray *formattedContexts = [[NSMutableArray alloc] init]; + for (id item in contexts) { + [formattedContexts addObject:(item != [NSNull null] ? item : @"(nil)")]; + } + + [result appendString:@": "]; + [result appendString:[formattedContexts componentsJoinedByString:@", "]]; + return result; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m new file mode 100644 index 0000000..e4b8469 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkConstants.m @@ -0,0 +1,41 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +#import + +NSString *const kGULNetworkBackgroundSessionConfigIDPrefix = @"com.gul.network.background-upload"; +NSString *const kGULNetworkApplicationSupportSubdirectory = @"GUL/Network"; +NSString *const kGULNetworkTempDirectoryName = @"GULNetworkTemporaryDirectory"; +const NSTimeInterval kGULNetworkTempFolderExpireTime = 60 * 60; // 1 hour +const NSTimeInterval kGULNetworkTimeOutInterval = 60; // 1 minute. +NSString *const kGULNetworkReachabilityHost = @"app-measurement.com"; +NSString *const kGULNetworkErrorContext = @"Context"; + +const int kGULNetworkHTTPStatusOK = 200; +const int kGULNetworkHTTPStatusNoContent = 204; +const int kGULNetworkHTTPStatusCodeMultipleChoices = 300; +const int kGULNetworkHTTPStatusCodeMovedPermanently = 301; +const int kGULNetworkHTTPStatusCodeFound = 302; +const int kGULNetworkHTTPStatusCodeNotModified = 304; +const int kGULNetworkHTTPStatusCodeMovedTemporarily = 307; +const int kGULNetworkHTTPStatusCodeNotFound = 404; +const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic = 429; +const int kGULNetworkHTTPStatusCodeUnavailable = 503; + +NSString *const kGULNetworkErrorDomain = @"com.gul.network.ErrorDomain"; + +GULLoggerService kGULLoggerNetwork = @"[GULNetwork]"; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h new file mode 100644 index 0000000..5aca9fd --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkInternal.h @@ -0,0 +1,24 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +extern NSString *const kGULNetworkErrorDomain; + +/// The logger service for GULNetwork. +extern GULLoggerService kGULLoggerNetwork; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m new file mode 100644 index 0000000..c29de0c --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/GULNetworkURLSession.m @@ -0,0 +1,729 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" +#import "GoogleUtilities/Network/GULNetworkInternal.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h" +#import "GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h" + +@interface GULNetworkURLSession () +@end + +@implementation GULNetworkURLSession { + /// The handler to be called when the request completes or error has occurs. + GULNetworkURLSessionCompletionHandler _completionHandler; + + /// Session ID generated randomly with a fixed prefix. + NSString *_sessionID; + + /// The session configuration. + NSURLSessionConfiguration *_sessionConfig; + + /// The current NSURLSession. + NSURLSession *__weak _Nullable _URLSession; + + /// The path to the directory where all temporary files are stored before uploading. + NSURL *_networkDirectoryURL; + + /// The downloaded data from fetching. + NSData *_downloadedData; + + /// The path to the temporary file which stores the uploading data. + NSURL *_uploadingFileURL; + + /// The current request. + NSURLRequest *_request; +} + +#pragma mark - Init + +- (instancetype)initWithNetworkLoggerDelegate:(id)networkLoggerDelegate { + self = [super init]; + if (self) { + // Create URL to the directory where all temporary files to upload have to be stored. +#if TARGET_OS_TV + NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); +#else + NSArray *paths = + NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); +#endif + NSString *storageDirectory = paths.firstObject; + NSArray *tempPathComponents = @[ + storageDirectory, kGULNetworkApplicationSupportSubdirectory, kGULNetworkTempDirectoryName + ]; + _networkDirectoryURL = [NSURL fileURLWithPathComponents:tempPathComponents]; + _sessionID = [NSString stringWithFormat:@"%@-%@", kGULNetworkBackgroundSessionConfigIDPrefix, + [[NSUUID UUID] UUIDString]]; + _loggerDelegate = networkLoggerDelegate; + } + return self; +} + +#pragma mark - External Methods + +#pragma mark - To be called from AppDelegate + ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler: + (GULNetworkSystemCompletionHandler)systemCompletionHandler { + // The session may not be Analytics background. Ignore those that do not have the prefix. + if (![sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + return; + } + GULNetworkURLSession *fetcher = [self fetcherWithSessionIdentifier:sessionID]; + if (fetcher != nil) { + [fetcher addSystemCompletionHandler:systemCompletionHandler forSession:sessionID]; + } else { + GULOSLogError(kGULLogSubsystem, kGULLoggerNetwork, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULNetworkMessageCodeNetwork003], + @"Failed to retrieve background session with ID %@ after app is relaunched.", + sessionID); + } +} + +#pragma mark - External Methods + +/// Sends an async POST request using `NSURLSession`, and returns an ID of the connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler: + (GULNetworkURLSessionCompletionHandler)handler { + // NSURLSessionUploadTask does not work with NSData in the background. + // To avoid this issue, write the data to a temporary file to upload it. + // Make a temporary file with the data subset. + _uploadingFileURL = [self temporaryFilePathWithSessionID:_sessionID]; + NSError *writeError; + NSURLSessionUploadTask *postRequestTask; + NSURLSession *session; + BOOL didWriteFile = NO; + + // Clean up the entire temp folder to avoid temp files that remain in case the previous session + // crashed and did not clean up. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // If there is no background network enabled, no need to write to file. This will allow default + // network session which runs on the foreground. + if (_backgroundNetworkEnabled && [self ensureTemporaryDirectoryExists]) { + didWriteFile = [request.HTTPBody writeToFile:_uploadingFileURL.path + options:NSDataWritingAtomic + error:&writeError]; + + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession000 + message:@"Failed to write request data to file" + context:writeError]; + } + } + + if (didWriteFile) { + // Exclude this file from backing up to iTunes. There are conflicting reports that excluding + // directory from backing up does not exclude files of that directory from backing up. + [self excludeFromBackupForURL:_uploadingFileURL]; + + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + // If we cannot write to file, just send it in the foreground. + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + [self populateSessionConfig:_sessionConfig withRequest:request]; + session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + // To avoid a runtime warning in Xcode 15 Beta 4, the given `URLRequest` + // should have a nil `HTTPBody`. To workaround this, the given `URLRequest` + // is copied and the `HTTPBody` data is removed. + NSData *givenRequestHTTPBody = [request.HTTPBody copy]; + NSMutableURLRequest *requestWithoutHTTPBody = [request mutableCopy]; + requestWithoutHTTPBody.HTTPBody = nil; + + if (didWriteFile) { + postRequestTask = [session uploadTaskWithRequest:requestWithoutHTTPBody + fromFile:_uploadingFileURL]; + } else { + postRequestTask = [session uploadTaskWithRequest:requestWithoutHTTPBody + fromData:givenRequestHTTPBody]; + } + + if (!session || !postRequestTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + // Store completion handler because background session does not accept handler block but custom + // delegate. + _completionHandler = [handler copy]; + [postRequestTask resume]; + + return _sessionID; +} + +/// Sends an async GET request using `NSURLSession`, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler { + if (_backgroundNetworkEnabled) { + _sessionConfig = [self backgroundSessionConfigWithSessionID:_sessionID]; + } else { + _sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration]; + } + + [self populateSessionConfig:_sessionConfig withRequest:request]; + + // Do not cache the GET request. + _sessionConfig.URLCache = nil; + + NSURLSession *session = [NSURLSession sessionWithConfiguration:_sessionConfig + delegate:self + delegateQueue:[NSOperationQueue mainQueue]]; + NSURLSessionDownloadTask *downloadTask = [session downloadTaskWithRequest:request]; + + if (!session || !downloadTask) { + NSError *error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkRequestCreation + userInfo:@{kGULNetworkErrorContext : @"Cannot create network session"}]; + [self callCompletionHandler:handler withResponse:nil data:nil error:error]; + return nil; + } + + _URLSession = session; + + // Save the session into memory. + [[self class] setSessionInFetcherMap:self forSessionID:_sessionID]; + + _request = [request copy]; + + _completionHandler = [handler copy]; + [downloadTask resume]; + + return _sessionID; +} + +#pragma mark - NSURLSessionDataDelegate + +/// Called by the NSURLSession when the data task has received some of the expected data. +/// Once the session is completed, URLSession:task:didCompleteWithError will be called and the +/// completion handler will be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + dataTask:(NSURLSessionDataTask *)dataTask + didReceiveData:(NSData *)data { + @synchronized(self) { + NSMutableData *mutableData = [[NSMutableData alloc] init]; + if (_downloadedData) { + mutableData = _downloadedData.mutableCopy; + } + [mutableData appendData:data]; + _downloadedData = mutableData; + } +} + +#pragma mark - NSURLSessionTaskDelegate + +/// Called by the NSURLSession once the download task is completed. The file is saved in the +/// provided URL so we need to read the data and store into _downloadedData. Once the session is +/// completed, URLSession:task:didCompleteWithError will be called and the completion handler will +/// be called with the downloaded data. +- (void)URLSession:(NSURLSession *)session + downloadTask:(NSURLSessionDownloadTask *)task + didFinishDownloadingToURL:(NSURL *)url { + if (!url.path) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession001 + message:@"Unable to read downloaded data from empty temp path"]; + _downloadedData = nil; + return; + } + + NSError *error; + _downloadedData = [NSData dataWithContentsOfFile:url.path options:0 error:&error]; + + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession002 + message:@"Cannot read the content of downloaded data" + context:error]; + _downloadedData = nil; + } +} + +#if TARGET_OS_IOS || TARGET_OS_TV +- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession003 + message:@"Background session finished" + context:session.configuration.identifier]; + [self callSystemCompletionHandler:session.configuration.identifier]; +} +#endif + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didCompleteWithError:(NSError *)error { + // Avoid any chance of recursive behavior leading to it being used repeatedly. + GULNetworkURLSessionCompletionHandler handler = _completionHandler; + _completionHandler = nil; + + if (task.response) { + // The following assertion should always be true for HTTP requests, see https://goo.gl/gVLxT7. + NSAssert([task.response isKindOfClass:[NSHTTPURLResponse class]], @"URL response must be HTTP"); + + // The server responded so ignore the error created by the system. + error = nil; + } else if (!error) { + error = [[NSError alloc] + initWithDomain:kGULNetworkErrorDomain + code:GULErrorCodeNetworkInvalidResponse + userInfo:@{kGULNetworkErrorContext : @"Network Error: Empty network response"}]; + } + + [self callCompletionHandler:handler + withResponse:(NSHTTPURLResponse *)task.response + data:_downloadedData + error:error]; + + // Remove the temp file to avoid trashing devices with lots of temp files. + [self removeTempItemAtURL:_uploadingFileURL]; + + // Try to clean up stale files again. + [self maybeRemoveTempFilesAtURL:_networkDirectoryURL + expiringTime:kGULNetworkTempFolderExpireTime]; + + // This is called without checking the sessionID here since non-background sessions + // won't have an ID. + [session finishTasksAndInvalidate]; + + // Explicitly remove the session so it won't be reused. The weak map table should + // remove the session on deallocation, but dealloc may not happen immediately after + // calling `finishTasksAndInvalidate`. + NSString *sessionID = session.configuration.identifier; + [[self class] setSessionInFetcherMap:nil forSessionID:sessionID]; +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge + completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, + NSURLCredential *credential))completionHandler { + // The handling is modeled after GTMSessionFetcher. + if ([challenge.protectionSpace.authenticationMethod + isEqualToString:NSURLAuthenticationMethodServerTrust]) { + SecTrustRef serverTrust = challenge.protectionSpace.serverTrust; + if (serverTrust == NULL) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession004 + message:@"Received empty server trust for host. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); + return; + } + NSURLCredential *credential = [NSURLCredential credentialForTrust:serverTrust]; + if (!credential) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession005 + message:@"Unable to verify server identity. Host" + context:_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + return; + } + + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession006 + message:@"Received SSL challenge for host. Host" + context:_request.URL]; + + void (^callback)(BOOL) = ^(BOOL allow) { + if (allow) { + completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + } else { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession007 + message:@"Cancelling authentication challenge for host. Host" + context:self->_request.URL]; + completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, nil); + } + }; + + // Retain the trust object to avoid a SecTrustEvaluate() crash on iOS 7. + CFRetain(serverTrust); + + // Evaluate the certificate chain. + // + // The delegate queue may be the main thread. Trust evaluation could cause some + // blocking network activity, so we must evaluate async, as documented at + // https://developer.apple.com/library/ios/technotes/tn2232/ + dispatch_queue_t evaluateBackgroundQueue = + dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + dispatch_async(evaluateBackgroundQueue, ^{ + BOOL shouldAllow; + CFErrorRef errorRef = NULL; + + @synchronized([GULNetworkURLSession class]) { + shouldAllow = SecTrustEvaluateWithError(serverTrust, &errorRef); + } + + if (errorRef) { + [self->_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession008 + message:@"Cannot evaluate server trust. Error, host" + contexts:@[ @((int)CFErrorGetCode(errorRef)), self->_request.URL ]]; + CFRelease(errorRef); + } + + // Call the call back with the permission. + callback(shouldAllow); + + CFRelease(serverTrust); + }); + return; + } + + // Default handling for other Auth Challenges. + completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); +} + +#pragma mark - Internal Methods + +/// Stores system completion handler with session ID as key. +- (void)addSystemCompletionHandler:(GULNetworkSystemCompletionHandler)handler + forSession:(NSString *)identifier { + if (!handler) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession009 + message:@"Cannot store nil system completion handler in network"]; + return; + } + + if (!identifier.length) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession010 + message:@"Cannot store system completion handler with empty network " + "session identifier"]; + return; + } + + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + if (systemCompletionHandlers[identifier]) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession011 + message:@"Got multiple system handlers for a single session ID" + context:identifier]; + } + + systemCompletionHandlers[identifier] = handler; +} + +/// Calls the system provided completion handler with the session ID stored in the dictionary. +/// The handler will be removed from the dictionary after being called. +- (void)callSystemCompletionHandler:(NSString *)identifier { + GULMutableDictionary *systemCompletionHandlers = + [[self class] sessionIDToSystemCompletionHandlerDictionary]; + GULNetworkSystemCompletionHandler handler = [systemCompletionHandlers objectForKey:identifier]; + + if (handler) { + [systemCompletionHandlers removeObjectForKey:identifier]; + + dispatch_async(dispatch_get_main_queue(), ^{ + handler(); + }); + } +} + +/// Sets or updates the session ID of this session. +- (void)setSessionID:(NSString *)sessionID { + _sessionID = [sessionID copy]; +} + +/// Creates a background session configuration with the session ID using the supported method. +- (NSURLSessionConfiguration *)backgroundSessionConfigWithSessionID:(NSString *)sessionID { + return [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:sessionID]; +} + +- (void)maybeRemoveTempFilesAtURL:(NSURL *)folderURL expiringTime:(NSTimeInterval)staleTime { + if (!folderURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + NSArray *properties = @[ NSURLCreationDateKey ]; + NSArray *directoryContent = + [fileManager contentsOfDirectoryAtURL:folderURL + includingPropertiesForKeys:properties + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants + error:&error]; + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelDebug + messageCode:kGULNetworkMessageCodeURLSession012 + message:@"Cannot get files from the temporary network folder. Error" + context:error]; + return; + } + + if (!directoryContent.count) { + return; + } + + NSTimeInterval now = [NSDate date].timeIntervalSince1970; + for (NSURL *tempFile in directoryContent) { + NSDate *creationDate; + BOOL getCreationDate = [tempFile getResourceValue:&creationDate + forKey:NSURLCreationDateKey + error:NULL]; + if (!getCreationDate) { + continue; + } + NSTimeInterval creationTimeInterval = creationDate.timeIntervalSince1970; + if (fabs(now - creationTimeInterval) > staleTime) { + [self removeTempItemAtURL:tempFile]; + } + } +} + +/// Removes the temporary file written to disk for sending the request. It has to be cleaned up +/// after the session is done. +- (void)removeTempItemAtURL:(NSURL *)fileURL { + if (!fileURL.absoluteString.length) { + return; + } + + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + if (![fileManager removeItemAtURL:fileURL error:&error] && error.code != NSFileNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession013 + message:@"Failed to remove temporary uploading data file. Error" + context:error.localizedDescription]; + } +} + +/// Gets the fetcher with the session ID. ++ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier { + GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier]; + if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) { + session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil]; + [session setSessionID:sessionIdentifier]; + [self setSessionInFetcherMap:session forSessionID:sessionIdentifier]; + } + return session; +} + +/// Returns a map of the fetcher by session ID. Creates a map if it is not created. +/// When reading and writing from/to the session map, don't use this method directly. +/// To avoid thread safety issues, use one of the helper methods at the bottom of the +/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID: ++ (NSMapTable *)sessionIDToFetcherMap { + static NSMapTable *sessionIDToFetcherMap; + + static dispatch_once_t sessionMapOnceToken; + dispatch_once(&sessionMapOnceToken, ^{ + sessionIDToFetcherMap = [NSMapTable strongToWeakObjectsMapTable]; + }); + return sessionIDToFetcherMap; +} + ++ (NSLock *)sessionIDToFetcherMapReadWriteLock { + static NSLock *lock; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + lock = [[NSLock alloc] init]; + }); + return lock; +} + +/// Returns a map of system provided completion handler by session ID. Creates a map if it is not +/// created. ++ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary { + static GULMutableDictionary *systemCompletionHandlers; + + static dispatch_once_t systemCompletionHandlerOnceToken; + dispatch_once(&systemCompletionHandlerOnceToken, ^{ + systemCompletionHandlers = [[GULMutableDictionary alloc] init]; + }); + return systemCompletionHandlers; +} + +- (NSURL *)temporaryFilePathWithSessionID:(NSString *)sessionID { + NSString *tempName = [NSString stringWithFormat:@"GULUpload_temp_%@", sessionID]; + return [_networkDirectoryURL URLByAppendingPathComponent:tempName]; +} + +/// Makes sure that the directory to store temp files exists. If not, tries to create it and returns +/// YES. If there is anything wrong, returns NO. +- (BOOL)ensureTemporaryDirectoryExists { + NSFileManager *fileManager = [NSFileManager defaultManager]; + NSError *error = nil; + + // Create a temporary directory if it does not exist or was deleted. + if ([_networkDirectoryURL checkResourceIsReachableAndReturnError:&error]) { + return YES; + } + + if (error && error.code != NSFileReadNoSuchFileError) { + [_loggerDelegate + GULNetwork_logWithLevel:kGULNetworkLogLevelWarning + messageCode:kGULNetworkMessageCodeURLSession014 + message:@"Error while trying to access Network temp folder. Error" + context:error]; + } + + NSError *writeError = nil; + + [fileManager createDirectoryAtURL:_networkDirectoryURL + withIntermediateDirectories:YES + attributes:nil + error:&writeError]; + if (writeError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession015 + message:@"Cannot create temporary directory. Error" + context:writeError]; + return NO; + } + + // Set the iCloud exclusion attribute on the Documents URL. + [self excludeFromBackupForURL:_networkDirectoryURL]; + + return YES; +} + +- (void)excludeFromBackupForURL:(NSURL *)url { + if (!url.path) { + return; + } + + // Set the iCloud exclusion attribute on the Documents URL. + NSError *preventBackupError = nil; + [url setResourceValue:@YES forKey:NSURLIsExcludedFromBackupKey error:&preventBackupError]; + if (preventBackupError) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession016 + message:@"Cannot exclude temporary folder from iTunes backup"]; + } +} + +- (void)URLSession:(NSURLSession *)session + task:(NSURLSessionTask *)task + willPerformHTTPRedirection:(NSHTTPURLResponse *)response + newRequest:(NSURLRequest *)request + completionHandler:(void (^)(NSURLRequest *))completionHandler { + NSArray *nonAllowedRedirectionCodes = @[ + @(kGULNetworkHTTPStatusCodeFound), @(kGULNetworkHTTPStatusCodeMovedPermanently), + @(kGULNetworkHTTPStatusCodeMovedTemporarily), @(kGULNetworkHTTPStatusCodeMultipleChoices) + ]; + + // Allow those not in the non allowed list to be followed. + if (![nonAllowedRedirectionCodes containsObject:@(response.statusCode)]) { + completionHandler(request); + return; + } + + // Do not allow redirection if the response code is in the non-allowed list. + NSURLRequest *newRequest = request; + + if (response) { + newRequest = nil; + } + + completionHandler(newRequest); +} + +#pragma mark - Helper Methods + ++ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *existingSession = + [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + if (existingSession) { + if (session) { + NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession]; + [existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo + messageCode:kGULNetworkMessageCodeURLSession019 + message:message]; + } + [existingSession->_URLSession finishTasksAndInvalidate]; + } + if (session) { + [[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID]; + } else { + [[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID]; + } + [[self sessionIDToFetcherMapReadWriteLock] unlock]; +} + ++ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID { + [[self sessionIDToFetcherMapReadWriteLock] lock]; + GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID]; + [[self sessionIDToFetcherMapReadWriteLock] unlock]; + return session; +} + +- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler + withResponse:(NSHTTPURLResponse *)response + data:(NSData *)data + error:(NSError *)error { + if (error) { + [_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelError + messageCode:kGULNetworkMessageCodeURLSession017 + message:@"Encounter network error. Code, error" + contexts:@[ @(error.code), error ]]; + } + + if (handler) { + dispatch_async(dispatch_get_main_queue(), ^{ + handler(response, data, self->_sessionID, error); + }); + } +} + +// Always use the request parameters even if the default session configuration is more restrictive. +- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig + withRequest:(NSURLRequest *)request { + sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields; + sessionConfig.timeoutIntervalForRequest = request.timeoutInterval; + sessionConfig.timeoutIntervalForResource = request.timeoutInterval; + sessionConfig.requestCachePolicy = request.cachePolicy; +} + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h new file mode 100644 index 0000000..02f25db --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULMutableDictionary.h @@ -0,0 +1,50 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A mutable dictionary that provides atomic accessor and mutators. +@interface GULMutableDictionary : NSObject + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKey:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)object forKey:(id)key; + +/// Removes the object given its session ID from the dictionary. +- (void)removeObjectForKey:(id)key; + +/// Removes all objects. +- (void)removeAllObjects; + +/// Returns the number of current objects in the dictionary. +- (NSUInteger)count; + +/// Returns an object given a key in the dictionary or nil if not found. +- (id)objectForKeyedSubscript:(id)key; + +/// Updates the object given its key or adds it to the dictionary if it is not in the dictionary. +- (void)setObject:(id)obj forKeyedSubscript:(id)key; + +/// Returns the immutable dictionary. +- (NSDictionary *)dictionary; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h new file mode 100644 index 0000000..4c5b5f5 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetwork.h @@ -0,0 +1,101 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkURLSession.h" + +NS_ASSUME_NONNULL_BEGIN + +/// Delegate protocol for GULNetwork events. +@protocol GULNetworkReachabilityDelegate + +/// Tells the delegate to handle events when the network reachability changes to connected or not +/// connected. +- (void)reachabilityDidChange; + +@end + +/// The Network component that provides network status and handles network requests and responses. +/// This is not thread safe. +/// +/// NOTE: +/// User must add FIRAnalytics handleEventsForBackgroundURLSessionID:completionHandler to the +/// AppDelegate application:handleEventsForBackgroundURLSession:completionHandler: +@interface GULNetwork : NSObject + +/// Indicates if network connectivity is available. +@property(nonatomic, readonly, getter=isNetworkConnected) BOOL networkConnected; + +/// Indicates if there are any uploads in progress. +@property(nonatomic, readonly, getter=hasUploadInProgress) BOOL uploadInProgress; + +/// An optional delegate that can be used in the event when network reachability changes. +@property(nonatomic, weak) id reachabilityDelegate; + +/// An optional delegate that can be used to log messages, warnings or errors that occur in the +/// network operations. +@property(nonatomic, weak) id loggerDelegate; + +/// Indicates whether the logger should display debug messages. +@property(nonatomic, assign) BOOL isDebugModeEnabled; + +/// The time interval in seconds for the network request to timeout. +@property(nonatomic, assign) NSTimeInterval timeoutInterval; + +/// Initializes with the default reachability host. +- (instancetype)init; + +/// Initializes with a custom reachability host. +- (instancetype)initWithReachabilityHost:(NSString *)reachabilityHost; + +/// Handles events when background session with the given ID has finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Compresses and sends a POST request with the provided data to the URL. The session will be +/// background session if usingBackgroundSession is YES. Otherwise, the POST session is default +/// session. Returns a session ID or nil if an error occurs. +- (nullable NSString *)postURL:(NSURL *)url + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Compresses and sends a POST request with the provided headers and data to the URL. The session +/// will be background session if usingBackgroundSession is YES. Otherwise, the POST session is +/// default session. Returns a session ID or nil if an error occurs. +- (nullable NSString *)postURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + payload:(NSData *)payload + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +/// Sends a GET request with the provided data to the URL. The session will be background session +/// if usingBackgroundSession is YES. Otherwise, the GET session is default session. Returns a +/// session ID or nil if an error occurs. +- (nullable NSString *)getURL:(NSURL *)url + headers:(nullable NSDictionary *)headers + queue:(nullable dispatch_queue_t)queue + usingBackgroundSession:(BOOL)usingBackgroundSession + completionHandler:(GULNetworkCompletionHandler)handler; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h new file mode 100644 index 0000000..341b974 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkConstants.h @@ -0,0 +1,75 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// Error codes in Firebase Network error domain. +/// Note: these error codes should never change. It would make it harder to decode the errors if +/// we inadvertently altered any of these codes in a future SDK version. +typedef NS_ENUM(NSInteger, GULNetworkErrorCode) { + /// Unknown error. + GULNetworkErrorCodeUnknown = 0, + /// Error occurs when the request URL is invalid. + GULErrorCodeNetworkInvalidURL = 1, + /// Error occurs when request cannot be constructed. + GULErrorCodeNetworkRequestCreation = 2, + /// Error occurs when payload cannot be compressed. + GULErrorCodeNetworkPayloadCompression = 3, + /// Error occurs when session task cannot be created. + GULErrorCodeNetworkSessionTaskCreation = 4, + /// Error occurs when there is no response. + GULErrorCodeNetworkInvalidResponse = 5 +}; + +#pragma mark - Network constants + +/// The prefix of the ID of the background session. +extern NSString *const kGULNetworkBackgroundSessionConfigIDPrefix; + +/// The sub directory to store the files of data that is being uploaded in the background. +extern NSString *const kGULNetworkApplicationSupportSubdirectory; + +/// Name of the temporary directory that stores files for background uploading. +extern NSString *const kGULNetworkTempDirectoryName; + +/// The period when the temporary uploading file can stay. +extern const NSTimeInterval kGULNetworkTempFolderExpireTime; + +/// The default network request timeout interval. +extern const NSTimeInterval kGULNetworkTimeOutInterval; + +/// The host to check the reachability of the network. +extern NSString *const kGULNetworkReachabilityHost; + +/// The key to get the error context of the UserInfo. +extern NSString *const kGULNetworkErrorContext; + +#pragma mark - Network Status Code + +extern const int kGULNetworkHTTPStatusOK; +extern const int kGULNetworkHTTPStatusNoContent; +extern const int kGULNetworkHTTPStatusCodeMultipleChoices; +extern const int kGULNetworkHTTPStatusCodeMovedPermanently; +extern const int kGULNetworkHTTPStatusCodeFound; +extern const int kGULNetworkHTTPStatusCodeNotModified; +extern const int kGULNetworkHTTPStatusCodeMovedTemporarily; +extern const int kGULNetworkHTTPStatusCodeNotFound; +extern const int kGULNetworkHTTPStatusCodeCannotAcceptTraffic; +extern const int kGULNetworkHTTPStatusCodeUnavailable; + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h new file mode 100644 index 0000000..b9e93ec --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkLoggerProtocol.h @@ -0,0 +1,53 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkMessageCode.h" + +NS_ASSUME_NONNULL_BEGIN + +/// The log levels used by GULNetworkLogger. +typedef NS_ENUM(NSInteger, GULNetworkLogLevel) { + kGULNetworkLogLevelError = 3, + kGULNetworkLogLevelWarning = 4, + kGULNetworkLogLevelInfo = 6, + kGULNetworkLogLevelDebug = 7, +}; + +@protocol GULNetworkLoggerDelegate + +@required +/// Tells the delegate to log a message with an array of contexts and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + contexts:(NSArray *)contexts; + +/// Tells the delegate to log a message with a context and the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message + context:(id)context; + +/// Tells the delegate to log a message with the log level. +- (void)GULNetwork_logWithLevel:(GULNetworkLogLevel)logLevel + messageCode:(GULNetworkMessageCode)messageCode + message:(NSString *)message; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h new file mode 100644 index 0000000..2d45ec6 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkMessageCode.h @@ -0,0 +1,51 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULNetworkMessageCode) { + // GULNetwork.m + kGULNetworkMessageCodeNetwork000 = 900000, // I-NET900000 + kGULNetworkMessageCodeNetwork001 = 900001, // I-NET900001 + kGULNetworkMessageCodeNetwork002 = 900002, // I-NET900002 + kGULNetworkMessageCodeNetwork003 = 900003, // I-NET900003 + // GULNetworkURLSession.m + kGULNetworkMessageCodeURLSession000 = 901000, // I-NET901000 + kGULNetworkMessageCodeURLSession001 = 901001, // I-NET901001 + kGULNetworkMessageCodeURLSession002 = 901002, // I-NET901002 + kGULNetworkMessageCodeURLSession003 = 901003, // I-NET901003 + kGULNetworkMessageCodeURLSession004 = 901004, // I-NET901004 + kGULNetworkMessageCodeURLSession005 = 901005, // I-NET901005 + kGULNetworkMessageCodeURLSession006 = 901006, // I-NET901006 + kGULNetworkMessageCodeURLSession007 = 901007, // I-NET901007 + kGULNetworkMessageCodeURLSession008 = 901008, // I-NET901008 + kGULNetworkMessageCodeURLSession009 = 901009, // I-NET901009 + kGULNetworkMessageCodeURLSession010 = 901010, // I-NET901010 + kGULNetworkMessageCodeURLSession011 = 901011, // I-NET901011 + kGULNetworkMessageCodeURLSession012 = 901012, // I-NET901012 + kGULNetworkMessageCodeURLSession013 = 901013, // I-NET901013 + kGULNetworkMessageCodeURLSession014 = 901014, // I-NET901014 + kGULNetworkMessageCodeURLSession015 = 901015, // I-NET901015 + kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016 + kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017 + kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018 + kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019 +}; + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h new file mode 100644 index 0000000..3f9f7f9 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Network/Public/GoogleUtilities/GULNetworkURLSession.h @@ -0,0 +1,62 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +#import "GULNetworkLoggerProtocol.h" + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^GULNetworkCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSError *_Nullable error); +typedef void (^GULNetworkURLSessionCompletionHandler)(NSHTTPURLResponse *_Nullable response, + NSData *_Nullable data, + NSString *sessionID, + NSError *_Nullable error); +typedef void (^GULNetworkSystemCompletionHandler)(void); + +/// The protocol that uses NSURLSession for iOS >= 7.0 to handle requests and responses. +@interface GULNetworkURLSession : NSObject + +/// Indicates whether the background network is enabled. Default value is NO. +@property(nonatomic, getter=isBackgroundNetworkEnabled) BOOL backgroundNetworkEnabled; + +/// The logger delegate to log message, errors or warnings that occur during the network operations. +@property(nonatomic, weak, nullable) id loggerDelegate; + +/// Calls the system provided completion handler after the background session is finished. ++ (void)handleEventsForBackgroundURLSessionID:(NSString *)sessionID + completionHandler:(GULNetworkSystemCompletionHandler)completionHandler; + +/// Initializes with logger delegate. +- (instancetype)initWithNetworkLoggerDelegate: + (nullable id)networkLoggerDelegate NS_DESIGNATED_INITIALIZER; + +- (instancetype)init NS_UNAVAILABLE; + +/// Sends an asynchronous POST request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session/connection. +- (nullable NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +/// Sends an asynchronous GET request and calls the provided completion handler when the request +/// completes or when errors occur, and returns an ID of the session. +- (nullable NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request + completionHandler:(GULNetworkURLSessionCompletionHandler)handler; + +NS_ASSUME_NONNULL_END +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy b/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..1c9e1a6 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Privacy/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,34 @@ + + + + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + NSPrivacyCollectedDataTypes + + + NSPrivacyAccessedAPITypes + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryFileTimestamp + NSPrivacyAccessedAPITypeReasons + + C617.1 + + + + NSPrivacyAccessedAPIType + NSPrivacyAccessedAPICategoryUserDefaults + NSPrivacyAccessedAPITypeReasons + + C56D.1 + + + + + + diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h new file mode 100644 index 0000000..103ed3b --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h @@ -0,0 +1,48 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#if !TARGET_OS_WATCH +typedef SCNetworkReachabilityRef (*GULReachabilityCreateWithNameFn)(CFAllocatorRef allocator, + const char *host); + +typedef Boolean (*GULReachabilitySetCallbackFn)(SCNetworkReachabilityRef target, + SCNetworkReachabilityCallBack callback, + SCNetworkReachabilityContext *context); +typedef Boolean (*GULReachabilityScheduleWithRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); +typedef Boolean (*GULReachabilityUnscheduleFromRunLoopFn)(SCNetworkReachabilityRef target, + CFRunLoopRef runLoop, + CFStringRef runLoopMode); + +typedef void (*GULReachabilityReleaseFn)(CFTypeRef cf); + +struct GULReachabilityApi { + GULReachabilityCreateWithNameFn createWithNameFn; + GULReachabilitySetCallbackFn setCallbackFn; + GULReachabilityScheduleWithRunLoopFn scheduleWithRunLoopFn; + GULReachabilityUnscheduleFromRunLoopFn unscheduleFromRunLoopFn; + GULReachabilityReleaseFn releaseFn; +}; +#endif +@interface GULReachabilityChecker (Internal) + +- (const struct GULReachabilityApi *)reachabilityApi; +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi; + +@end diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m new file mode 100644 index 0000000..e3745c6 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityChecker.m @@ -0,0 +1,263 @@ +// Copyright 2017 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +#import "GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h" + +#import "GoogleUtilities/Reachability/GULReachabilityChecker+Internal.h" +#import "GoogleUtilities/Reachability/GULReachabilityMessageCode.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +static GULLoggerService kGULLoggerReachability = @"[GULReachability]"; +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info); + +static const struct GULReachabilityApi kGULDefaultReachabilityApi = { + SCNetworkReachabilityCreateWithName, + SCNetworkReachabilitySetCallback, + SCNetworkReachabilityScheduleWithRunLoop, + SCNetworkReachabilityUnscheduleFromRunLoop, + CFRelease, +}; + +static NSString *const kGULReachabilityUnknownStatus = @"Unknown"; +static NSString *const kGULReachabilityConnectedStatus = @"Connected"; +static NSString *const kGULReachabilityDisconnectedStatus = @"Disconnected"; +#endif +@interface GULReachabilityChecker () + +@property(nonatomic, assign) const struct GULReachabilityApi *reachabilityApi; +@property(nonatomic, assign) GULReachabilityStatus reachabilityStatus; +@property(nonatomic, copy) NSString *host; +#if !TARGET_OS_WATCH +@property(nonatomic, assign) SCNetworkReachabilityRef reachability; +#endif + +@end + +@implementation GULReachabilityChecker + +@synthesize reachabilityApi = reachabilityApi_; +#if !TARGET_OS_WATCH +@synthesize reachability = reachability_; +#endif + +- (const struct GULReachabilityApi *)reachabilityApi { + return reachabilityApi_; +} + +- (void)setReachabilityApi:(const struct GULReachabilityApi *)reachabilityApi { +#if !TARGET_OS_WATCH + if (reachability_) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode000], + @"Cannot change reachability API while reachability is running. " + @"Call stop first."); + return; + } + reachabilityApi_ = reachabilityApi; +#endif +} + +@synthesize reachabilityStatus = reachabilityStatus_; +@synthesize host = host_; +@synthesize reachabilityDelegate = reachabilityDelegate_; + +- (BOOL)isActive { +#if !TARGET_OS_WATCH + return reachability_ != nil; +#else + return NO; +#endif +} + +- (void)setReachabilityDelegate:(id)reachabilityDelegate { + if (reachabilityDelegate && + (![(NSObject *)reachabilityDelegate conformsToProtocol:@protocol(GULReachabilityDelegate)])) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-NET%06ld", (long)kGULReachabilityMessageCode005], + @"Reachability delegate doesn't conform to Reachability protocol."); + return; + } + reachabilityDelegate_ = reachabilityDelegate; +} + +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host { + self = [super init]; + + if (!host || !host.length) { + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode001], + @"Invalid host specified"); + return nil; + } + if (self) { +#if !TARGET_OS_WATCH + [self setReachabilityDelegate:reachabilityDelegate]; + reachabilityApi_ = &kGULDefaultReachabilityApi; + reachabilityStatus_ = kGULReachabilityUnknown; + host_ = [host copy]; + reachability_ = nil; +#endif + } + return self; +} + +- (void)dealloc { + reachabilityDelegate_ = nil; + [self stop]; +} + +- (BOOL)start { +#if TARGET_OS_WATCH + return NO; +#else + + if (!reachability_) { + reachability_ = reachabilityApi_->createWithNameFn(kCFAllocatorDefault, [host_ UTF8String]); + if (!reachability_) { + return NO; + } + SCNetworkReachabilityContext context = { + 0, /* version */ + (__bridge void *)(self), /* info (passed as last parameter to reachability callback) */ + NULL, /* retain */ + NULL, /* release */ + NULL /* copyDescription */ + }; + if (!reachabilityApi_->setCallbackFn(reachability_, ReachabilityCallback, &context) || + !reachabilityApi_->scheduleWithRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes)) { + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + + GULOSLogError(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode002], + @"Failed to start reachability handle"); + return NO; + } + } + GULOSLogDebug(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode003], + @"Monitoring the network status"); + return YES; +#endif +} + +- (void)stop { +#if !TARGET_OS_WATCH + if (reachability_) { + reachabilityStatus_ = kGULReachabilityUnknown; + reachabilityApi_->unscheduleFromRunLoopFn(reachability_, CFRunLoopGetMain(), + kCFRunLoopCommonModes); + reachabilityApi_->releaseFn(reachability_); + reachability_ = nil; + } +#endif +} + +#if !TARGET_OS_WATCH +- (GULReachabilityStatus)statusForFlags:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = kGULReachabilityNotReachable; + // If the Reachable flag is not set, we definitely don't have connectivity. + if (flags & kSCNetworkReachabilityFlagsReachable) { + // Reachable flag is set. Check further flags. + if (!(flags & kSCNetworkReachabilityFlagsConnectionRequired)) { +// Connection required flag is not set, so we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } else if ((flags & (kSCNetworkReachabilityFlagsConnectionOnDemand | + kSCNetworkReachabilityFlagsConnectionOnTraffic)) && + !(flags & kSCNetworkReachabilityFlagsInterventionRequired)) { +// If the connection on demand or connection on traffic flag is set, and user intervention +// is not required, we have connectivity. +#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_VISION + status = (flags & kSCNetworkReachabilityFlagsIsWWAN) ? kGULReachabilityViaCellular + : kGULReachabilityViaWifi; +#elif TARGET_OS_OSX + status = kGULReachabilityViaWifi; +#endif + } + } + return status; +} + +- (void)reachabilityFlagsChanged:(SCNetworkReachabilityFlags)flags { + GULReachabilityStatus status = [self statusForFlags:flags]; + if (reachabilityStatus_ != status) { + NSString *reachabilityStatusString; + if (status == kGULReachabilityUnknown) { + reachabilityStatusString = kGULReachabilityUnknownStatus; + } else { + reachabilityStatusString = (status == kGULReachabilityNotReachable) + ? kGULReachabilityDisconnectedStatus + : kGULReachabilityConnectedStatus; + } + + GULOSLogDebug(kGULLogSubsystem, kGULLoggerReachability, NO, + [NSString stringWithFormat:@"I-REA%06ld", (long)kGULReachabilityMessageCode004], + @"Network status has changed. Code:%@, status:%@", @(status), + reachabilityStatusString); + reachabilityStatus_ = status; + [reachabilityDelegate_ reachability:self statusChanged:reachabilityStatus_]; + } +} + +#endif +@end + +#if !TARGET_OS_WATCH +static void ReachabilityCallback(SCNetworkReachabilityRef reachability, + SCNetworkReachabilityFlags flags, + void *info) { + GULReachabilityChecker *checker = (__bridge GULReachabilityChecker *)info; + [checker reachabilityFlagsChanged:flags]; +} +#endif + +// This function used to be at the top of the file, but it was moved here +// as a workaround for a suspected compiler bug. When compiled in Release mode +// and run on an iOS device with WiFi disabled, the reachability code crashed +// when calling SCNetworkReachabilityScheduleWithRunLoop, or shortly thereafter. +// After unsuccessfully trying to diagnose the cause of the crash, it was +// discovered that moving this function to the end of the file magically fixed +// the crash. If you are going to edit this file, exercise caution and make sure +// to test thoroughly with an iOS device under various network conditions. +const NSString *GULReachabilityStatusString(GULReachabilityStatus status) { + switch (status) { + case kGULReachabilityUnknown: + return @"Reachability Unknown"; + + case kGULReachabilityNotReachable: + return @"Not reachable"; + + case kGULReachabilityViaWifi: + return @"Reachable via Wifi"; + + case kGULReachabilityViaCellular: + return @"Reachable via Cellular Data"; + + default: + return [NSString stringWithFormat:@"Invalid reachability status %d", (int)status]; + } +} diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h new file mode 100644 index 0000000..373e0af --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/GULReachabilityMessageCode.h @@ -0,0 +1,29 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// Make sure these codes do not overlap with any contained in the FIRAMessageCode enum. +typedef NS_ENUM(NSInteger, GULReachabilityMessageCode) { + // GULReachabilityChecker.m + kGULReachabilityMessageCode000 = 902000, // I-NET902000 + kGULReachabilityMessageCode001 = 902001, // I-NET902001 + kGULReachabilityMessageCode002 = 902002, // I-NET902002 + kGULReachabilityMessageCode003 = 902003, // I-NET902003 + kGULReachabilityMessageCode004 = 902004, // I-NET902004 + kGULReachabilityMessageCode005 = 902005, // I-NET902005 + kGULReachabilityMessageCode006 = 902006, // I-NET902006 +}; diff --git a/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h b/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h new file mode 100644 index 0000000..cac5ca3 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/Reachability/Public/GoogleUtilities/GULReachabilityChecker.h @@ -0,0 +1,83 @@ +/* + * Copyright 2017 Google + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import +#if !TARGET_OS_WATCH +#import +#endif + +NS_ASSUME_NONNULL_BEGIN + +/// Reachability Status +typedef enum { + kGULReachabilityUnknown, ///< Have not yet checked or been notified whether host is reachable. + kGULReachabilityNotReachable, ///< Host is not reachable. + kGULReachabilityViaWifi, ///< Host is reachable via Wifi. + kGULReachabilityViaCellular, ///< Host is reachable via cellular. +} GULReachabilityStatus; + +const NSString *GULReachabilityStatusString(GULReachabilityStatus status); + +@class GULReachabilityChecker; + +/// Google Analytics iOS Reachability Checker. +@protocol GULReachabilityDelegate +@required +/// Called when network status has changed. +- (void)reachability:(GULReachabilityChecker *)reachability + statusChanged:(GULReachabilityStatus)status; +@end + +/// Google Analytics iOS Network Status Checker. +@interface GULReachabilityChecker : NSObject + +/// The last known reachability status, or GULReachabilityStatusUnknown if the +/// checker is not active. +@property(nonatomic, readonly) GULReachabilityStatus reachabilityStatus; +/// The host to which reachability status is to be checked. +@property(nonatomic, copy, readonly) NSString *host; +/// The delegate to be notified of reachability status changes. +@property(nonatomic, weak) id reachabilityDelegate; +/// `YES` if the reachability checker is active, `NO` otherwise. +@property(nonatomic, readonly) BOOL isActive; + +/// Initialize the reachability checker. Note that you must call start to begin checking for and +/// receiving notifications about network status changes. +/// +/// @param reachabilityDelegate The delegate to be notified when reachability status to host +/// changes. +/// +/// @param host The name of the host. +/// +- (instancetype)initWithReachabilityDelegate:(id)reachabilityDelegate + withHost:(NSString *)host; + +- (instancetype)init NS_UNAVAILABLE; + +/// Start checking for reachability to the specified host. This has no effect if the status +/// checker is already checking for connectivity. +/// +/// @return `YES` if initiating status checking was successful or the status checking has already +/// been initiated, `NO` otherwise. +- (BOOL)start; + +/// Stop checking for reachability to the specified host. This has no effect if the status +/// checker is not checking for connectivity. +- (void)stop; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m new file mode 100644 index 0000000..b4ac798 --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/GULUserDefaults.m @@ -0,0 +1,165 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h" + +#import "GoogleUtilities/Logger/Public/GoogleUtilities/GULLogger.h" + +NS_ASSUME_NONNULL_BEGIN + +static NSString *const kGULLogFormat = @"I-GUL%06ld"; + +static GULLoggerService kGULLogUserDefaultsService = @"[GoogleUtilities/UserDefaults]"; + +typedef NS_ENUM(NSInteger, GULUDMessageCode) { + GULUDMessageCodeInvalidKeyGet = 1, + GULUDMessageCodeInvalidKeySet = 2, + GULUDMessageCodeInvalidObjectSet = 3, + GULUDMessageCodeSynchronizeFailed = 4, +}; + +@interface GULUserDefaults () + +@property(nonatomic, readonly) NSUserDefaults *userDefaults; + +@end + +@implementation GULUserDefaults + ++ (GULUserDefaults *)standardUserDefaults { + static GULUserDefaults *standardUserDefaults; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + standardUserDefaults = [[GULUserDefaults alloc] init]; + }); + return standardUserDefaults; +} + +- (instancetype)init { + return [self initWithSuiteName:nil]; +} + +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName { + self = [super init]; + + NSString *name = [suiteName copy]; + + if (self) { + _userDefaults = name.length ? [[NSUserDefaults alloc] initWithSuiteName:name] + : [NSUserDefaults standardUserDefaults]; + } + + return self; +} + +- (nullable id)objectForKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULOSLogWarning(kGULLogSubsystem, @"", NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeyGet], + @"Cannot get object for invalid user default key."); + return nil; + } + + return [self.userDefaults objectForKey:key]; +} + +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName { + NSString *key = [defaultName copy]; + if (![key isKindOfClass:[NSString class]] || !key.length) { + GULOSLogWarning(kGULLogSubsystem, kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidKeySet], + @"Cannot set object for invalid user default key."); + return; + } + if (!value) { + [self.userDefaults removeObjectForKey:key]; + return; + } + BOOL isAcceptableValue = + [value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSNumber class]] || + [value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]] || + [value isKindOfClass:[NSDate class]] || [value isKindOfClass:[NSData class]]; + if (!isAcceptableValue) { + GULOSLogWarning( + kGULLogSubsystem, kGULLogUserDefaultsService, NO, + [NSString stringWithFormat:kGULLogFormat, (long)GULUDMessageCodeInvalidObjectSet], + @"Cannot set invalid object to user defaults. Must be a string, number, array, " + @"dictionary, date, or data. Value: %@", + value); + return; + } + + [self.userDefaults setObject:value forKey:key]; +} + +- (void)removeObjectForKey:(NSString *)key { + [self setObject:nil forKey:key]; +} + +#pragma mark - Getters + +- (NSInteger)integerForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.integerValue; +} + +- (float)floatForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.floatValue; +} + +- (double)doubleForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.doubleValue; +} + +- (BOOL)boolForKey:(NSString *)defaultName { + NSNumber *object = [self objectForKey:defaultName]; + return object.boolValue; +} + +- (nullable NSString *)stringForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSArray *)arrayForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName { + return [self objectForKey:defaultName]; +} + +#pragma mark - Setters + +- (void)setInteger:(NSInteger)integer forKey:(NSString *)defaultName { + [self setObject:@(integer) forKey:defaultName]; +} + +- (void)setFloat:(float)value forKey:(NSString *)defaultName { + [self setObject:@(value) forKey:defaultName]; +} + +- (void)setDouble:(double)doubleNumber forKey:(NSString *)defaultName { + [self setObject:@(doubleNumber) forKey:defaultName]; +} + +- (void)setBool:(BOOL)boolValue forKey:(NSString *)defaultName { + [self setObject:@(boolValue) forKey:defaultName]; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h new file mode 100644 index 0000000..83b23fa --- /dev/null +++ b/Pods/GoogleUtilities/GoogleUtilities/UserDefaults/Public/GoogleUtilities/GULUserDefaults.h @@ -0,0 +1,105 @@ +// Copyright 2018 Google +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +/// A thread-safe user defaults that uses C functions from CFPreferences.h instead of +/// `NSUserDefaults`. This is to avoid sending an `NSNotification` when it's changed from a +/// background thread to avoid crashing. // TODO: Insert radar number here. +@interface GULUserDefaults : NSObject + +/// A shared user defaults similar to +[NSUserDefaults standardUserDefaults] and accesses the same +/// data of the standardUserDefaults. ++ (GULUserDefaults *)standardUserDefaults; + +/// Initializes preferences with a suite name that is the same with the NSUserDefaults' suite name. +/// Both of CFPreferences and NSUserDefaults share the same plist file so their data will exactly +/// the same. +/// +/// @param suiteName The name of the suite of the user defaults. +- (instancetype)initWithSuiteName:(nullable NSString *)suiteName; + +#pragma mark - Getters + +/// Searches the receiver's search list for a default with the key 'defaultName' and return it. If +/// another process has changed defaults in the search list, NSUserDefaults will automatically +/// update to the latest values. If the key in question has been marked as ubiquitous via a Defaults +/// Configuration File, the latest value may not be immediately available, and the registered value +/// will be returned instead. +- (nullable id)objectForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value is not an NSArray. +- (nullable NSArray *)arrayForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will return nil if the value +/// is not an NSDictionary. +- (nullable NSDictionary *)dictionaryForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it will convert NSNumber values to their NSString +/// representation. If a non-string non-number value is found, nil will be returned. +- (nullable NSString *)stringForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to an NSInteger. If the +/// value is an NSNumber, the result of -integerValue will be returned. If the value is an NSString, +/// it will be converted to NSInteger if possible. If the value is a boolean, it will be converted +/// to either 1 for YES or 0 for NO. If the value is absent or can't be converted to an integer, 0 +/// will be returned. +- (NSInteger)integerForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a float, and boolean values will not be +/// converted. +- (float)floatForKey:(NSString *)defaultName; + +/// Similar to -integerForKey:, except that it returns a double, and boolean values will not be +/// converted. +- (double)doubleForKey:(NSString *)defaultName; + +/// Equivalent to -objectForKey:, except that it converts the returned value to a BOOL. If the value +/// is an NSNumber, NO will be returned if the value is 0, YES otherwise. If the value is an +/// NSString, values of "YES" or "1" will return YES, and values of "NO", "0", or any other string +/// will return NO. If the value is absent or can't be converted to a BOOL, NO will be returned. +- (BOOL)boolForKey:(NSString *)defaultName; + +#pragma mark - Setters + +/// Immediately stores a value (or removes the value if `nil` is passed as the value) for the +/// provided key in the search list entry for the receiver's suite name in the current user and any +/// host, then asynchronously stores the value persistently, where it is made available to other +/// processes. +- (void)setObject:(nullable id)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a float to an NSNumber. +- (void)setFloat:(float)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a double to an +/// NSNumber. +- (void)setDouble:(double)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from an NSInteger to an +/// NSNumber. +- (void)setInteger:(NSInteger)value forKey:(NSString *)defaultName; + +/// Equivalent to -setObject:forKey: except that the value is converted from a BOOL to an NSNumber. +- (void)setBool:(BOOL)value forKey:(NSString *)defaultName; + +#pragma mark - Removing Defaults + +/// Equivalent to -[... setObject:nil forKey:defaultName] +- (void)removeObjectForKey:(NSString *)defaultName; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/GoogleUtilities/LICENSE b/Pods/GoogleUtilities/LICENSE new file mode 100644 index 0000000..47e7301 --- /dev/null +++ b/Pods/GoogleUtilities/LICENSE @@ -0,0 +1,224 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +================================================================================ + +Copyright (c) 2017 Landon J. Fuller +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Pods/GoogleUtilities/README.md b/Pods/GoogleUtilities/README.md new file mode 100644 index 0000000..736aaf8 --- /dev/null +++ b/Pods/GoogleUtilities/README.md @@ -0,0 +1,189 @@ +[![Version](https://img.shields.io/cocoapods/v/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![License](https://img.shields.io/cocoapods/l/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) +[![Platform](https://img.shields.io/cocoapods/p/GoogleUtilities.svg?style=flat)](https://cocoapods.org/pods/GoogleUtilities) + +[![Actions Status][gh-google-utilities-badge]][gh-actions] + +# GoogleUtilities + +GoogleUtilities provides a set of utilities for Firebase and other Google SDKs for Apple platform +development. + +The utilities are not directly supported for non-Google library usage. + +## Integration Testing +These instructions apply to minor and patch version updates. Major versions need +a customized adaptation. + +After the CI is green: +* Determine the next version for release by checking the + [tagged releases](https://github.com/google/GoogleUtilities/tags). + Ensure that the next release version keeps the Swift PM and CocoaPods versions in sync. +* Verify that the releasing version is the latest entry in the [CHANGELOG.md](CHANGELOG.md), + updating it if necessary. +* Update the version in the podspec to match the latest entry in the [CHANGELOG.md](CHANGELOG.md) +* Checkout the `main` branch and ensure it is up to date + ```console + git checkout main + git pull + ``` +* Add the CocoaPods tag (`{version}` will be the latest version in the [podspec](GoogleUtilities.podspec#L3)) + ```console + git tag CocoaPods-{version} + git push origin CocoaPods-{version} + ``` +* Push the podspec to the designated repo + * If this version of GoogleUtilities is intended to launch **before or with** the next Firebase release: +
+ Push to SpecsStaging + + ```console + pod repo push --skip-tests --use-json staging GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'staging' repo.`, add the staging repo with: + ```console + pod repo add staging git@github.com:firebase/SpecsStaging.git + ``` +
+ * Otherwise: +
+ Push to SpecsDev + + ```console + pod repo push --skip-tests --use-json dev GoogleUtilities.podspec + ``` + + If the command fails with `Unable to find the 'dev' repo.`, add the dev repo with: + ```console + pod repo add dev git@github.com:firebase/SpecsDev.git + ``` +
+* Run Firebase CI by waiting until next nightly or adding a PR that touches `Gemfile`. +* On google3, run copybara using the command below. Then, start a global TAP on the generated CL. Deflake as needed. + ```console + third_party/firebase/ios/Releases/run_copy_bara.py --directory GoogleUtilities --branch main + ``` + +## Publishing +The release process is as follows: +1. [Tag and release for Swift PM](#swift-package-manager) +2. [Publish to CocoaPods](#cocoapods) +3. [Create GitHub Release](#create-github-release) +4. [Perform post release cleanup](#post-release-cleanup) + +### Swift Package Manager + By creating and [pushing a tag](https://github.com/google/GoogleUtilities/tags) + for Swift PM, the newly tagged version will be immediately released for public use. + Given this, please verify the intended time of release for Swift PM. + * Add a version tag for Swift PM + ```console + git tag {version} + git push origin {version} + ``` + *Note: Ensure that any inflight PRs that depend on the new `GoogleUtilities` version are updated to point to the + newly tagged version rather than a checksum.* + +### CocoaPods +* Publish the newly versioned pod to CocoaPods + + It's recommended to point to the `GoogleUtilities.podspec` in `staging` to make sure the correct spec is being published. + ```console + pod trunk push ~/.cocoapods/repos/staging/GoogleUtilities/{version}/GoogleUtilities.podspec.json + ``` + *Note: In some cases, it may be acceptable to `pod trunk push` with the `--skip-tests` flag. Please double check with + the maintainers before doing so.* + + The pod push was successful if the above command logs: `🚀 GoogleUtilities ({version}) successfully published`. + In addition, a new commit that publishes the new version (co-authored by [CocoaPodsAtGoogle](https://github.com/CocoaPodsAtGoogle)) + should appear in the [CocoaPods specs repo](https://github.com/CocoaPods/Specs). Last, the latest version should be displayed + on [GoogleUtilities's CocoaPods page](https://cocoapods.org/pods/GoogleUtilities). + +### [Create GitHub Release](https://github.com/google/GoogleUtilities/releases/new/) + Update the [release template](https://github.com/google/GoogleUtilities/releases/new/)'s **Tag version** and **Release title** + fields with the latest version. In addition, reference the [Release Notes](./CHANGELOG.md) in the release's description. + + See [this release](https://github.com/google/GoogleUtilities/releases/edit/7.7.0) for an example. + + *Don't forget to perform the [post release cleanup](#post-release-cleanup)!* + +### Post Release Cleanup +
+ Clean up SpecsStaging + + ```console + pwd=$(pwd) + mkdir -p /tmp/release-cleanup && cd $_ + git clone git@github.com:firebase/SpecsStaging.git + cd SpecsStaging/ + git rm -rf GoogleUtilities/ + git commit -m "Post publish cleanup" + git push origin master + rm -rf /tmp/release-cleanup + cd $pwd + ``` +
+ +## Development + +To develop in this repository, ensure that you have at least the following software: + + * Xcode 12.0 (or later) + * CocoaPods 1.10.0 (or later) + * [CocoaPods generate](https://github.com/square/cocoapods-generate) + +For the pod that you want to develop: + +`pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` + +Note: If the CocoaPods cache is out of date, you may need to run +`pod repo update` before the `pod gen` command. + +Note: Set the `--platforms` option to `macos` or `tvos` to develop/test for +those platforms. Since 10.2, Xcode does not properly handle multi-platform +CocoaPods workspaces. + +### Development for Catalyst +* `pod gen GoogleUtilities.podspec --local-sources=./ --auto-open --platforms=ios` +* Check the Mac box in the App-iOS Build Settings +* Sign the App in the Settings Signing & Capabilities tab +* Click Pods in the Project Manager +* Add Signing to the iOS host app and unit test targets +* Select the Unit-unit scheme +* Run it to build and test + +Alternatively disable signing in each target: +* Go to Build Settings tab +* Click `+` +* Select `Add User-Defined Setting` +* Add `CODE_SIGNING_REQUIRED` setting with a value of `NO` + +### Code Formatting + +To ensure that the code is formatted consistently, run the script +[./scripts/check.sh](https://github.com/firebase/firebase-ios-sdk/blob/main/scripts/check.sh) +before creating a PR. + +GitHub Actions will verify that any code changes are done in a style compliant +way. Install `clang-format` and `mint`: + +```console +brew install clang-format@18 +brew install mint +``` + +### Running Unit Tests + +Select a scheme and press Command-u to build a component and run its unit tests. + +## Contributing + +See [Contributing](CONTRIBUTING.md). + +## License + +The contents of this repository is licensed under the +[Apache License, version 2.0](http://www.apache.org/licenses/LICENSE-2.0). + +[gh-actions]: https://github.com/firebase/firebase-ios-sdk/actions +[gh-google-utilities-badge]: https://github.com/firebase/firebase-ios-sdk/workflows/google-utilities/badge.svg diff --git a/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m b/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m new file mode 100644 index 0000000..e2f7275 --- /dev/null +++ b/Pods/GoogleUtilities/third_party/IsAppEncrypted/IsAppEncrypted.m @@ -0,0 +1,104 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// +// Comment from +// iPhone Dev +// Wiki Crack Prevention: +// App Store binaries are signed by both their developer and Apple. This +// encrypts the binary so that decryption keys are needed in order to make the +// binary readable. When iOS executes the binary, the decryption keys are used +// to decrypt the binary into a readable state where it is then loaded into +// memory and executed. iOS can tell the encryption status of a binary via the +// cryptid structure member of LC_ENCRYPTION_INFO MachO load command. If +// cryptid is a non-zero value then the binary is encrypted. +// +// 'Cracking' works by letting the kernel decrypt the binary then siphoning the +// decrypted data into a new binary file, resigning, and repackaging. This will +// only work on jailbroken devices as codesignature validation has been +// removed. Resigning takes place because while the codesignature doesn't have +// to be valid thanks to the jailbreak, it does have to be in place unless you +// have AppSync or similar to disable codesignature checks. +// +// More information at +// Landon Fuller's blog + +#import "third_party/IsAppEncrypted/Public/IsAppEncrypted.h" + +#import +#import + +/// The encryption info struct and constants are missing from the iPhoneSimulator SDK, but not from +/// the iPhoneOS or Mac OS X SDKs. Since one doesn't ever ship a Simulator binary, we'll just +/// provide the definitions here. +#if TARGET_OS_SIMULATOR && !defined(LC_ENCRYPTION_INFO) +#define LC_ENCRYPTION_INFO 0x21 +struct encryption_info_command { + uint32_t cmd; + uint32_t cmdsize; + uint32_t cryptoff; + uint32_t cryptsize; + uint32_t cryptid; +}; +#endif + +BOOL IsAppEncrypted(void) { + const struct mach_header *executableHeader = NULL; + for (uint32_t i = 0; i < _dyld_image_count(); i++) { + const struct mach_header *header = _dyld_get_image_header(i); + if (header && header->filetype == MH_EXECUTE) { + executableHeader = header; + break; + } + } + + if (!executableHeader) { + return NO; + } + + BOOL is64bit = (executableHeader->magic == MH_MAGIC_64); + uintptr_t cursor = (uintptr_t)executableHeader + + (is64bit ? sizeof(struct mach_header_64) : sizeof(struct mach_header)); + const struct segment_command *segmentCommand = NULL; + uint32_t i = 0; + + while (i++ < executableHeader->ncmds) { + segmentCommand = (struct segment_command *)cursor; + + if (!segmentCommand) { + continue; + } + + if ((!is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO) || + (is64bit && segmentCommand->cmd == LC_ENCRYPTION_INFO_64)) { + if (is64bit) { + struct encryption_info_command_64 *cryptCmd = + (struct encryption_info_command_64 *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } else { + struct encryption_info_command *cryptCmd = (struct encryption_info_command *)segmentCommand; + return cryptCmd && cryptCmd->cryptid != 0; + } + } + cursor += segmentCommand->cmdsize; + } + + return NO; +} diff --git a/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h b/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h new file mode 100644 index 0000000..1a4305a --- /dev/null +++ b/Pods/GoogleUtilities/third_party/IsAppEncrypted/Public/IsAppEncrypted.h @@ -0,0 +1,24 @@ +// Copyright (c) 2017 Landon J. Fuller +// All rights reserved. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. + +#import + +BOOL IsAppEncrypted(void); diff --git a/Pods/Headers/Private/Firebase/Firebase.h b/Pods/Headers/Private/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/Pods/Headers/Private/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/Pods/Headers/Public/Firebase/Firebase.h b/Pods/Headers/Public/Firebase/Firebase.h new file mode 120000 index 0000000..07ac6eb --- /dev/null +++ b/Pods/Headers/Public/Firebase/Firebase.h @@ -0,0 +1 @@ +../../../Firebase/CoreOnly/Sources/Firebase.h \ No newline at end of file diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/Firebase.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/Firebase.xcscheme new file mode 100644 index 0000000..8b3c425 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/Firebase.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting-FirebaseABTesting_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting-FirebaseABTesting_Privacy.xcscheme new file mode 100644 index 0000000..78755fa --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting-FirebaseABTesting_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting.xcscheme new file mode 100644 index 0000000..12e2081 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseABTesting.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme new file mode 100644 index 0000000..4ef6a07 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseAnalytics.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme new file mode 100644 index 0000000..15f9320 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore-FirebaseCore_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore.xcscheme new file mode 100644 index 0000000..a36829f --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCore.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension-FirebaseCoreExtension_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension-FirebaseCoreExtension_Privacy.xcscheme new file mode 100644 index 0000000..d311914 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension-FirebaseCoreExtension_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension.xcscheme new file mode 100644 index 0000000..0741e8c --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreExtension.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme new file mode 100644 index 0000000..cf35a72 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal-FirebaseCoreInternal_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme new file mode 100644 index 0000000..3f22e05 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCoreInternal.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics-FirebaseCrashlytics_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics-FirebaseCrashlytics_Privacy.xcscheme new file mode 100644 index 0000000..eb7f2f4 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics-FirebaseCrashlytics_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics.xcscheme new file mode 100644 index 0000000..2bab6f5 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseCrashlytics.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme new file mode 100644 index 0000000..abb8f0c --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations-FirebaseInstallations_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme new file mode 100644 index 0000000..81cf4f5 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseInstallations.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebasePerformance.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebasePerformance.xcscheme new file mode 100644 index 0000000..de6be50 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebasePerformance.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig-FirebaseRemoteConfig_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig-FirebaseRemoteConfig_Privacy.xcscheme new file mode 100644 index 0000000..82bb77d --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig-FirebaseRemoteConfig_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig.xcscheme new file mode 100644 index 0000000..8ba2d5f --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfig.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfigInterop.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfigInterop.xcscheme new file mode 100644 index 0000000..e1b41a8 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseRemoteConfigInterop.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSessions.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSessions.xcscheme new file mode 100644 index 0000000..cac1f1b --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSessions.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSharedSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSharedSwift.xcscheme new file mode 100644 index 0000000..c6adb45 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/FirebaseSharedSwift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme new file mode 100644 index 0000000..cf7db98 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleAppMeasurement.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme new file mode 100644 index 0000000..e63b44b --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport-GoogleDataTransport_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme new file mode 100644 index 0000000..117e970 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleDataTransport.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme new file mode 100644 index 0000000..e61fe15 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities-GoogleUtilities_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities.xcscheme new file mode 100644 index 0000000..4909ee5 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/GoogleUtilities.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme new file mode 100644 index 0000000..0d034a4 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC-FBLPromises_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC.xcscheme new file mode 100644 index 0000000..91d9b1a --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesObjC.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift-Promises_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift-Promises_Privacy.xcscheme new file mode 100644 index 0000000..b26ca49 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift-Promises_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift.xcscheme new file mode 100644 index 0000000..bf21c40 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/PromisesSwift.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme new file mode 100644 index 0000000..373f771 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb-nanopb_Privacy.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb.xcscheme b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb.xcscheme new file mode 100644 index 0000000..6de6831 --- /dev/null +++ b/Pods/Pods.xcodeproj/xcuserdata/oscar.xcuserdatad/xcschemes/nanopb.xcscheme @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Pods/PromisesObjC/LICENSE b/Pods/PromisesObjC/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/PromisesObjC/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/PromisesObjC/README.md b/Pods/PromisesObjC/README.md new file mode 100644 index 0000000..e0e65b7 --- /dev/null +++ b/Pods/PromisesObjC/README.md @@ -0,0 +1,60 @@ +[![Apache +License](https://img.shields.io/github/license/google/promises.svg)](LICENSE) +[![Travis](https://api.travis-ci.org/google/promises.svg?branch=master)](https://travis-ci.org/google/promises) +[![Gitter Chat](https://badges.gitter.im/google/promises.svg)](https://gitter.im/google/promises) + +![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg?longCache=true&style=flat) +![Languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg?longCache=true&style=flat) +![Package Managers](https://img.shields.io/badge/supports-Bazel%20%7C%20SwiftPM%20%7C%20CocoaPods%20%7C%20Carthage-yellow.svg?longCache=true&style=flat) + +# Promises + +Promises is a modern framework that provides a synchronization construct for +Objective-C and Swift to facilitate writing asynchronous code. + +* [Introduction](g3doc/index.md) + * [The problem with async + code](g3doc/index.md#the-problem-with-async-code) + * [Promises to the rescue](g3doc/index.md#promises-to-the-rescue) + * [What is a promise?](g3doc/index.md#what-is-a-promise) +* [Framework](g3doc/index.md#framework) + * [Features](g3doc/index.md#features) + * [Benchmark](g3doc/index.md#benchmark) +* [Getting started](g3doc/index.md#getting-started) + * [Add dependency](g3doc/index.md#add-dependency) + * [Import](g3doc/index.md#import) + * [Adopt](g3doc/index.md#adopt) +* [Basics](g3doc/index.md#basics) + * [Creating promises](g3doc/index.md#creating-promises) + * [Async](g3doc/index.md#async) + * [Do](g3doc/index.md#do) + * [Pending](g3doc/index.md#pending) + * [Resolved](g3doc/index.md#create-a-resolved-promise) + * [Observing fulfillment](g3doc/index.md#observing-fulfillment) + * [Then](g3doc/index.md#then) + * [Observing rejection](g3doc/index.md#observing-rejection) + * [Catch](g3doc/index.md#catch) +* [Extensions](g3doc/index.md#extensions) + * [All](g3doc/index.md#all) + * [Always](g3doc/index.md#always) + * [Any](g3doc/index.md#any) + * [AwaitPromise](g3doc/index.md#awaitpromise) + * [Delay](g3doc/index.md#delay) + * [Race](g3doc/index.md#race) + * [Recover](g3doc/index.md#recover) + * [Reduce](g3doc/index.md#reduce) + * [Retry](g3doc/index.md#retry) + * [Timeout](g3doc/index.md#timeout) + * [Validate](g3doc/index.md#validate) + * [Wrap](g3doc/index.md#wrap) +* [Advanced topics](g3doc/index.md#advanced-topics) + * [Default dispatch queue](g3doc/index.md#default-dispatch-queue) + * [Ownership and retain + cycles](g3doc/index.md#ownership-and-retain-cycles) + * [Testing](g3doc/index.md#testing) + * [Objective-C <-> Swift + interoperability](g3doc/index.md#objective-c---swift-interoperability) + * [Dot-syntax in Objective-C](g3doc/index.md#dot-syntax-in-objective-c) +* [Anti-patterns](g3doc/index.md#anti-patterns) + * [Broken chain](g3doc/index.md#broken-chain) + * [Nested promises](g3doc/index.md#nested-promises) diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m new file mode 100644 index 0000000..a9c7feb --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+All.m @@ -0,0 +1,89 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AllAdditions) + ++ (FBLPromise *)all:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue all:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue all:(NSArray *)allPromises { + NSParameterAssert(queue); + NSParameterAssert(allPromises); + + if (allPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [allPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else if ([promise isKindOfClass:[NSError class]]) { + reject(promise); + return; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are fulfilled. + for (FBLPromise *promise in promises) { + if (!promise.isFulfilled) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill([promises valueForKey:NSStringFromSelector(@selector(value))]); + } + reject:^(NSError *error) { + reject(error); + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all { + return ^(NSArray *promises) { + return [self all:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue all:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAllCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m new file mode 100644 index 0000000..c4e9776 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Always.m @@ -0,0 +1,61 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Always.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AlwaysAdditions) + +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue always:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue always:(FBLPromiseAlwaysWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue + chainedFulfill:^id(id value) { + work(); + return value; + } + chainedReject:^id(NSError *error) { + work(); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AlwaysAdditions) + +- (FBLPromise * (^)(FBLPromiseAlwaysWorkBlock))always { + return ^(FBLPromiseAlwaysWorkBlock work) { + return [self always:work]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn { + return ^(dispatch_queue_t queue, FBLPromiseAlwaysWorkBlock work) { + return [self onQueue:queue always:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAlwaysCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m new file mode 100644 index 0000000..8454c34 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Any.m @@ -0,0 +1,115 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Any.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +static NSArray *FBLPromiseCombineValuesAndErrors(NSArray *promises) { + NSMutableArray *combinedValuesAndErrors = [[NSMutableArray alloc] init]; + for (FBLPromise *promise in promises) { + if (promise.isFulfilled) { + [combinedValuesAndErrors addObject:promise.value ?: [NSNull null]]; + continue; + } + if (promise.isRejected) { + [combinedValuesAndErrors addObject:promise.error]; + continue; + } + assert(!promise.isPending); + }; + return combinedValuesAndErrors; +} + +@implementation FBLPromise (AnyAdditions) + ++ (FBLPromise *)any:(NSArray *)promises { + return [self onQueue:FBLPromise.defaultDispatchQueue any:promises]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue any:(NSArray *)anyPromises { + NSParameterAssert(queue); + NSParameterAssert(anyPromises); + + if (anyPromises.count == 0) { + return [[self alloc] initWithResolution:@[]]; + } + NSMutableArray *promises = [anyPromises mutableCopy]; + return [self + onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (NSUInteger i = 0; i < promises.count; ++i) { + id promise = promises[i]; + if ([promise isKindOfClass:self]) { + continue; + } else { + [promises replaceObjectAtIndex:i + withObject:[[self alloc] initWithResolution:promise]]; + } + } + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue + fulfill:^(id __unused _) { + // Wait until all are resolved. + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + } + // If called multiple times, only the first one affects the result. + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } + reject:^(NSError *error) { + BOOL atLeastOneIsFulfilled = NO; + for (FBLPromise *promise in promises) { + if (promise.isPending) { + return; + } + if (promise.isFulfilled) { + atLeastOneIsFulfilled = YES; + } + } + if (atLeastOneIsFulfilled) { + fulfill(FBLPromiseCombineValuesAndErrors(promises)); + } else { + reject(error); + } + }]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any { + return ^(NSArray *promises) { + return [self any:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue any:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAnyCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m new file mode 100644 index 0000000..c0a89d3 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Async.m @@ -0,0 +1,73 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Async.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (AsyncAdditions) + ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue async:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue async:(FBLPromiseAsyncWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + work( + ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }, + ^(NSError *error) { + [promise reject:error]; + }); + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async { + return ^(FBLPromiseAsyncWorkBlock work) { + return [self async:work]; + }; +} + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn { + return ^(dispatch_queue_t queue, FBLPromiseAsyncWorkBlock work) { + return [self onQueue:queue async:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAsyncCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m new file mode 100644 index 0000000..0f86b2f --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Await.m @@ -0,0 +1,51 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Await.h" + +#import "FBLPromisePrivate.h" + +id __nullable FBLPromiseAwait(FBLPromise *promise, NSError **outError) { + assert(promise); + + static dispatch_once_t onceToken; + static dispatch_queue_t queue; + dispatch_once(&onceToken, ^{ + queue = dispatch_queue_create("com.google.FBLPromises.Await", DISPATCH_QUEUE_CONCURRENT); + }); + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + id __block resolution; + NSError __block *blockError; + [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + resolution = value; + dispatch_semaphore_signal(semaphore); + return value; + } + chainedReject:^id(NSError *error) { + blockError = error; + dispatch_semaphore_signal(semaphore); + return error; + }]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (outError) { + *outError = blockError; + } + return resolution; +} + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeAwaitCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m new file mode 100644 index 0000000..fff7690 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Catch.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Catch.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (CatchAdditions) + +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject { + return [self onQueue:FBLPromise.defaultDispatchQueue catch:reject]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue catch:(FBLPromiseCatchWorkBlock)reject { + NSParameterAssert(queue); + NSParameterAssert(reject); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + reject(error); + return error; + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch { + return ^(FBLPromiseCatchWorkBlock catch) { + return [self catch:catch]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn { + return ^(dispatch_queue_t queue, FBLPromiseCatchWorkBlock catch) { + return [self onQueue:queue catch:catch]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeCatchCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m new file mode 100644 index 0000000..5aeeb1f --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Delay.m @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Delay.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DelayAdditions) + +- (FBLPromise *)delay:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue delay:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue delay:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + [promise fulfill:value]; + }); + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay { + return ^(NSTimeInterval interval) { + return [self delay:interval]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue delay:interval]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeDelayCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m new file mode 100644 index 0000000..9ae6033 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Do.m @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Do.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (DoAdditions) + ++ (instancetype)do:(FBLPromiseDoWorkBlock)work { + return [self onQueue:self.defaultDispatchQueue do:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_DoAdditions) + ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn { + return ^(dispatch_queue_t queue, FBLPromiseDoWorkBlock work) { + return [self onQueue:queue do:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeDoCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m new file mode 100644 index 0000000..1672ac4 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Race.m @@ -0,0 +1,68 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Race.h" + +#import "FBLPromise+Async.h" +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RaceAdditions) + ++ (instancetype)race:(NSArray *)promises { + return [self onQueue:self.defaultDispatchQueue race:promises]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)racePromises { + NSParameterAssert(queue); + NSAssert(racePromises.count > 0, @"No promises to observe"); + + NSArray *promises = [racePromises copy]; + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + for (id promise in promises) { + if (![promise isKindOfClass:self]) { + fulfill(promise); + return; + } + } + // Subscribe all, but only the first one to resolve will change + // the resulting promise's state. + for (FBLPromise *promise in promises) { + [promise observeOnQueue:queue fulfill:fulfill reject:reject]; + } + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race { + return ^(NSArray *promises) { + return [self race:promises]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn { + return ^(dispatch_queue_t queue, NSArray *promises) { + return [self onQueue:queue race:promises]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRaceCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m new file mode 100644 index 0000000..50e337a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Recover.m @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Recover.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (RecoverAdditions) + +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery { + return [self onQueue:FBLPromise.defaultDispatchQueue recover:recovery]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue recover:(FBLPromiseRecoverWorkBlock)recovery { + NSParameterAssert(queue); + NSParameterAssert(recovery); + + return [self chainOnQueue:queue + chainedFulfill:nil + chainedReject:^id(NSError *error) { + return recovery(error); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover { + return ^(FBLPromiseRecoverWorkBlock recovery) { + return [self recover:recovery]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn { + return ^(dispatch_queue_t queue, FBLPromiseRecoverWorkBlock recovery) { + return [self onQueue:queue recover:recovery]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRecoverCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m new file mode 100644 index 0000000..f98cf69 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Reduce.m @@ -0,0 +1,64 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Reduce.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ReduceAdditions) + +- (FBLPromise *)reduce:(NSArray *)items combine:(FBLPromiseReducerBlock)reducer { + return [self onQueue:FBLPromise.defaultDispatchQueue reduce:items combine:reducer]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer { + NSParameterAssert(queue); + NSParameterAssert(items); + NSParameterAssert(reducer); + + FBLPromise *promise = self; + for (id item in items) { + promise = [promise chainOnQueue:queue + chainedFulfill:^id(id value) { + return reducer(value, item); + } + chainedReject:nil]; + } + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce { + return ^(NSArray *items, FBLPromiseReducerBlock reducer) { + return [self reduce:items combine:reducer]; + }; +} + +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn { + return ^(dispatch_queue_t queue, NSArray *items, FBLPromiseReducerBlock reducer) { + return [self onQueue:queue reduce:items combine:reducer]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeReduceCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m new file mode 100644 index 0000000..841be68 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Retry.m @@ -0,0 +1,131 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Retry.h" + +#import "FBLPromisePrivate.h" + +NSInteger const FBLPromiseRetryDefaultAttemptsCount = 1; +NSTimeInterval const FBLPromiseRetryDefaultDelayInterval = 1.0; + +static void FBLPromiseRetryAttempt(FBLPromise *promise, dispatch_queue_t queue, NSInteger count, + NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + __auto_type retrier = ^(id __nullable value) { + if ([value isKindOfClass:[NSError class]]) { + if (count <= 0 || (predicate && !predicate(count, value))) { + [promise reject:value]; + } else { + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + FBLPromiseRetryAttempt(promise, queue, count - 1, interval, predicate, work); + }); + } + } else { + [promise fulfill:value]; + } + }; + id value = work(); + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue fulfill:retrier reject:retrier]; + } else { + retrier(value); + } +} + +@implementation FBLPromise (RetryAdditions) + ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue attempts:FBLPromiseRetryDefaultAttemptsCount retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue attempts:count retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:queue + attempts:count + delay:FBLPromiseRetryDefaultDelayInterval + condition:nil + retry:work]; +} + ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue + attempts:count + delay:interval + condition:predicate + retry:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + FBLPromise *promise = [[self alloc] initPending]; + FBLPromiseRetryAttempt(promise, queue, count, interval, predicate, work); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry { + return ^id(FBLPromiseRetryWorkBlock work) { + return [self retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn { + return ^id(dispatch_queue_t queue, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue retry:work]; + }; +} + ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgain { + return ^id(NSInteger count, NSTimeInterval interval, FBLPromiseRetryPredicateBlock predicate, + FBLPromiseRetryWorkBlock work) { + return [self attempts:count delay:interval condition:predicate retry:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock, + FBLPromiseRetryWorkBlock))retryAgainOn { + return ^id(dispatch_queue_t queue, NSInteger count, NSTimeInterval interval, + FBLPromiseRetryPredicateBlock predicate, FBLPromiseRetryWorkBlock work) { + return [self onQueue:queue attempts:count delay:interval condition:predicate retry:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeRetryCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m new file mode 100644 index 0000000..7d6b461 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Testing.m @@ -0,0 +1,58 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) { + BOOL isTimedOut = NO; + NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:timeout]; + static NSTimeInterval const minimalTimeout = 0.01; + static int64_t const minimalTimeToWait = (int64_t)(minimalTimeout * NSEC_PER_SEC); + dispatch_time_t waitTime = dispatch_time(DISPATCH_TIME_NOW, minimalTimeToWait); + dispatch_group_t dispatchGroup = FBLPromise.dispatchGroup; + NSRunLoop *runLoop = NSRunLoop.currentRunLoop; + while (dispatch_group_wait(dispatchGroup, waitTime)) { + isTimedOut = timeoutDate.timeIntervalSinceNow < 0.0; + if (isTimedOut) { + break; + } + [runLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:minimalTimeout]]; + } + return !isTimedOut; +} + +@implementation FBLPromise (TestingAdditions) + +// These properties are implemented in the FBLPromise class itself. +@dynamic isPending; +@dynamic isFulfilled; +@dynamic isRejected; +@dynamic value; +@dynamic error; + ++ (dispatch_group_t)dispatchGroup { + static dispatch_group_t gDispatchGroup; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + gDispatchGroup = dispatch_group_create(); + }); + return gDispatchGroup; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeTestingCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m new file mode 100644 index 0000000..32df102 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Then.m @@ -0,0 +1,53 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Then.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ThenAdditions) + +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work { + return [self onQueue:FBLPromise.defaultDispatchQueue then:work]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue then:(FBLPromiseThenWorkBlock)work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self chainOnQueue:queue chainedFulfill:work chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then { + return ^(FBLPromiseThenWorkBlock work) { + return [self then:work]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn { + return ^(dispatch_queue_t queue, FBLPromiseThenWorkBlock work) { + return [self onQueue:queue then:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeThenCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m new file mode 100644 index 0000000..91da9ff --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Timeout.m @@ -0,0 +1,67 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Timeout.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (TimeoutAdditions) + +- (FBLPromise *)timeout:(NSTimeInterval)interval { + return [self onQueue:FBLPromise.defaultDispatchQueue timeout:interval]; +} + +- (FBLPromise *)onQueue:(dispatch_queue_t)queue timeout:(NSTimeInterval)interval { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + FBLPromise* __weak weakPromise = promise; + dispatch_after(dispatch_time(0, (int64_t)(interval * NSEC_PER_SEC)), queue, ^{ + NSError *timedOutError = [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeTimedOut + userInfo:nil]; + [weakPromise reject:timedOutError]; + }); + return promise; +} + +@end + +@implementation FBLPromise (DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout { + return ^(NSTimeInterval interval) { + return [self timeout:interval]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn { + return ^(dispatch_queue_t queue, NSTimeInterval interval) { + return [self onQueue:queue timeout:interval]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeTimeoutCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m new file mode 100644 index 0000000..3520e24 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Validate.m @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Validate.h" + +#import "FBLPromisePrivate.h" + +@implementation FBLPromise (ValidateAdditions) + +- (FBLPromise*)validate:(FBLPromiseValidateWorkBlock)predicate { + return [self onQueue:FBLPromise.defaultDispatchQueue validate:predicate]; +} + +- (FBLPromise*)onQueue:(dispatch_queue_t)queue validate:(FBLPromiseValidateWorkBlock)predicate { + NSParameterAssert(queue); + NSParameterAssert(predicate); + + FBLPromiseChainedFulfillBlock chainedFulfill = ^id(id value) { + return predicate(value) ? value : + [[NSError alloc] initWithDomain:FBLPromiseErrorDomain + code:FBLPromiseErrorCodeValidationFailure + userInfo:nil]; + }; + return [self chainOnQueue:queue chainedFulfill:chainedFulfill chainedReject:nil]; +} + +@end + +@implementation FBLPromise (DotSyntax_ValidateAdditions) + +- (FBLPromise* (^)(FBLPromiseValidateWorkBlock))validate { + return ^(FBLPromiseValidateWorkBlock predicate) { + return [self validate:predicate]; + }; +} + +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn { + return ^(dispatch_queue_t queue, FBLPromiseValidateWorkBlock predicate) { + return [self onQueue:queue validate:predicate]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeValidateCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m new file mode 100644 index 0000000..840bc16 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise+Wrap.m @@ -0,0 +1,423 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Wrap.h" + +#import "FBLPromise+Async.h" + +@implementation FBLPromise (WrapAdditions) + ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^{ + fulfill(nil); + }); + }]; +} + ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(id __nullable value) { + fulfill(value); + }); + }]; +} + ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(nil); + } + }); + }]; +} + ++ (instancetype)wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapObjectOrErrorCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (instancetype)wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapErrorOrObjectCompletion:work]; +} + ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSError *__nullable error, id __nullable value) { + if (error) { + reject(error); + } else { + fulfill(value); + } + }); + }]; +} + ++ (FBLPromise *)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrap2ObjectsOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(id __nullable value1, id __nullable value2, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@[ value1 ?: [NSNull null], value2 ?: [NSNull null] ]); + } + }); + }]; +} + ++ (FBLPromise *)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(BOOL value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapBoolOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(BOOL value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(NSInteger value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapIntegerOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(NSInteger value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + ++ (FBLPromise *)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:(dispatch_queue_t)queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock __unused _) { + work(^(double value) { + fulfill(@(value)); + }); + }]; +} + ++ (FBLPromise *)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion))work { + return [self onQueue:self.defaultDispatchQueue wrapDoubleOrErrorCompletion:work]; +} + ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion))work { + NSParameterAssert(queue); + NSParameterAssert(work); + + return [self onQueue:queue + async:^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { + work(^(double value, NSError *__nullable error) { + if (error) { + reject(error); + } else { + fulfill(@(value)); + } + }); + }]; +} + +@end + +@implementation FBLPromise (DotSyntax_WrapAdditions) + ++ (FBLPromise * (^)(void (^)(FBLPromiseCompletion)))wrapCompletion { + return ^(void (^work)(FBLPromiseCompletion)) { + return [self wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseCompletion)) { + return [self onQueue:queue wrapCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion { + return ^(void (^work)(FBLPromiseObjectCompletion)) { + return [self wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectCompletion)) { + return [self onQueue:queue wrapObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion { + return ^(void (^work)(FBLPromiseErrorCompletion)) { + return [self wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorCompletion)) { + return [self onQueue:queue wrapErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion { + return ^(void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseObjectOrErrorCompletion)) { + return [self onQueue:queue wrapObjectOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion { + return ^(void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseErrorOrObjectCompletion)) { + return [self onQueue:queue wrapErrorOrObjectCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion { + return ^(void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromise2ObjectsOrErrorCompletion)) { + return [self onQueue:queue wrap2ObjectsOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion { + return ^(void (^work)(FBLPromiseBoolCompletion)) { + return [self wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolCompletion)) { + return [self onQueue:queue wrapBoolCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletion { + return ^(void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseBoolOrErrorCompletion))) + wrapBoolOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseBoolOrErrorCompletion)) { + return [self onQueue:queue wrapBoolOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion { + return ^(void (^work)(FBLPromiseIntegerCompletion)) { + return [self wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerCompletion)) { + return [self onQueue:queue wrapIntegerCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion { + return ^(void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseIntegerOrErrorCompletion)) { + return [self onQueue:queue wrapIntegerOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion { + return ^(void (^work)(FBLPromiseDoubleCompletion)) { + return [self wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleCompletion)) { + return [self onQueue:queue wrapDoubleCompletion:work]; + }; +} + ++ (FBLPromise * (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion { + return ^(void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self wrapDoubleOrErrorCompletion:work]; + }; +} + ++ (FBLPromise * (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn { + return ^(dispatch_queue_t queue, void (^work)(FBLPromiseDoubleOrErrorCompletion)) { + return [self onQueue:queue wrapDoubleOrErrorCompletion:work]; + }; +} + +@end + +/** Stub used to force the linker to include the categories in this file. */ +void FBLIncludeWrapCategory(void) {} diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m new file mode 100644 index 0000000..9a61ed2 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromise.m @@ -0,0 +1,346 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromisePrivate.h" + +/** All states a promise can be in. */ +typedef NS_ENUM(NSInteger, FBLPromiseState) { + FBLPromiseStatePending = 0, + FBLPromiseStateFulfilled, + FBLPromiseStateRejected, +}; + +typedef void (^FBLPromiseObserver)(FBLPromiseState state, id __nullable resolution); + +static dispatch_queue_t gFBLPromiseDefaultDispatchQueue; + +@implementation FBLPromise { + /** Current state of the promise. */ + FBLPromiseState _state; + /** + Set of arbitrary objects to keep strongly while the promise is pending. + Becomes nil after the promise has been resolved. + */ + NSMutableSet *__nullable _pendingObjects; + /** + Value to fulfill the promise with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ + id __nullable _value; + /** + Error to reject the promise with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ + NSError *__nullable _error; + /** List of observers to notify when the promise gets resolved. */ + NSMutableArray *_observers; +} + ++ (void)initialize { + if (self == [FBLPromise class]) { + gFBLPromiseDefaultDispatchQueue = dispatch_get_main_queue(); + } +} + ++ (dispatch_queue_t)defaultDispatchQueue { + @synchronized(self) { + return gFBLPromiseDefaultDispatchQueue; + } +} + ++ (void)setDefaultDispatchQueue:(dispatch_queue_t)queue { + NSParameterAssert(queue); + + @synchronized(self) { + gFBLPromiseDefaultDispatchQueue = queue; + } +} + ++ (instancetype)pendingPromise { + return [[self alloc] initPending]; +} + ++ (instancetype)resolvedWith:(nullable id)resolution { + return [[self alloc] initWithResolution:resolution]; +} + +- (void)fulfill:(nullable id)value { + if ([value isKindOfClass:[NSError class]]) { + [self reject:(NSError *)value]; + } else { + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateFulfilled; + _value = value; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _value); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } + } +} + +- (void)reject:(NSError *)error { + NSAssert([error isKindOfClass:[NSError class]], @"Invalid error type."); + + if (![error isKindOfClass:[NSError class]]) { + // Give up on invalid error type in Release mode. + @throw error; // NOLINT + } + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + _state = FBLPromiseStateRejected; + _error = error; + _pendingObjects = nil; + for (FBLPromiseObserver observer in _observers) { + observer(_state, _error); + } + _observers = nil; + dispatch_group_leave(FBLPromise.dispatchGroup); + } + } +} + +#pragma mark - NSObject + +- (NSString *)description { + if (self.isFulfilled) { + return [NSString stringWithFormat:@"<%@ %p> Fulfilled: %@", NSStringFromClass([self class]), + self, self.value]; + } + if (self.isRejected) { + return [NSString stringWithFormat:@"<%@ %p> Rejected: %@", NSStringFromClass([self class]), + self, self.error]; + } + return [NSString stringWithFormat:@"<%@ %p> Pending", NSStringFromClass([self class]), self]; +} + +#pragma mark - Private + +- (instancetype)initPending { + self = [super init]; + if (self) { + dispatch_group_enter(FBLPromise.dispatchGroup); + } + return self; +} + +- (instancetype)initWithResolution:(nullable id)resolution { + self = [super init]; + if (self) { + if ([resolution isKindOfClass:[NSError class]]) { + _state = FBLPromiseStateRejected; + _error = (NSError *)resolution; + } else { + _state = FBLPromiseStateFulfilled; + _value = resolution; + } + } + return self; +} + +- (void)dealloc { + if (_state == FBLPromiseStatePending) { + dispatch_group_leave(FBLPromise.dispatchGroup); + } +} + +- (BOOL)isPending { + @synchronized(self) { + return _state == FBLPromiseStatePending; + } +} + +- (BOOL)isFulfilled { + @synchronized(self) { + return _state == FBLPromiseStateFulfilled; + } +} + +- (BOOL)isRejected { + @synchronized(self) { + return _state == FBLPromiseStateRejected; + } +} + +- (nullable id)value { + @synchronized(self) { + return _value; + } +} + +- (NSError *__nullable)error { + @synchronized(self) { + return _error; + } +} + +- (void)addPendingObject:(id)object { + NSParameterAssert(object); + + @synchronized(self) { + if (_state == FBLPromiseStatePending) { + if (!_pendingObjects) { + _pendingObjects = [[NSMutableSet alloc] init]; + } + [_pendingObjects addObject:object]; + } + } +} + +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject { + NSParameterAssert(queue); + NSParameterAssert(onFulfill); + NSParameterAssert(onReject); + + @synchronized(self) { + switch (_state) { + case FBLPromiseStatePending: { + if (!_observers) { + _observers = [[NSMutableArray alloc] init]; + } + [_observers addObject:^(FBLPromiseState state, id __nullable resolution) { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + switch (state) { + case FBLPromiseStatePending: + break; + case FBLPromiseStateFulfilled: + onFulfill(resolution); + break; + case FBLPromiseStateRejected: + onReject(resolution); + break; + } + }); + }]; + break; + } + case FBLPromiseStateFulfilled: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onFulfill(self->_value); + }); + break; + } + case FBLPromiseStateRejected: { + dispatch_group_async(FBLPromise.dispatchGroup, queue, ^{ + onReject(self->_error); + }); + break; + } + } + } +} + +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject { + NSParameterAssert(queue); + + FBLPromise *promise = [[[self class] alloc] initPending]; + __auto_type resolver = ^(id __nullable value) { + if ([value isKindOfClass:[FBLPromise class]]) { + [(FBLPromise *)value observeOnQueue:queue + fulfill:^(id __nullable value) { + [promise fulfill:value]; + } + reject:^(NSError *error) { + [promise reject:error]; + }]; + } else { + [promise fulfill:value]; + } + }; + [self observeOnQueue:queue + fulfill:^(id __nullable value) { + value = chainedFulfill ? chainedFulfill(value) : value; + resolver(value); + } + reject:^(NSError *error) { + id value = chainedReject ? chainedReject(error) : error; + resolver(value); + }]; + return promise; +} + +#pragma mark - Category linking workaround + +extern void FBLIncludeAllCategory(void); +extern void FBLIncludeAlwaysCategory(void); +extern void FBLIncludeAnyCategory(void); +extern void FBLIncludeAsyncCategory(void); +extern void FBLIncludeAwaitCategory(void); +extern void FBLIncludeCatchCategory(void); +extern void FBLIncludeDelayCategory(void); +extern void FBLIncludeDoCategory(void); +extern void FBLIncludeRaceCategory(void); +extern void FBLIncludeRecoverCategory(void); +extern void FBLIncludeReduceCategory(void); +extern void FBLIncludeRetryCategory(void); +extern void FBLIncludeTestingCategory(void); +extern void FBLIncludeThenCategory(void); +extern void FBLIncludeTimeoutCategory(void); +extern void FBLIncludeValidateCategory(void); +extern void FBLIncludeWrapCategory(void); + +/** + Does nothing when called, and not meant to be called. + + This method forces the linker to include all FBLPromise categories even if + users do not include the '-ObjC' linker flag in their projects. + */ ++ (void)noop { + FBLIncludeAllCategory(); + FBLIncludeAllCategory(); + FBLIncludeAlwaysCategory(); + FBLIncludeAnyCategory(); + FBLIncludeAsyncCategory(); + FBLIncludeAwaitCategory(); + FBLIncludeCatchCategory(); + FBLIncludeDelayCategory(); + FBLIncludeDoCategory(); + FBLIncludeRaceCategory(); + FBLIncludeRecoverCategory(); + FBLIncludeReduceCategory(); + FBLIncludeRetryCategory(); + FBLIncludeTestingCategory(); + FBLIncludeThenCategory(); + FBLIncludeTimeoutCategory(); + FBLIncludeValidateCategory(); + FBLIncludeWrapCategory(); +} + +@end + +@implementation FBLPromise (DotSyntaxAdditions) + ++ (FBLPromise * (^)(void))pending { + return ^(void) { + return [self pendingPromise]; + }; +} + ++ (FBLPromise * (^)(id __nullable))resolved { + return ^(id resolution) { + return [self resolvedWith:resolution]; + }; +} + +@end diff --git a/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m new file mode 100644 index 0000000..1cc181a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/FBLPromiseError.m @@ -0,0 +1,19 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NSErrorDomain const FBLPromiseErrorDomain = @"com.google.FBLPromises.Error"; diff --git a/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy b/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..5397adc --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h new file mode 100644 index 0000000..9c0090e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+All.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AllAdditions) + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)all:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until all of the given promises are fulfilled. + If one of the given promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected FBLPromise correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of an array containing the values of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + all:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `all` operators. + Usage: FBLPromise.all(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AllAdditions) + ++ (FBLPromise * (^)(NSArray *))all FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))allOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h new file mode 100644 index 0000000..13000f5 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Always.h @@ -0,0 +1,54 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AlwaysAdditions) + +typedef void (^FBLPromiseAlwaysWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)always:(FBLPromiseAlwaysWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to dispatch on. + @param work A block that always executes, no matter if the receiver is rejected or fulfilled. + @return A new pending promise to be resolved with same resolution as the receiver. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + always:(FBLPromiseAlwaysWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `always` operators. + Usage: promise.always(^{...}) + */ +@interface FBLPromise(DotSyntax_AlwaysAdditions) + +- (FBLPromise* (^)(FBLPromiseAlwaysWorkBlock))always FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAlwaysWorkBlock))alwaysOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h new file mode 100644 index 0000000..82875bf --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Any.h @@ -0,0 +1,69 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AnyAdditions) + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSErrors`, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)any:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Waits until all of the given promises are either fulfilled or rejected. + If all promises are rejected, then the returned promise is rejected with same error + as the last one rejected. + If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array of + values or `NSError`s, matching the original order of fulfilled or rejected promises respectively. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + Promises resolved with `nil` become `NSNull` instances in the resulting array. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return Promise of array containing the values or `NSError`s of input promises in the same order. + */ ++ (FBLPromise *)onQueue:(dispatch_queue_t)queue + any:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `any` operators. + Usage: FBLPromise.any(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_AnyAdditions) + ++ (FBLPromise * (^)(NSArray *))any FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))anyOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h new file mode 100644 index 0000000..0588a9e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Async.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(AsyncAdditions) + +typedef void (^FBLPromiseFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseAsyncWorkBlock)(FBLPromiseFulfillBlock fulfill, + FBLPromiseRejectBlock reject) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)async:(FBLPromiseAsyncWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + async:(FBLPromiseAsyncWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `async` operators. + Usage: FBLPromise.async(^(FBLPromiseFulfillBlock fulfill, FBLPromiseRejectBlock reject) { ... }) + */ +@interface FBLPromise(DotSyntax_AsyncAdditions) + ++ (FBLPromise* (^)(FBLPromiseAsyncWorkBlock))async FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, FBLPromiseAsyncWorkBlock))asyncOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h new file mode 100644 index 0000000..c97a1ba --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Await.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for promise resolution. The current thread blocks until the promise is resolved. + + @param promise Promise to wait for. + @param error Error the promise was rejected with, or `nil` if the promise was fulfilled. + @return Value the promise was fulfilled with. If the promise was rejected, the return value + is always `nil`, but the error out arg is not. + */ +FOUNDATION_EXTERN id __nullable FBLPromiseAwait(FBLPromise *promise, + NSError **error) NS_REFINED_FOR_SWIFT; + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h new file mode 100644 index 0000000..a9ff170 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Catch.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(CatchAdditions) + +typedef void (^FBLPromiseCatchWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously. + + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)catch:(FBLPromiseCatchWorkBlock)reject NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with same resolution as the receiver. + If receiver is rejected, then `reject` block is executed asynchronously on the given queue. + + @param queue A queue to invoke the `reject` block on. + @param reject A block to handle the error that receiver was rejected with. + @return A new pending promise. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + catch:(FBLPromiseCatchWorkBlock)reject NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `catch` operators. + Usage: promise.catch(^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_CatchAdditions) + +- (FBLPromise* (^)(FBLPromiseCatchWorkBlock))catch FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseCatchWorkBlock))catchOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h new file mode 100644 index 0000000..557df48 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Delay.h @@ -0,0 +1,59 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DelayAdditions) + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)delay:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a new pending promise that fulfills with the same value as `self` after the `delay`, or + rejects with the same error immediately. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that fulfills at least `delay` seconds later than `self`, or rejects + with the same error immediately. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + delay:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `delay` operators. + Usage: promise.delay(...) + */ +@interface FBLPromise(DotSyntax_DelayAdditions) + +- (FBLPromise * (^)(NSTimeInterval))delay FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSTimeInterval))delayOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h new file mode 100644 index 0000000..6838e0a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Do.h @@ -0,0 +1,55 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(DoAdditions) + +typedef id __nullable (^FBLPromiseDoWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously. + + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)do:(FBLPromiseDoWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise and executes `work` block asynchronously on the given queue. + + @param queue A queue to invoke the `work` block on. + @param work A block that returns a value or an error used to resolve the promise. + @return A new pending promise. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue do:(FBLPromiseDoWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `do` operators. + Usage: FBLPromise.doOn(queue, ^(NSError *error) { ... }) + */ +@interface FBLPromise(DotSyntax_DoAdditions) + ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseDoWorkBlock))doOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h new file mode 100644 index 0000000..2f67258 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Race.h @@ -0,0 +1,62 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RaceAdditions) + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)race:(NSArray *)promises NS_SWIFT_UNAVAILABLE(""); + +/** + Wait until any of the given promises are fulfilled. + If one of the promises is rejected, then the returned promise is rejected with same error. + If any other arbitrary value or `NSError` appears in the array instead of `FBLPromise`, + it's implicitly considered a pre-fulfilled or pre-rejected `FBLPromise` correspondingly. + + @param queue A queue to dispatch on. + @param promises Promises to wait for. + @return A new pending promise to be resolved with the same resolution as the first promise, among + the given ones, which was resolved. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue race:(NSArray *)promises NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `race` operators. + Usage: FBLPromise.race(@[ ... ]) + */ +@interface FBLPromise(DotSyntax_RaceAdditions) + ++ (FBLPromise * (^)(NSArray *))race FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSArray *))raceOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h new file mode 100644 index 0000000..bb7df7e --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Recover.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(RecoverAdditions) + +typedef id __nullable (^FBLPromiseRecoverWorkBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)recover:(FBLPromiseRecoverWorkBlock)recovery NS_SWIFT_UNAVAILABLE(""); + +/** + Provides a new promise to recover in case the receiver gets rejected. + + @param queue A queue to dispatch on. + @param recovery A block to handle the error that the receiver was rejected with. + @return A new pending promise to use instead of the rejected one that gets resolved with resolution + returned from `recovery` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + recover:(FBLPromiseRecoverWorkBlock)recovery NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `recover` operators. + Usage: promise.recover(^id(NSError *error) {...}) + */ +@interface FBLPromise(DotSyntax_RecoverAdditions) + +- (FBLPromise * (^)(FBLPromiseRecoverWorkBlock))recover FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRecoverWorkBlock))recoverOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h new file mode 100644 index 0000000..5bb1eee --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Reduce.h @@ -0,0 +1,71 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ReduceAdditions) + +typedef id __nullable (^FBLPromiseReducerBlock)(Value __nullable partial, id next) + NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +/** + Sequentially reduces a collection of values to a single promise using a given combining block + and the value `self` resolves with as initial value. + + @param queue A queue to dispatch on. + @param items An array of values to process in order. + @param reducer A block to combine an accumulating value and an element of the sequence into + the new accumulating value or a promise resolved with it, to be used in the next + call of the `reducer` or returned to the caller. + @return A new pending promise returned from the last `reducer` invocation. + Or `self` if `items` is empty. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + reduce:(NSArray *)items + combine:(FBLPromiseReducerBlock)reducer NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `reduce` operators. + Usage: promise.reduce(values, ^id(id partial, id next) { ... }) + */ +@interface FBLPromise(DotSyntax_ReduceAdditions) + +- (FBLPromise * (^)(NSArray *, FBLPromiseReducerBlock))reduce FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, NSArray *, FBLPromiseReducerBlock))reduceOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h new file mode 100644 index 0000000..414a17a --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Retry.h @@ -0,0 +1,165 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** The default number of retry attempts is 1. */ +FOUNDATION_EXTERN NSInteger const FBLPromiseRetryDefaultAttemptsCount NS_REFINED_FOR_SWIFT; + +/** The default delay interval before making a retry attempt is 1.0 second. */ +FOUNDATION_EXTERN NSTimeInterval const FBLPromiseRetryDefaultDelayInterval NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(RetryAdditions) + +typedef id __nullable (^FBLPromiseRetryWorkBlock)(void) NS_SWIFT_UNAVAILABLE(""); +typedef BOOL (^FBLPromiseRetryPredicateBlock)(NSInteger, NSError *) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on rejection where the + `work` block is retried after a delay of `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. Defaults to `FBLPromiseRetryDefaultAttemptsCount` attempt(s) on + rejection where the `work` block is retried on the given `queue` after a delay of + `FBLPromiseRetryDefaultDelayInterval` second(s). + + @param queue A queue to invoke the `work` block on. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously, or rejects with the same error after all retry attempts have + been exhausted. On rejection, the `work` block is retried after the given delay `interval` and will + continue to retry until the number of specified attempts have been exhausted or will bail early if + the given condition is not met. + + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the default queue and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise that fulfills with the same value as the promise returned from `work` + block, which executes asynchronously on the given `queue`, or rejects with the same error after all + retry attempts have been exhausted. On rejection, the `work` block is retried after the given + delay `interval` and will continue to retry until the number of specified attempts have been + exhausted or will bail early if the given condition is not met. + + @param queue A queue to invoke the `work` block on. + @param count Max number of retry attempts. The `work` block will be executed once if the specified + count is less than or equal to zero. + @param interval Time to wait before the next retry attempt. + @param predicate Condition to check before the next retry attempt. The predicate block provides the + the number of remaining retry attempts and the error that the promise was rejected + with. + @param work A block that executes asynchronously on the given `queue` and returns a value or an + error used to resolve the promise. + @return A new pending promise that fulfills with the same value as the promise returned from `work` + block, or rejects with the same error after all retry attempts have been exhausted or if + the given condition is not met. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + attempts:(NSInteger)count + delay:(NSTimeInterval)interval + condition:(nullable FBLPromiseRetryPredicateBlock)predicate + retry:(FBLPromiseRetryWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise+Retry` operators. + Usage: FBLPromise.retry(^id { ... }) + */ +@interface FBLPromise(DotSyntax_RetryAdditions) + ++ (FBLPromise * (^)(FBLPromiseRetryWorkBlock))retry FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, FBLPromiseRetryWorkBlock))retryOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(NSInteger, NSTimeInterval, FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgain FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(dispatch_queue_t, NSInteger, NSTimeInterval, + FBLPromiseRetryPredicateBlock __nullable, + FBLPromiseRetryWorkBlock))retryAgainOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h new file mode 100644 index 0000000..8478ae2 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Testing.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Waits for all scheduled promises blocks. + + @param timeout Maximum time to wait. + @return YES if all promises blocks have completed before the timeout and NO otherwise. + */ +FOUNDATION_EXTERN BOOL FBLWaitForPromisesWithTimeout(NSTimeInterval timeout) NS_REFINED_FOR_SWIFT; + +@interface FBLPromise(TestingAdditions) + +/** + Dispatch group for promises that is typically used to wait for all scheduled blocks. + */ +@property(class, nonatomic, readonly) dispatch_group_t dispatchGroup NS_REFINED_FOR_SWIFT; + +/** + Properties to get the current state of the promise. + */ +@property(nonatomic, readonly) BOOL isPending NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isFulfilled NS_REFINED_FOR_SWIFT; +@property(nonatomic, readonly) BOOL isRejected NS_REFINED_FOR_SWIFT; + +/** + Value the promise was fulfilled with. + Can be nil if the promise is still pending, was resolved with nil or after it has been rejected. + */ +@property(nonatomic, readonly, nullable) Value value NS_REFINED_FOR_SWIFT; + +/** + Error the promise was rejected with. + Can be nil if the promise is still pending or after it has been fulfilled. + */ +@property(nonatomic, readonly, nullable) NSError *error NS_REFINED_FOR_SWIFT; + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h new file mode 100644 index 0000000..32027e6 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Then.h @@ -0,0 +1,63 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ThenAdditions) + +typedef id __nullable (^FBLPromiseThenWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously only + when the receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with + the same error. + + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)then:(FBLPromiseThenWorkBlock)work NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise which eventually gets resolved with resolution returned from `work` + block: either value, error or another promise. The `work` block is executed asynchronously when the + receiver is fulfilled. If receiver is rejected, the returned promise is also rejected with the same + error. + + @param queue A queue to invoke the `work` block on. + @param work A block to handle the value that receiver was fulfilled with. + @return A new pending promise to be resolved with resolution returned from the `work` block. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + then:(FBLPromiseThenWorkBlock)work NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `then` operators. + Usage: promise.then(^id(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ThenAdditions) + +- (FBLPromise* (^)(FBLPromiseThenWorkBlock))then FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, FBLPromiseThenWorkBlock))thenOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h new file mode 100644 index 0000000..184ba16 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Timeout.h @@ -0,0 +1,57 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(TimeoutAdditions) + +/** + Waits for a promise with the specified `timeout`. + + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)timeout:(NSTimeInterval)interval NS_SWIFT_UNAVAILABLE(""); + +/** + Waits for a promise with the specified `timeout`. + + @param queue A queue to dispatch on. + @param interval Time to wait in seconds. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeTimedOut` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + timeout:(NSTimeInterval)interval NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `timeout` operators. + Usage: promise.timeout(...) + */ +@interface FBLPromise(DotSyntax_TimeoutAdditions) + +- (FBLPromise* (^)(NSTimeInterval))timeout FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise* (^)(dispatch_queue_t, NSTimeInterval))timeoutOn FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h new file mode 100644 index 0000000..9dfa2f1 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Validate.h @@ -0,0 +1,60 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface FBLPromise(ValidateAdditions) + +typedef BOOL (^FBLPromiseValidateWorkBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)validate:(FBLPromiseValidateWorkBlock)predicate NS_SWIFT_UNAVAILABLE(""); + +/** + Validates a fulfilled value or rejects the value if it can not be validated. + + @param queue A queue to dispatch on. + @param predicate An expression to validate. + @return A new pending promise that gets either resolved with same resolution as the receiver or + rejected with `FBLPromiseErrorCodeValidationFailure` error code in `FBLPromiseErrorDomain`. + */ +- (FBLPromise *)onQueue:(dispatch_queue_t)queue + validate:(FBLPromiseValidateWorkBlock)predicate NS_REFINED_FOR_SWIFT; + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `validate` operators. + Usage: promise.validate(^BOOL(id value) { ... }) + */ +@interface FBLPromise(DotSyntax_ValidateAdditions) + +- (FBLPromise * (^)(FBLPromiseValidateWorkBlock))validate FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); +- (FBLPromise * (^)(dispatch_queue_t, FBLPromiseValidateWorkBlock))validateOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h new file mode 100644 index 0000000..664e1bb --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise+Wrap.h @@ -0,0 +1,316 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Different types of completion handlers available to be wrapped with promise. + */ +typedef void (^FBLPromiseCompletion)(void) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectCompletion)(id __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorCompletion)(NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseObjectOrErrorCompletion)(id __nullable, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseErrorOrObjectCompletion)(NSError* __nullable, id __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromise2ObjectsOrErrorCompletion)(id __nullable, id __nullable, + NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolCompletion)(BOOL) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseBoolOrErrorCompletion)(BOOL, NSError* __nullable) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerCompletion)(NSInteger) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseIntegerOrErrorCompletion)(NSInteger, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleCompletion)(double) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseDoubleOrErrorCompletion)(double, NSError* __nullable) + NS_SWIFT_UNAVAILABLE(""); + +/** + Provides an easy way to convert methods that use common callback patterns into promises. + */ +@interface FBLPromise(WrapAdditions) + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)wrapCompletion:(void (^)(FBLPromiseCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with `nil` when completion handler is invoked. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapCompletion:(void (^)(FBLPromiseCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectCompletion:(void (^)(FBLPromiseObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error provided by completion handler. + If error is `nil`, fulfills with `nil`, otherwise rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorCompletion:(void (^)(FBLPromiseErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)wrapObjectOrErrorCompletion: + (void (^)(FBLPromiseObjectOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an object provided by completion handler if error is `nil`. + Otherwise, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapObjectOrErrorCompletion:(void (^)(FBLPromiseObjectOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)wrapErrorOrObjectCompletion: + (void (^)(FBLPromiseErrorOrObjectCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an error or object provided by completion handler. If error + is not `nil`, rejects with the error. + */ ++ (instancetype)onQueue:(dispatch_queue_t)queue + wrapErrorOrObjectCompletion:(void (^)(FBLPromiseErrorOrObjectCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)wrap2ObjectsOrErrorCompletion: + (void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an array of objects provided by completion handler in order + if error is `nil`. Otherwise, rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrap2ObjectsOrErrorCompletion:(void (^)(FBLPromise2ObjectsOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolCompletion:(void (^)(FBLPromiseBoolCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapBoolOrErrorCompletion: + (void (^)(FBLPromiseBoolOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping YES/NO when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapBoolOrErrorCompletion:(void (^)(FBLPromiseBoolOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerCompletion:(void (^)(FBLPromiseIntegerCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapIntegerOrErrorCompletion: + (void (^)(FBLPromiseIntegerOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping an integer when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapIntegerOrErrorCompletion:(void (^)(FBLPromiseIntegerOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleCompletion:(void (^)(FBLPromiseDoubleCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +/** + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)wrapDoubleOrErrorCompletion: + (void (^)(FBLPromiseDoubleOrErrorCompletion handler))work NS_SWIFT_UNAVAILABLE(""); + +/** + @param queue A queue to invoke the `work` block on. + @param work A block to perform any operations needed to resolve the promise. + @returns A promise that resolves with an `NSNumber` wrapping a double when error is `nil`. + Otherwise rejects with the error. + */ ++ (FBLPromise*)onQueue:(dispatch_queue_t)queue + wrapDoubleOrErrorCompletion:(void (^)(FBLPromiseDoubleOrErrorCompletion handler))work + NS_SWIFT_UNAVAILABLE(""); + +@end + +/** + Convenience dot-syntax wrappers for `FBLPromise` `wrap` operators. + Usage: FBLPromise.wrapCompletion(^(FBLPromiseCompletion handler) {...}) + */ +@interface FBLPromise(DotSyntax_WrapAdditions) + ++ (FBLPromise* (^)(void (^)(FBLPromiseCompletion)))wrapCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseCompletion)))wrapCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseObjectCompletion)))wrapObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletion FBL_PROMISES_DOT_SYNTAX + NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseErrorCompletion)))wrapErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseObjectOrErrorCompletion)))wrapObjectOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseErrorOrObjectCompletion)))wrapErrorOrObjectCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromise2ObjectsOrErrorCompletion))) + wrap2ObjectsOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolCompletion)))wrapBoolCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseBoolOrErrorCompletion)))wrapBoolOrErrorCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseIntegerCompletion)))wrapIntegerCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseIntegerOrErrorCompletion))) + wrapIntegerOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletion + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, + void (^)(FBLPromiseDoubleCompletion)))wrapDoubleCompletionOn + FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletion FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise* (^)(dispatch_queue_t, void (^)(FBLPromiseDoubleOrErrorCompletion))) + wrapDoubleOrErrorCompletionOn FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h new file mode 100644 index 0000000..98c813b --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromise.h @@ -0,0 +1,93 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromiseError.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Promises synchronization construct in Objective-C. + */ +@interface FBLPromise<__covariant Value> : NSObject + +/** + Default dispatch queue used for `FBLPromise`, which is `main` if a queue is not specified. + */ +@property(class) dispatch_queue_t defaultDispatchQueue NS_REFINED_FOR_SWIFT; + +/** + Creates a pending promise. + */ ++ (instancetype)pendingPromise NS_REFINED_FOR_SWIFT; + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ ++ (instancetype)resolvedWith:(nullable id)resolution NS_REFINED_FOR_SWIFT; + +/** + Synchronously fulfills the promise with a value. + + @param value An arbitrary value to fulfill the promise with, including `nil`. + */ +- (void)fulfill:(nullable Value)value NS_REFINED_FOR_SWIFT; + +/** + Synchronously rejects the promise with an error. + + @param error An error to reject the promise with. + */ +- (void)reject:(NSError *)error NS_REFINED_FOR_SWIFT; + ++ (instancetype)new NS_UNAVAILABLE; +- (instancetype)init NS_UNAVAILABLE; +@end + +@interface FBLPromise() + +/** + Adds an object to the set of pending objects to keep strongly while the promise is pending. + Used by the Swift wrappers to keep them alive until the underlying ObjC promise is resolved. + + @param object An object to add. + */ +- (void)addPendingObject:(id)object NS_REFINED_FOR_SWIFT; + +@end + +#ifdef FBL_PROMISES_DOT_SYNTAX_IS_DEPRECATED +#define FBL_PROMISES_DOT_SYNTAX __attribute__((deprecated)) +#else +#define FBL_PROMISES_DOT_SYNTAX +#endif + +@interface FBLPromise(DotSyntaxAdditions) + +/** + Convenience dot-syntax wrappers for FBLPromise. + Usage: FBLPromise.pending() + FBLPromise.resolved(value) + + */ ++ (FBLPromise * (^)(void))pending FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); ++ (FBLPromise * (^)(id __nullable))resolved FBL_PROMISES_DOT_SYNTAX NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h new file mode 100644 index 0000000..d37af53 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromiseError.h @@ -0,0 +1,43 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +FOUNDATION_EXTERN NSErrorDomain const FBLPromiseErrorDomain NS_REFINED_FOR_SWIFT; + +/** + Possible error codes in `FBLPromiseErrorDomain`. + */ +typedef NS_ENUM(NSInteger, FBLPromiseErrorCode) { + /** Promise failed to resolve in time. */ + FBLPromiseErrorCodeTimedOut = 1, + /** Validation predicate returned false. */ + FBLPromiseErrorCodeValidationFailure = 2, +} NS_REFINED_FOR_SWIFT; + +NS_INLINE BOOL FBLPromiseErrorIsTimedOut(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeTimedOut; +} + +NS_INLINE BOOL FBLPromiseErrorIsValidationFailure(NSError *error) NS_SWIFT_UNAVAILABLE("") { + return error.domain == FBLPromiseErrorDomain && + error.code == FBLPromiseErrorCodeValidationFailure; +} + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h new file mode 100644 index 0000000..7a132f2 --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromisePrivate.h @@ -0,0 +1,66 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+Testing.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + Miscellaneous low-level private interfaces available to extend standard FBLPromise functionality. + */ +@interface FBLPromise() + +typedef void (^FBLPromiseOnFulfillBlock)(Value __nullable value) NS_SWIFT_UNAVAILABLE(""); +typedef void (^FBLPromiseOnRejectBlock)(NSError *error) NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedFulfillBlock)(Value __nullable value) + NS_SWIFT_UNAVAILABLE(""); +typedef id __nullable (^__nullable FBLPromiseChainedRejectBlock)(NSError *error) + NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a pending promise. + */ +- (instancetype)initPending NS_SWIFT_UNAVAILABLE(""); + +/** + Creates a resolved promise. + + @param resolution An object to resolve the promise with: either a value or an error. + @return A new resolved promise. + */ +- (instancetype)initWithResolution:(nullable id)resolution NS_SWIFT_UNAVAILABLE(""); + +/** + Invokes `fulfill` and `reject` blocks on `queue` when the receiver gets either fulfilled or + rejected respectively. + */ +- (void)observeOnQueue:(dispatch_queue_t)queue + fulfill:(FBLPromiseOnFulfillBlock)onFulfill + reject:(FBLPromiseOnRejectBlock)onReject NS_SWIFT_UNAVAILABLE(""); + +/** + Returns a new promise which gets resolved with the return value of `chainedFulfill` or + `chainedReject` blocks respectively. The blocks are invoked when the receiver gets either + fulfilled or rejected. If `nil` is passed to either block arg, the returned promise is resolved + with the same resolution as the receiver. + */ +- (FBLPromise *)chainOnQueue:(dispatch_queue_t)queue + chainedFulfill:(FBLPromiseChainedFulfillBlock)chainedFulfill + chainedReject:(FBLPromiseChainedRejectBlock)chainedReject NS_SWIFT_UNAVAILABLE(""); + +@end + +NS_ASSUME_NONNULL_END diff --git a/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h new file mode 100644 index 0000000..2d90bad --- /dev/null +++ b/Pods/PromisesObjC/Sources/FBLPromises/include/FBLPromises.h @@ -0,0 +1,32 @@ +/** + Copyright 2018 Google Inc. All rights reserved. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at: + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" diff --git a/Pods/PromisesSwift/LICENSE b/Pods/PromisesSwift/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Pods/PromisesSwift/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Pods/PromisesSwift/README.md b/Pods/PromisesSwift/README.md new file mode 100644 index 0000000..e0e65b7 --- /dev/null +++ b/Pods/PromisesSwift/README.md @@ -0,0 +1,60 @@ +[![Apache +License](https://img.shields.io/github/license/google/promises.svg)](LICENSE) +[![Travis](https://api.travis-ci.org/google/promises.svg?branch=master)](https://travis-ci.org/google/promises) +[![Gitter Chat](https://badges.gitter.im/google/promises.svg)](https://gitter.im/google/promises) + +![Platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20iOS%20%7C%20tvOS%20%7C%20watchOS-blue.svg?longCache=true&style=flat) +![Languages](https://img.shields.io/badge/languages-Swift%20%7C%20ObjC-orange.svg?longCache=true&style=flat) +![Package Managers](https://img.shields.io/badge/supports-Bazel%20%7C%20SwiftPM%20%7C%20CocoaPods%20%7C%20Carthage-yellow.svg?longCache=true&style=flat) + +# Promises + +Promises is a modern framework that provides a synchronization construct for +Objective-C and Swift to facilitate writing asynchronous code. + +* [Introduction](g3doc/index.md) + * [The problem with async + code](g3doc/index.md#the-problem-with-async-code) + * [Promises to the rescue](g3doc/index.md#promises-to-the-rescue) + * [What is a promise?](g3doc/index.md#what-is-a-promise) +* [Framework](g3doc/index.md#framework) + * [Features](g3doc/index.md#features) + * [Benchmark](g3doc/index.md#benchmark) +* [Getting started](g3doc/index.md#getting-started) + * [Add dependency](g3doc/index.md#add-dependency) + * [Import](g3doc/index.md#import) + * [Adopt](g3doc/index.md#adopt) +* [Basics](g3doc/index.md#basics) + * [Creating promises](g3doc/index.md#creating-promises) + * [Async](g3doc/index.md#async) + * [Do](g3doc/index.md#do) + * [Pending](g3doc/index.md#pending) + * [Resolved](g3doc/index.md#create-a-resolved-promise) + * [Observing fulfillment](g3doc/index.md#observing-fulfillment) + * [Then](g3doc/index.md#then) + * [Observing rejection](g3doc/index.md#observing-rejection) + * [Catch](g3doc/index.md#catch) +* [Extensions](g3doc/index.md#extensions) + * [All](g3doc/index.md#all) + * [Always](g3doc/index.md#always) + * [Any](g3doc/index.md#any) + * [AwaitPromise](g3doc/index.md#awaitpromise) + * [Delay](g3doc/index.md#delay) + * [Race](g3doc/index.md#race) + * [Recover](g3doc/index.md#recover) + * [Reduce](g3doc/index.md#reduce) + * [Retry](g3doc/index.md#retry) + * [Timeout](g3doc/index.md#timeout) + * [Validate](g3doc/index.md#validate) + * [Wrap](g3doc/index.md#wrap) +* [Advanced topics](g3doc/index.md#advanced-topics) + * [Default dispatch queue](g3doc/index.md#default-dispatch-queue) + * [Ownership and retain + cycles](g3doc/index.md#ownership-and-retain-cycles) + * [Testing](g3doc/index.md#testing) + * [Objective-C <-> Swift + interoperability](g3doc/index.md#objective-c---swift-interoperability) + * [Dot-syntax in Objective-C](g3doc/index.md#dot-syntax-in-objective-c) +* [Anti-patterns](g3doc/index.md#anti-patterns) + * [Broken chain](g3doc/index.md#broken-chain) + * [Nested promises](g3doc/index.md#nested-promises) diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+All.swift b/Pods/PromisesSwift/Sources/Promises/Promise+All.swift new file mode 100644 index 0000000..e775382 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+All.swift @@ -0,0 +1,182 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Dispatch + +/// Waits until all of the promises have been fulfilled. +/// If one of the promises is rejected, then the returned promise is rejected with the same error. +/// If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: Promise of an array containing the values of input promises in the same order. +public func all( + on queue: DispatchQueue = .promises, + _ promises: Promise... +) -> Promise<[Value]> { + return all(on: queue, promises) +} + +/// Waits until all of the promises have been fulfilled. +/// If one of the promises is rejected, then the returned promise is rejected with same error. +/// If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: Promise of an array containing the values of input promises in the same order. +public func all( + on queue: DispatchQueue = .promises, + _ promises: Container +) -> Promise<[Value]> where Container.Element == Promise { + let promises = promises.map { $0.objCPromise } + let promise = Promise<[Value]>( + Promise<[Value]>.ObjCPromise.__onQueue(queue, all: promises) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Waits until all of the promises have been fulfilled. +/// If one of the promises is rejected, then the returned promise is rejected with same error. +/// If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promiseA: Promise of type `A`. +/// - promiseB: Promise of type `B`. +/// - returns: Promise of a tuple containing the values of input promises in the same order. +public func all( + on queue: DispatchQueue = .promises, + _ promiseA: Promise, + _ promiseB: Promise +) -> Promise<(A, B)> { + let promises = [ + promiseA.objCPromise, + promiseB.objCPromise + ] + let promise = Promise<(A, B)>( + Promise<(A, B)>.ObjCPromise.__onQueue( + queue, + all: promises + ).__onQueue(queue, then: { objCValues in + guard let values = objCValues as [AnyObject]?, + let valueA = Promise.asValue(values[0]), + let valueB = Promise.asValue(values[1]) + else { + preconditionFailure("Cannot convert \(type(of: objCValues)) to \((A, B).self)") + } + return (valueA, valueB) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Waits until all of the promises have been fulfilled. +/// If one of the promises is rejected, then the returned promise is rejected with same error. +/// If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promiseA: Promise of type `A`. +/// - promiseB: Promise of type `B`. +/// - promiseC: Promise of type `C`. +/// - returns: Promise of a tuple containing the values of input promises in the same order. +public func all( + on queue: DispatchQueue = .promises, + _ promiseA: Promise, + _ promiseB: Promise, + _ promiseC: Promise +) -> Promise<(A, B, C)> { + let promises = [ + promiseA.objCPromise, + promiseB.objCPromise, + promiseC.objCPromise + ] + let promise = Promise<(A, B, C)>( + Promise<(A, B, C)>.ObjCPromise.__onQueue( + queue, + all: promises + ).__onQueue(queue, then: { objCValues in + guard let values = objCValues as [AnyObject]?, + let valueA = Promise.asValue(values[0]), + let valueB = Promise.asValue(values[1]), + let valueC = Promise.asValue(values[2]) + else { + preconditionFailure("Cannot convert \(type(of: objCValues)) to \((A, B, C).self)") + } + return (valueA, valueB, valueC) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Waits until all of the promises have been fulfilled. +/// If one of the promises is rejected, then the returned promise is rejected with same error. +/// If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promiseA: Promise of type `A`. +/// - promiseB: Promise of type `B`. +/// - promiseC: Promise of type `C`. +/// - promiseD: Promise of type `D`. +/// - returns: Promise of a tuple containing the values of input promises in the same order. +public func all( + on queue: DispatchQueue = .promises, + _ promiseA: Promise, + _ promiseB: Promise, + _ promiseC: Promise, + _ promiseD: Promise +) -> Promise<(A, B, C, D)> { + let promises = [ + promiseA.objCPromise, + promiseB.objCPromise, + promiseC.objCPromise, + promiseD.objCPromise + ] + let promise = Promise<(A, B, C, D)>( + Promise<(A, B, C, D)>.ObjCPromise.__onQueue( + queue, + all: promises + ).__onQueue(queue, then: { objCValues in + guard let values = objCValues as [AnyObject]?, + let valueA = Promise.asValue(values[0]), + let valueB = Promise.asValue(values[1]), + let valueC = Promise.asValue(values[2]), + let valueD = Promise.asValue(values[3]) + else { + preconditionFailure("Cannot convert \(type(of: objCValues)) to \((A, B, C, D).self)") + } + return (valueA, valueB, valueC, valueD) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Always.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Always.swift new file mode 100644 index 0000000..abaa1bd --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Always.swift @@ -0,0 +1,31 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Dispatch + +public extension Promise { + + /// Provides a way to always execute a given chained block. + /// - parameters: + /// - queue: A queue to dispatch on. + /// - work: A block that always executes, no matter if `self` is rejected or fulfilled. + /// - returns: A new pending promise to be resolved with same resolution as `self`. + @discardableResult + func always(on queue: DispatchQueue = .promises, _ work: @escaping () -> Void) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, always: work)) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Any.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Any.swift new file mode 100644 index 0000000..d3ee69c --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Any.swift @@ -0,0 +1,276 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +/// Waits for all of the given promises to be fulfilled or rejected. +/// If all promises are rejected, then the returned promise is rejected with same error +/// as the last one rejected. +/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array +/// of `Maybe` enums containing values or `Error`s, matching the original order of fulfilled or +/// rejected promises respectively. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: Promise of an array of `Maybe` enums containing the values or `Error`s of input +/// promises in their original order. +public func any( + on queue: DispatchQueue = .promises, + _ promises: Promise... +) -> Promise<[Maybe]> { + return any(on: queue, promises) +} + +/// Waits for all of the given promises to be fulfilled or rejected. +/// If all promises are rejected, then the returned promise is rejected with same error +/// as the last one rejected. +/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with an array +/// of `Maybe` enums containing values or `Error`s, matching the original order of fulfilled or +/// rejected promises respectively. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: Promise of an array of `Maybe` enums containing the values or `Error`s of input +/// promises in their original order. +public func any( + on queue: DispatchQueue = .promises, + _ promises: Container +) -> Promise<[Maybe]> where Container.Element == Promise { + let promises = promises.map { $0.objCPromise } + let promise = Promise<[Maybe]>( + Promise<[Maybe]>.ObjCPromise.__onQueue( + queue, + any: promises + ).__onQueue(queue, then: { values in + guard let values = values as [AnyObject]? else { preconditionFailure() } + return Promise<[Maybe]>.asAnyObject(values.map { asMaybe($0) as Maybe }) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Waits for all of the given promises to be fulfilled or rejected. +/// If all promises are rejected, then the returned promise is rejected with same error +/// as the last one rejected. +/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with a tuple +/// of `Maybe` enums containing values or `Error`s, matching the original order of fulfilled or +/// rejected promises respectively. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promiseA: Promise of type `A`. +/// - promiseB: Promise of type `B`. +/// - returns: Promise of a tuple of `Maybe` enums containing the values or `Error`s of input +/// promises in their original order. +public func any( + on queue: DispatchQueue = .promises, + _ promiseA: Promise, + _ promiseB: Promise +) -> Promise<(Maybe, Maybe)> { + let promises = [ + promiseA.objCPromise, + promiseB.objCPromise + ] + let promise = Promise<(Maybe, Maybe)>( + Promise<(Maybe, Maybe)>.ObjCPromise.__onQueue( + queue, + any: promises + ).__onQueue(queue, then: { objCValues in + guard let values = objCValues as [AnyObject]? else { preconditionFailure() } + let valueA = asMaybe(values[0]) as Maybe + let valueB = asMaybe(values[1]) as Maybe + return (valueA, valueB) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Waits for all of the given promises to be fulfilled or rejected. +/// If all promises are rejected, then the returned promise is rejected with same error +/// as the last one rejected. +/// If at least one of the promises is fulfilled, the resulting promise is fulfilled with a tuple +/// of `Maybe` enums containing values or `Error`s, matching the original order of fulfilled or +/// rejected promises respectively. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promiseA: Promise of type `A`. +/// - promiseB: Promise of type `B`. +/// - promiseC: Promise of type `C`. +/// - returns: Promise of a tuple of `Maybe` enums containing the values or `Error`s of input +/// promises in their original order. +public func any( + on queue: DispatchQueue = .promises, + _ promiseA: Promise, + _ promiseB: Promise, + _ promiseC: Promise +) -> Promise<(Maybe, Maybe, Maybe)> { + let promises = [ + promiseA.objCPromise, + promiseB.objCPromise, + promiseC.objCPromise + ] + let promise = Promise<(Maybe, Maybe, Maybe)>( + Promise<(Maybe, Maybe, Maybe)>.ObjCPromise.__onQueue( + queue, + any: promises + ).__onQueue(queue, then: { objCValues in + guard let values = objCValues as [AnyObject]? else { preconditionFailure() } + let valueA = asMaybe(values[0]) as Maybe + let valueB = asMaybe(values[1]) as Maybe + let valueC = asMaybe(values[2]) as Maybe + return (valueA, valueB, valueC) + }) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} + +/// Wrapper enum for `any` results. +/// - value: Contains the value that corresponding promise was fulfilled with. +/// - error: Contains the error that corresponding promise was rejected with. +public enum Maybe { + case value(Value) + case error(Error) + + public init(_ value: Value) { self = .value(value) } + + public init(_ error: Error) { self = .error(error) } + + public var value: Value? { + if case .value(let value) = self { return value } else { return nil } + } + + public var error: Error? { + if case .error(let error) = self { return error } else { return nil } + } +} + +// MARK: - Conversion + +/// Helper functions that facilitates conversion of `Promise.any` results to the results normally +/// expected from `ObjCPromise.any`. +/// +/// Convert a promise created with `any` in Swift to Objective-C: +/// +/// any([promise1, promise2, promise3]).then { arrayOfMaybeEnums in +/// return arrayOfMaybeEnums.map { $0.asAnyObject() } +/// }.asObjCPromise() as Promise<[AnyObject?]>.ObjCPromise +/// +/// Convert a promise created with `any` in Objective-C to Swift: +/// +/// Promise<[AnyObject]>(objCPromise).then { arrayOfAnyObjects in +/// return arrayOfAnyObjects.map { asMaybe($0) as Maybe } +/// } +public extension Maybe { + + /// Converts generic `Value` to `AnyObject`. + func asAnyObject() -> AnyObject? { + switch self { + case .value(let value): + return Promise.asAnyObject(value) + case .error(let error): + return error as NSError + } + } +} + +/// Helper function to wrap the results of `ObjCPromise.any` with the safe `Maybe` enum. +public func asMaybe(_ value: AnyObject) -> Maybe { + if type(of: value) is NSError.Type { + return .error(value as! NSError) + } else { + guard let value = Promise.asValue(value) else { preconditionFailure() } + return .value(value) + } +} + +// MARK: - Equatable + +/// Equality operators for `Maybe`. +#if !swift(>=4.1) +extension Maybe where Value: Equatable {} +#else +extension Maybe: Equatable where Value: Equatable {} +#endif // !swift(>=4.1) + +public func == (lhs: Maybe, rhs: Maybe) -> Bool { + switch (lhs, rhs) { + case (.value(let lhs), .value(let rhs)): + return lhs == rhs + case (.error(let lhs), .error(let rhs)): + return (lhs as NSError).isEqual(rhs as NSError) + case (.value, .error), (.error, .value): + return false + } +} + +public func != (lhs: Maybe, rhs: Maybe) -> Bool { + return !(lhs == rhs) +} + +#if !swift(>=4.1) + +public func == (lhs: Maybe, rhs: Maybe) -> Bool { + switch (lhs, rhs) { + case (.value(let lhs), .value(let rhs)): + switch (lhs, rhs) { + case (nil, nil): + return true + case (nil, _?), (_?, nil): + return false + case let (lhs?, rhs?): + return lhs == rhs + } + case (.error(let lhs), .error(let rhs)): + return (lhs as NSError).isEqual(rhs as NSError) + case (.value, .error), (.error, .value): + return false + } +} + +public func != (lhs: Maybe, rhs: Maybe) -> Bool { + return !(lhs == rhs) +} + +public func == (lhs: [Maybe], rhs: [Maybe]) -> Bool { + if lhs.count != rhs.count { return false } + for (lhs, rhs) in zip(lhs, rhs) where lhs != rhs { return false } + return true +} + +public func != (lhs: [Maybe], rhs: [Maybe]) -> Bool { + return !(lhs == rhs) +} + +public func == (lhs: [Maybe], rhs: [Maybe]) -> Bool { + if lhs.count != rhs.count { return false } + for (lhs, rhs) in zip(lhs, rhs) where lhs != rhs { return false } + return true +} + +public func != (lhs: [Maybe], rhs: [Maybe]) -> Bool { + return !(lhs == rhs) +} + +#endif // !swift(>=4.1) diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Async.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Async.swift new file mode 100644 index 0000000..45db623 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Async.swift @@ -0,0 +1,42 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + typealias Async = (@escaping (Value) -> Void, @escaping (Error) -> Void) throws -> Void + + /// Creates a pending promise and executes `work` block asynchronously on the given `queue`. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block to perform any operations needed to resolve the promise. + convenience init(on queue: DispatchQueue = .promises, _ work: @escaping Async) { + let objCPromise = ObjCPromise.__onQueue(queue) { fulfill, reject in + do { + try work({ value in + if type(of: value) is NSError.Type { + reject(value as! NSError) + } else { + fulfill(Promise.asAnyObject(value)) + } + }, reject) + } catch let error { + reject(error as NSError) + } + } + self.init(objCPromise) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(self) + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Await.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Await.swift new file mode 100644 index 0000000..2a447fc --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Await.swift @@ -0,0 +1,28 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FBLPromises + +/// Waits for promise resolution. The current thread blocks until the promise is resolved. +/// - parameters: +/// - promise: Promise to wait for. +/// - throws: Error the promise was rejected with. +/// - returns: Value the promise was fulfilled with. +public func awaitPromise(_ promise: Promise) throws -> Value { + var outError: NSError? + let outValue = __FBLPromiseAwait(promise.objCPromise, &outError) as AnyObject + if let error = outError { throw error } + guard let value = Promise.asValue(outValue) else { preconditionFailure() } + return value +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Catch.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Catch.swift new file mode 100644 index 0000000..975ce4d --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Catch.swift @@ -0,0 +1,37 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + typealias Catch = (Error) -> Void + + /// Creates a pending promise which eventually gets resolved with same resolution as `self`. + /// If `self` is rejected, then `reject` block is executed asynchronously on the given queue. + /// - parameters: + /// - queue: A queue to invoke the `reject` block on. + /// - reject: A block to handle the error that `self` was rejected with. + /// - returns: A new pending promise. + @discardableResult + func `catch`(on queue: DispatchQueue = .promises, _ reject: @escaping Catch) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, catch: { + // Convert `NSError` to `PromiseError`, if applicable. + let error = PromiseError($0) ?? $0 + return reject(error as NSError) + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Delay.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Delay.swift new file mode 100644 index 0000000..b2f77ee --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Delay.swift @@ -0,0 +1,35 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + + /// Creates a new pending promise that fulfills with the same value as `self` after the `delay`, + /// or rejects with the same error immediately. + /// - parameters: + /// - queue: A queue to dispatch on. + /// - interval: Time to wait in seconds. + /// - returns: A new pending promise that fulfills at least `interval` seconds later than `self`, + /// or rejects with the same error immediately. + func delay( + on queue: DispatchQueue = .promises, + _ interval: TimeInterval + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, delay: interval)) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Do.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Do.swift new file mode 100644 index 0000000..fd7505a --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Do.swift @@ -0,0 +1,61 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + // swiftlint:disable:next type_name + typealias Do = () throws -> T + + /// Creates a pending promise to be resolved with the return value of `work` block which is + /// executed asynchronously on the given `queue`. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block that returns a value used to resolve the new promise. + convenience init(on queue: DispatchQueue = .promises, _ work: @escaping Do) { + let objCPromise = ObjCPromise.__onQueue(queue) { + do { + let resolution = try work() + return type(of: resolution) is NSError.Type + ? resolution as! NSError : Promise.asAnyObject(resolution) + } catch let error { + return error as NSError + } + } + self.init(objCPromise) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(self) + } + + /// Creates a pending promise to be resolved with the same resolution as the promise returned from + /// `work` block which is executed asynchronously on the given `queue`. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block that returns a promise used to resolve the new promise. + convenience init( + on queue: DispatchQueue = .promises, + _ work: @escaping Do> + ) { + let objCPromise = ObjCPromise.__onQueue(queue) { + do { + return try work().objCPromise + } catch let error { + return error as NSError + } + } + self.init(objCPromise) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(self) + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Race.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Race.swift new file mode 100644 index 0000000..389c4c8 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Race.swift @@ -0,0 +1,53 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Dispatch + +/// Wait until any of the given promises are fulfilled. +/// If one of the given promises is rejected, then the returned promise is rejected with same +/// error. If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: First promise, among the given ones, which was fulfilled. +public func race( + on queue: DispatchQueue = .promises, + _ promises: Promise... +) -> Promise { + return race(on: queue, promises) +} + +/// Wait until any of the given promises are fulfilled. +/// If one of the given promises is rejected, then the returned promise is rejected with same +/// error. If any other arbitrary value or `Error` appears in the array instead of `Promise`, +/// it's implicitly considered a pre-fulfilled or pre-rejected `Promise` correspondingly. +/// - parameters: +/// - queue: A queue to dispatch on. +/// - promises: Promises to wait for. +/// - returns: First promise, among the given ones, which was fulfilled. +public func race( + on queue: DispatchQueue = .promises, + _ promises: [Promise] +) -> Promise { + let promises = promises.map { $0.objCPromise } + let promise = Promise( + Promise.ObjCPromise.__onQueue(queue, race: promises) + ) + // Keep Swift wrapper alive for chained promises until `ObjCPromise` counterpart is resolved. + promises.forEach { + $0.__addPendingObject(promise) + } + return promise +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Recover.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Recover.swift new file mode 100644 index 0000000..a8e0463 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Recover.swift @@ -0,0 +1,68 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + + /// Provides a new promise to recover in case `self` gets rejected. + /// - parameters: + /// - queue: A queue to execute `recovery` block on. + /// - recovery: A block to handle the error that `self` was rejected with. + /// - returns: A new pending promise to use instead of the rejected one that gets resolved with + /// the same resolution as the promise returned from `recovery` block. + @discardableResult + func recover( + on queue: DispatchQueue = .promises, + _ recovery: @escaping (Error) throws -> Promise + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, recover: { + do { + // Convert `NSError` to `PromiseError`, if applicable. + let error = PromiseError($0) ?? $0 + return try recovery(error).objCPromise + } catch let error { + return error as NSError + } + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } + + /// Provides a new promise to recover in case `self` gets rejected. + /// - parameters: + /// - queue: A queue to execute `recovery` block on. + /// - recovery: A block to handle the error that `self` was rejected with. + /// - returns: A new pending promise to use instead of the rejected one that gets resolved with + /// the value returned from `recovery` block. + @discardableResult + func recover( + on queue: DispatchQueue = .promises, + _ recovery: @escaping (Error) throws -> Value + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, recover: { + do { + // Convert `NSError` to `PromiseError`, if applicable. + let error = PromiseError($0) ?? $0 + return Promise.asAnyObject(try recovery(error)) as Any + } catch let error { + return error as NSError + } + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Reduce.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Reduce.swift new file mode 100644 index 0000000..2ff1cab --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Reduce.swift @@ -0,0 +1,61 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Dispatch + +public extension Promise { + typealias Reducer = (Value, Element) throws -> Promise + + /// Sequentially reduces a collection of values to a single promise using a given combining block + /// and the value `self` resolves with as initial value. + /// - parameters: + /// - queue: A queue to execute `reducer` block on. + /// - items: A sequence of values to process in order. + /// - reducer: A block to combine an accumulating value and an element of the sequence into + /// a promise resolved with the new accumulating value, to be used in the next call + /// of the `reducer` or returned to the caller. + /// - returns: A new pending promise returned from the last `reducer` invocation. + /// Or `self` if `items` is empty. + @discardableResult + func reduce( + on queue: DispatchQueue = .promises, + _ items: Element..., + combine reducer: @escaping Reducer + ) -> Promise { + return reduce(on: queue, items, reducer) + } + + /// Sequentially reduces a collection of values to a single promise using a given combining block + /// and the value `self` resolves with as initial value. + /// - parameters: + /// - queue: A queue to execute `reducer` block on. + /// - items: A sequence of values to process in order. + /// - reducer: A block to combine an accumulating value and an element of the sequence into + /// a promise resolved with the new accumulating value, to be used in the next call + /// of the `reducer` or returned to the caller. + /// - returns: A new pending promise returned from the last `reducer` invocation. + /// Or `self` if `items` is empty. + @discardableResult + func reduce( + on queue: DispatchQueue = .promises, + _ items: Container, + _ reducer: @escaping Reducer + ) -> Promise { + return items.reduce(self) { promise, item in + promise.then { value in + try reducer(value, item) + } + } + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Retry.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Retry.swift new file mode 100644 index 0000000..cc59209 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Retry.swift @@ -0,0 +1,73 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FBLPromises + +/// Creates a pending promise that fulfills with the same value as the promise returned from `work` +/// block, which executes asynchronously on the given `queue`, or rejects with the same error after +/// all retry attempts have been exhausted. On rejection, the `work` block is retried after the +/// given delay `interval` and will continue to retry until the number of specified attempts have +/// been exhausted or will bail early if the given condition is not met. +/// +/// - parameters: +/// - queue: A queue to invoke the `work` block on. +/// - count: Max number of retry attempts. The `work` block will be executed once if the specified +/// count is less than or equal to zero. The default is +/// `__FBLPromiseRetryDefaultAttemptsCount`. +/// - interval: Time to wait before the next retry attempt. The default is +/// `__FBLPromiseRetryDefaultDelayInterval`. +/// - predicate: Condition to check before the next retry attempt. The block takes the following +/// parameters: +/// - count: Number of remaining retry attempts. +/// - error: The error the promise was rejected with. +/// - work: A block that executes asynchronously on the given `queue` and returns a value or an +/// error used to resolve the promise. +/// - returns: A new pending promise that fulfills with the same value as the promise returned from +/// `work` block, or rejects with the same error after all retry attempts have been +/// exhausted or if the given condition is not met. +public func retry( + on queue: DispatchQueue = .promises, + attempts count: Int = __FBLPromiseRetryDefaultAttemptsCount, + delay interval: TimeInterval = __FBLPromiseRetryDefaultDelayInterval, + condition predicate: ((_ count: Int, _ error: Error) -> Bool)? = nil, + _ work: @escaping () throws -> Promise +) -> Promise { +#if (swift(>=4.1) || (!swift(>=4.0) && swift(>=3.3))) + let predicateBlock = predicate +#else + var predicateBlock: ((_ count: Int, _ error: Error) -> ObjCBool)? + if predicate != nil { + predicateBlock = { count, error -> ObjCBool in + guard let predicate = predicate else { return true } + return ObjCBool(predicate(count, error)) + } + } +#endif // (swift(>=4.1) || (!swift(>=4.0) && swift(>=3.3))) + let objCPromise = Promise.ObjCPromise.__onQueue( + queue, + attempts: count, + delay: interval, + condition: predicateBlock + ) { + do { + return try work().objCPromise + } catch let error { + return error as NSError + } + } + let promise = Promise(objCPromise) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Testing.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Testing.swift new file mode 100644 index 0000000..a52ccd5 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Testing.swift @@ -0,0 +1,27 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FBLPromises + +extension DispatchGroup { + /// Dispatch group for promises that is typically used to wait for all scheduled blocks. + static var promises: DispatchGroup { return Promise.ObjCPromise.__dispatchGroup } +} + +/// Waits for all scheduled promise blocks. +/// - parameter timeout: Maximum time to wait. +/// - returns: `true` if all promise blocks have completed before `timeout` and `false` otherwise. +func waitForPromises(timeout: TimeInterval) -> Bool { + return __FBLWaitForPromisesWithTimeout(timeout) +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Then.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Then.swift new file mode 100644 index 0000000..88e131a --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Then.swift @@ -0,0 +1,105 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + typealias Then = (Value) throws -> Result + + /// Creates a pending promise which eventually gets resolved with the same resolution as the + /// promise returned from `work` block. The `work` block is executed asynchronously on the given + /// `queue` only when `self` is fulfilled. If `self` is rejected, the returned promise is also + /// rejected with the same error. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block to handle the value that `self` was fulfilled with. + /// - returns: A new pending promise to be resolved with the same resolution as the promise + /// returned from the `work` block. + @discardableResult + func then( + on queue: DispatchQueue = .promises, + _ work: @escaping Then> + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, then: { objCValue in + guard let value = Promise.asValue(objCValue) else { + preconditionFailure("Cannot cast \(type(of: objCValue)) to \(Value.self)") + } + do { + return try work(value).objCPromise + } catch let error { + return error as NSError + } + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } + + /// Creates a pending promise which eventually gets resolved with the value returned from `work` + /// block. The `work` block is executed asynchronously on the given `queue` only when `self` is + /// fulfilled. If `self` is rejected, the returned promise is also rejected with the same error. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block to handle the value that `self` was fulfilled with. + /// - returns: A new pending promise to be resolved with the value returned from the `work` block. + @discardableResult + func then( + on queue: DispatchQueue = .promises, + _ work: @escaping Then + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, then: { objCValue in + guard let value = Promise.asValue(objCValue) else { + preconditionFailure("Cannot cast \(type(of: objCValue)) to \(Value.self)") + } + do { + let value = try work(value) + return type(of: value) is NSError.Type + ? value as! NSError : Promise.asAnyObject(value) + } catch let error { + return error as NSError + } + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } + + /// Creates a pending promise which eventually gets resolved with the same resolution as `self`. + /// `work` block is executed asynchronously on the given `queue` only when `self` is fulfilled. + /// If `self` is rejected, the returned promise is also rejected with the same error. + /// - parameters: + /// - queue: A queue to invoke the `work` block on. + /// - work: A block to handle the value that `self` was fulfilled with. + /// - returns: A new pending promise to be resolved with the value passed into the `work` block. + @discardableResult + func then( + on queue: DispatchQueue = .promises, + _ work: @escaping Then + ) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, then: { objCValue in + guard let value = Promise.asValue(objCValue) else { + preconditionFailure("Cannot cast \(type(of: objCValue)) to \(Value.self)") + } + do { + try work(value) + return Promise.asAnyObject(value) + } catch let error { + return error as NSError + } + })) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Timeout.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Timeout.swift new file mode 100644 index 0000000..1300039 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Timeout.swift @@ -0,0 +1,32 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + + /// Waits on a promise for a given interval or rejects the promise if it exceeds the time limit. + /// - parameters: + /// - queue: A queue to dispatch on. + /// - interval: Time to wait in seconds. + /// - returns: A new pending promise that gets either resolved with same resolution as `self` or + /// rejected with `PromiseError.timedOut` error. + @discardableResult + func timeout(on queue: DispatchQueue = .promises, _ interval: TimeInterval) -> Promise { + let promise = Promise(objCPromise.__onQueue(queue, timeout: interval)) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Validate.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Validate.swift new file mode 100644 index 0000000..3825602 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Validate.swift @@ -0,0 +1,47 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Foundation + +public extension Promise { + + /// Validates a fulfilled value or rejects the value if it can not be validated. + /// - parameters: + /// - queue: A queue to dispatch on. + /// - predicate: An expression to validate. + /// - returns: A new pending promise that gets either resolved with same resolution as `self` or + /// rejected with `PromiseError.validationFailure` error. + @discardableResult + func validate( + on queue: DispatchQueue = .promises, + _ predicate: @escaping (Value) -> Bool + ) -> Promise { + let promise = Promise(objCPromise.__onQueue( + queue, + validate: { objCValue in + guard let value = Promise.asValue(objCValue) else { + preconditionFailure("Cannot cast \(type(of: objCValue)) to \(Value.self)") + } +#if (swift(>=4.1) || (!swift(>=4.0) && swift(>=3.3))) + return predicate(value) +#else + return ObjCBool(predicate(value)) +#endif // (swift(>=4.1) || (!swift(>=4.0) && swift(>=3.3))) + } + )) + // Keep Swift wrapper alive for chained promise until `ObjCPromise` counterpart is resolved. + objCPromise.__addPendingObject(promise) + return promise + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise+Wrap.swift b/Pods/PromisesSwift/Sources/Promises/Promise+Wrap.swift new file mode 100644 index 0000000..ecfbe3e --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise+Wrap.swift @@ -0,0 +1,163 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import Dispatch + +/// Provides a convenient way to convert methods that use common callback patterns into `Promise`s. + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with no arguments. +/// - returns: A new pending promise to be resolved with `nil` when completion handler finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping () -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, _ in + try work { fulfill(nil) } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with one argument of generic `Value` type. +/// - returns: A new pending promise to be resolved with the value provided by completion handler +/// when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Value) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, _ in + try work { fulfill($0) } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with one argument of optional generic `Value` type. +/// - returns: A new pending promise to be resolved with the value or error provided by completion +/// handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Value?) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, _ in + try work { fulfill($0) } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with two arguments: a generic of `Value` type and +/// an optional `Error`. +/// - returns: A new pending promise to be resolved with the value or error provided by completion +/// handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Value, Error?) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, reject in + try work { value, error in + if let error = error { + reject(error) + } else { + fulfill(value) + } + } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with two arguments: an optional `Error` and a generic of +/// `Value` type. +/// - returns: A new pending promise to be resolved with the error or value provided by completion +/// handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Error?, Value) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, reject in + try work { error, value in + if let error = error { + reject(error) + } else { + fulfill(value) + } + } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with two arguments: an optional generic of `Value` type +/// and an optional `Error`. +/// - returns: A new pending promise to be resolved with the value or error provided by completion +/// handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Value?, Error?) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, reject in + try work { value, error in + if let error = error { + reject(error) + } else { + fulfill(value) + } + } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with two arguments: an optional `Error` and an optional +/// generic of `Value` type. +/// - returns: A new pending promise to be resolved with the error or value provided by completion +/// handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Error?, Value?) -> Void) throws -> Void +) -> Promise { + return Promise(on: queue) { fulfill, reject in + try work { error, value in + if let error = error { + reject(error) + } else { + fulfill(value) + } + } + } +} + +/// Creates a new promise to be resolved when completion handler gets invoked. +/// - parameter work: A block to execute asynchronously to invoke some API that requires +/// a completion handler with three arguments: two optionals of `Any` type +/// and an optional `Error`. +/// - returns: A new pending promise to be resolved with a tuple of optional values or an error +/// provided by completion handler when it finishes. +public func wrap( + on queue: DispatchQueue = .promises, + _ work: @escaping (@escaping (Value1?, Value2?, Error?) -> Void) throws -> Void +) -> Promise<(Value1?, Value2?)> { + return Promise<(Value1?, Value2?)>(on: queue) { fulfill, reject in + try work { value1, value2, error in + if let error = error { + reject(error) + } else { + fulfill((value1, value2)) + } + } + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Promise.swift b/Pods/PromisesSwift/Sources/Promises/Promise.swift new file mode 100644 index 0000000..5ad9b94 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Promise.swift @@ -0,0 +1,146 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FBLPromises + +/// Promises synchronization construct in Swift. Leverages ObjC implementation internally. +public final class Promise { + public typealias ObjCPromise = FBLPromise + + /// Creates a new promise with an existing ObjC promise. + public init(_ objCPromise: ObjCPromise) { + guard let objCPromise = objCPromise as? ObjCPromise else { + preconditionFailure("Cannot cast \(T.self) to \(AnyObject.self)") + } + self.objCPromise = objCPromise + } + + /// Creates a new pending promise. + public static func pending() -> Promise { + return Promise.init(ObjCPromise.__pending()) + } + + /// Creates a new pending promise. + public convenience init() { + self.init(ObjCPromise.__pending()) + } + + /// Creates a new promise rejected with the given `error`. + public convenience init(_ error: Error) { + self.init(ObjCPromise.__resolved(with: error as NSError)) + } + + /// Creates a new promise resolved with the result of `work` block. + public convenience init(_ work: @autoclosure () throws -> Value) { + do { + let resolution = try work() + if type(of: resolution) is NSError.Type { + let error = resolution as! NSError + self.init(error) + } else if let objCPromise = resolution as? ObjCPromise { + self.init(objCPromise) + } else { + self.init(ObjCPromise.__resolved(with: Promise.asAnyObject(resolution))) + } + } catch let error { + self.init(error as NSError) + } + } + + /// Resolves `self` with the given `resolution`. + public func fulfill(_ resolution: Value) { + objCPromise.__fulfill(Promise.asAnyObject(resolution)) + } + + /// Rejects `self` with the given `error`. + public func reject(_ error: Error) { + objCPromise.__fulfill(error as NSError) + } + + /// Converts `self` into ObjC promise. + public func asObjCPromise() -> ObjCPromise { + guard let objCPromise = objCPromise as? ObjCPromise else { + preconditionFailure("Cannot cast \(AnyObject.self) to \(T.self)") + } + return objCPromise + } + + // MARK: Internal + + /// Underlying ObjC counterpart. + let objCPromise: ObjCPromise + + var isPending: Bool { return objCPromise.__isPending } + + var isFulfilled: Bool { return objCPromise.__isFulfilled } + + var isRejected: Bool { return objCPromise.__isRejected } + + var value: Value? { + let objCValue = objCPromise.__value + if Promise.isBridgedNil(objCValue) { return nil } + guard let value = objCValue as? Value else { + preconditionFailure("Cannot cast \(type(of: objCValue)) to \(Value.self)") + } + return value + } + + var error: Error? { + guard let objCPromiseError = objCPromise.__error else { return nil } + // Convert `NSError` to `PromiseError`, if applicable. + return PromiseError(objCPromiseError) ?? objCPromiseError + } + + /// Converts generic `Value` to `AnyObject`. + static func asAnyObject(_ value: Value) -> AnyObject? { + return Promise.isBridgedNil(value) ? nil : value as AnyObject + } + + /// Converts `AnyObject` to generic `Value`, or `nil` if the conversion is not possible. + static func asValue(_ value: AnyObject?) -> Value? { + // Swift nil becomes NSNull during bridging. + return (value as? Value) ?? NSNull() as AnyObject as? Value + } + + // MARK: Private + + /// Checks if generic `Value` is bridged ObjC `nil`. + private static func isBridgedNil(_ value: Value?) -> Bool { + // Swift nil becomes NSNull during bridging. + return !(value is NSNull) && (value as AnyObject is NSNull) + } +} + +extension Promise: CustomStringConvertible { + public var description: String { + var description = "nil" + if isFulfilled { + if let value = value { description = String(describing: value) } + return "Fulfilled: \(description)" + } + if isRejected { + if let error = error { description = String(describing: error) } + return "Rejected: \(description)" + } + return "Pending: \(Value.self)" + } +} + +public extension DispatchQueue { + /// Default dispatch queue used for `Promise`, which is `main` if a queue is not specified. + static var promises: DispatchQueue { + get { return Promise.ObjCPromise.__defaultDispatchQueue } + set { Promise.ObjCPromise.__defaultDispatchQueue = newValue } + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/PromiseError.swift b/Pods/PromisesSwift/Sources/Promises/PromiseError.swift new file mode 100644 index 0000000..37f0d04 --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/PromiseError.swift @@ -0,0 +1,58 @@ +// Copyright 2018 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import FBLPromises + +/// Internal errors that `Promise` can throw. +/// Indirectly conforms to `Swift.Error` through conformance to `Swift.CustomNSError` below. +/// Not placing it under extension `Promise` for convenience to avoid collisions with `Swift.Error`. +public enum PromiseError { + case timedOut + case validationFailure +} + +/// Downcasting from `Swift.Error`. +extension PromiseError { + public init?(_ error: Error) { + let error = error as NSError + if error.domain != __FBLPromiseErrorDomain { return nil } + switch error.code { + case __FBLPromiseErrorCode.timedOut.rawValue: + self = .timedOut + case __FBLPromiseErrorCode.validationFailure.rawValue: + self = .validationFailure + default: + return nil + } + } +} + +extension PromiseError: CustomNSError { + public static var errorDomain: String { + return __FBLPromiseErrorDomain + } + + public var errorCode: Int { + switch self { + case .timedOut: + return __FBLPromiseErrorCode.timedOut.rawValue + case .validationFailure: + return __FBLPromiseErrorCode.validationFailure.rawValue + } + } + + public var errorUserInfo: [String: Any] { + return [String: Any]() + } +} diff --git a/Pods/PromisesSwift/Sources/Promises/Resources/PrivacyInfo.xcprivacy b/Pods/PromisesSwift/Sources/Promises/Resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..5397adc --- /dev/null +++ b/Pods/PromisesSwift/Sources/Promises/Resources/PrivacyInfo.xcprivacy @@ -0,0 +1,14 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + diff --git a/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig b/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig new file mode 100644 index 0000000..d44b775 --- /dev/null +++ b/Pods/Target Support Files/Firebase/Firebase.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/FirebaseAnalytics/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "StoreKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/Firebase/Firebase.release.xcconfig b/Pods/Target Support Files/Firebase/Firebase.release.xcconfig new file mode 100644 index 0000000..d44b775 --- /dev/null +++ b/Pods/Target Support Files/Firebase/Firebase.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Firebase +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/FirebaseAnalytics/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/Firebase" "${PODS_ROOT}/Headers/Public" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "StoreKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/Firebase +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-Info.plist b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-dummy.m b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-dummy.m new file mode 100644 index 0000000..6b78697 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseABTesting : NSObject +@end +@implementation PodsDummy_FirebaseABTesting +@end diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-umbrella.h b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-umbrella.h new file mode 100644 index 0000000..6f49ae4 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting-umbrella.h @@ -0,0 +1,19 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseABTesting.h" +#import "FIRExperimentController.h" +#import "FIRLifecycleEvents.h" + +FOUNDATION_EXPORT double FirebaseABTestingVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseABTestingVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.debug.xcconfig b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.debug.xcconfig new file mode 100644 index 0000000..734fe04 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseABTesting +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.modulemap b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.modulemap new file mode 100644 index 0000000..6531b1a --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseABTesting { + umbrella header "FirebaseABTesting-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.release.xcconfig b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.release.xcconfig new file mode 100644 index 0000000..734fe04 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/FirebaseABTesting.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseABTesting +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseABTesting/ResourceBundle-FirebaseABTesting_Privacy-FirebaseABTesting-Info.plist b/Pods/Target Support Files/FirebaseABTesting/ResourceBundle-FirebaseABTesting_Privacy-FirebaseABTesting-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseABTesting/ResourceBundle-FirebaseABTesting_Privacy-FirebaseABTesting-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-input-files.xcfilelist b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-input-files.xcfilelist new file mode 100644 index 0000000..09a3da3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-input-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_ROOT}/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks.sh +${PODS_ROOT}/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework \ No newline at end of file diff --git a/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-output-files.xcfilelist b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-output-files.xcfilelist new file mode 100644 index 0000000..98ae84f --- /dev/null +++ b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks-output-files.xcfilelist @@ -0,0 +1 @@ +${PODS_XCFRAMEWORKS_BUILD_DIR}/FirebaseAnalytics/AdIdSupport/FirebaseAnalytics.framework \ No newline at end of file diff --git a/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks.sh b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks.sh new file mode 100755 index 0000000..0d05828 --- /dev/null +++ b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics-xcframeworks.sh @@ -0,0 +1,145 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + + +variant_for_slice() +{ + case "$1" in + "FirebaseAnalytics.xcframework/ios-arm64") + echo "" + ;; + "FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst") + echo "maccatalyst" + ;; + "FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator") + echo "simulator" + ;; + "FirebaseAnalytics.xcframework/macos-arm64_x86_64") + echo "" + ;; + "FirebaseAnalytics.xcframework/tvos-arm64") + echo "" + ;; + "FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator") + echo "simulator" + ;; + esac +} + +archs_for_slice() +{ + case "$1" in + "FirebaseAnalytics.xcframework/ios-arm64") + echo "arm64" + ;; + "FirebaseAnalytics.xcframework/ios-arm64_x86_64-maccatalyst") + echo "arm64 x86_64" + ;; + "FirebaseAnalytics.xcframework/ios-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + "FirebaseAnalytics.xcframework/macos-arm64_x86_64") + echo "arm64 x86_64" + ;; + "FirebaseAnalytics.xcframework/tvos-arm64") + echo "arm64" + ;; + "FirebaseAnalytics.xcframework/tvos-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + esac +} + +copy_dir() +{ + local source="$1" + local destination="$2" + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" \"${source}*\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}"/* "${destination}" +} + +SELECT_SLICE_RETVAL="" + +select_slice() { + local xcframework_name="$1" + xcframework_name="${xcframework_name##*/}" + local paths=("${@:2}") + # Locate the correct slice of the .xcframework for the current architectures + local target_path="" + + # Split archs on space so we can find a slice that has all the needed archs + local target_archs=$(echo $ARCHS | tr " " "\n") + + local target_variant="" + if [[ "$PLATFORM_NAME" == *"simulator" ]]; then + target_variant="simulator" + fi + if [[ ! -z ${EFFECTIVE_PLATFORM_NAME+x} && "$EFFECTIVE_PLATFORM_NAME" == *"maccatalyst" ]]; then + target_variant="maccatalyst" + fi + for i in ${!paths[@]}; do + local matched_all_archs="1" + local slice_archs="$(archs_for_slice "${xcframework_name}/${paths[$i]}")" + local slice_variant="$(variant_for_slice "${xcframework_name}/${paths[$i]}")" + for target_arch in $target_archs; do + if ! [[ "${slice_variant}" == "$target_variant" ]]; then + matched_all_archs="0" + break + fi + + if ! echo "${slice_archs}" | tr " " "\n" | grep -F -q -x "$target_arch"; then + matched_all_archs="0" + break + fi + done + + if [[ "$matched_all_archs" == "1" ]]; then + # Found a matching slice + echo "Selected xcframework slice ${paths[$i]}" + SELECT_SLICE_RETVAL=${paths[$i]} + break + fi + done +} + +install_xcframework() { + local basepath="$1" + local name="$2" + local package_type="$3" + local paths=("${@:4}") + + # Locate the correct slice of the .xcframework for the current architectures + select_slice "${basepath}" "${paths[@]}" + local target_path="$SELECT_SLICE_RETVAL" + if [[ -z "$target_path" ]]; then + echo "warning: [CP] $(basename ${basepath}): Unable to find matching slice in '${paths[@]}' for the current build architectures ($ARCHS) and platform (${EFFECTIVE_PLATFORM_NAME-${PLATFORM_NAME}})." + return + fi + local source="$basepath/$target_path" + + local destination="${PODS_XCFRAMEWORKS_BUILD_DIR}/${name}" + + if [ ! -d "$destination" ]; then + mkdir -p "$destination" + fi + + copy_dir "$source/" "$destination" + echo "Copied $source to $destination" +} + +install_xcframework "${PODS_ROOT}/FirebaseAnalytics/Frameworks/FirebaseAnalytics.xcframework" "FirebaseAnalytics/AdIdSupport" "framework" "ios-arm64" "ios-arm64_x86_64-maccatalyst" "ios-arm64_x86_64-simulator" + diff --git a/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.debug.xcconfig b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.debug.xcconfig new file mode 100644 index 0000000..38847ed --- /dev/null +++ b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAnalytics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/FirebaseAnalytics/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"c++" -l"sqlite3" -l"z" -framework "StoreKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseAnalytics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.release.xcconfig b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.release.xcconfig new file mode 100644 index 0000000..38847ed --- /dev/null +++ b/Pods/Target Support Files/FirebaseAnalytics/FirebaseAnalytics.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseAnalytics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/FirebaseAnalytics/Frameworks" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/FirebaseAnalytics/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"c++" -l"sqlite3" -l"z" -framework "StoreKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseAnalytics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist b/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m b/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m new file mode 100644 index 0000000..4f1eb27 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCore : NSObject +@end +@implementation PodsDummy_FirebaseCore +@end diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h b/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h new file mode 100644 index 0000000..509268c --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore-umbrella.h @@ -0,0 +1,23 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRApp.h" +#import "FIRConfiguration.h" +#import "FirebaseCore.h" +#import "FIRLoggerLevel.h" +#import "FIROptions.h" +#import "FIRTimestamp.h" +#import "FIRVersion.h" + +FOUNDATION_EXPORT double FirebaseCoreVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig b/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig new file mode 100644 index 0000000..4bd4933 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=11.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreInternal" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap b/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap new file mode 100644 index 0000000..4c38b87 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCore { + umbrella header "FirebaseCore-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig b/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig new file mode 100644 index 0000000..4bd4933 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/FirebaseCore.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 Firebase_VERSION=11.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_CFLAGS = $(inherited) -fno-autolink +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCoreInternal" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCore +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist b/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCore/ResourceBundle-FirebaseCore_Privacy-FirebaseCore-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-Info.plist b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-dummy.m b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-dummy.m new file mode 100644 index 0000000..945df00 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCoreExtension : NSObject +@end +@implementation PodsDummy_FirebaseCoreExtension +@end diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-prefix.pch b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-umbrella.h b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-umbrella.h new file mode 100644 index 0000000..3365681 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension-umbrella.h @@ -0,0 +1,25 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRAppInternal.h" +#import "FIRComponent.h" +#import "FIRComponentContainer.h" +#import "FIRComponentType.h" +#import "FirebaseCoreInternal.h" +#import "FIRHeartbeatLogger.h" +#import "FIRLibrary.h" +#import "FIRLogger.h" +#import "FIROptionsInternal.h" + +FOUNDATION_EXPORT double FirebaseCoreExtensionVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreExtensionVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.debug.xcconfig b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.debug.xcconfig new file mode 100644 index 0000000..344cfb4 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreExtension +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.modulemap b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.modulemap new file mode 100644 index 0000000..34afd4c --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCoreExtension { + umbrella header "FirebaseCoreExtension-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.release.xcconfig b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.release.xcconfig new file mode 100644 index 0000000..344cfb4 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/FirebaseCoreExtension.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -framework "FirebaseCore" -framework "Foundation" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreExtension +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCoreExtension/ResourceBundle-FirebaseCoreExtension_Privacy-FirebaseCoreExtension-Info.plist b/Pods/Target Support Files/FirebaseCoreExtension/ResourceBundle-FirebaseCoreExtension_Privacy-FirebaseCoreExtension-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreExtension/ResourceBundle-FirebaseCoreExtension_Privacy-FirebaseCoreExtension-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m new file mode 100644 index 0000000..1eb5767 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCoreInternal : NSObject +@end +@implementation PodsDummy_FirebaseCoreInternal +@end diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h new file mode 100644 index 0000000..559d38b --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double FirebaseCoreInternalVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCoreInternalVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig new file mode 100644 index 0000000..7137f77 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreInternal +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap new file mode 100644 index 0000000..c5a589e --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCoreInternal { + umbrella header "FirebaseCoreInternal-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig new file mode 100644 index 0000000..7137f77 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/FirebaseCoreInternal.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCoreInternal +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist b/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCoreInternal/ResourceBundle-FirebaseCoreInternal_Privacy-FirebaseCoreInternal-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-Info.plist b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-dummy.m b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-dummy.m new file mode 100644 index 0000000..b9c73b1 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseCrashlytics : NSObject +@end +@implementation PodsDummy_FirebaseCrashlytics +@end diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-umbrella.h b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-umbrella.h new file mode 100644 index 0000000..5c3e793 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics-umbrella.h @@ -0,0 +1,21 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRCrashlytics.h" +#import "FIRCrashlyticsReport.h" +#import "FirebaseCrashlytics.h" +#import "FIRExceptionModel.h" +#import "FIRStackFrame.h" + +FOUNDATION_EXPORT double FirebaseCrashlyticsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseCrashlyticsVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.debug.xcconfig b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.debug.xcconfig new file mode 100644 index 0000000..1b74ab4 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.debug.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCrashlytics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 CLS_SDK_NAME="Crashlytics iOS SDK" PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfigInterop" -framework "FirebaseSessions" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCrashlytics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.modulemap b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.modulemap new file mode 100644 index 0000000..90dc252 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseCrashlytics { + umbrella header "FirebaseCrashlytics-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.release.xcconfig b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.release.xcconfig new file mode 100644 index 0000000..1b74ab4 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/FirebaseCrashlytics.release.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCrashlytics +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 CLS_SDK_NAME="Crashlytics iOS SDK" PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -l"c++" -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfigInterop" -framework "FirebaseSessions" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseCrashlytics +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseCrashlytics/ResourceBundle-FirebaseCrashlytics_Privacy-FirebaseCrashlytics-Info.plist b/Pods/Target Support Files/FirebaseCrashlytics/ResourceBundle-FirebaseCrashlytics_Privacy-FirebaseCrashlytics-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseCrashlytics/ResourceBundle-FirebaseCrashlytics_Privacy-FirebaseCrashlytics-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m new file mode 100644 index 0000000..ae19551 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseInstallations : NSObject +@end +@implementation PodsDummy_FirebaseInstallations +@end diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h new file mode 100644 index 0000000..431ef45 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations-umbrella.h @@ -0,0 +1,20 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseInstallations.h" +#import "FIRInstallations.h" +#import "FIRInstallationsAuthTokenResult.h" +#import "FIRInstallationsErrors.h" + +FOUNDATION_EXPORT double FirebaseInstallationsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseInstallationsVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig new file mode 100644 index 0000000..c878136 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" -framework "FirebaseCore" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseInstallations +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap new file mode 100644 index 0000000..f6e2a29 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseInstallations { + umbrella header "FirebaseInstallations-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig new file mode 100644 index 0000000..c878136 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/FirebaseInstallations.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" -framework "FirebaseCore" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseInstallations +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist b/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseInstallations/ResourceBundle-FirebaseInstallations_Privacy-FirebaseInstallations-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-Info.plist b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-dummy.m b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-dummy.m new file mode 100644 index 0000000..b43fe71 --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebasePerformance : NSObject +@end +@implementation PodsDummy_FirebasePerformance +@end diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-umbrella.h b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-umbrella.h new file mode 100644 index 0000000..6cf2040 --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance-umbrella.h @@ -0,0 +1,21 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebasePerformance.h" +#import "FIRHTTPMetric.h" +#import "FIRPerformance.h" +#import "FIRPerformanceAttributable.h" +#import "FIRTrace.h" + +FOUNDATION_EXPORT double FirebasePerformanceVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebasePerformanceVersionString[]; + diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.debug.xcconfig b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.debug.xcconfig new file mode 100644 index 0000000..115a5d9 --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebasePerformance +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfig" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 FIRPerformance_LIB_VERSION=11.1.0 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfig" -framework "FirebaseSessions" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebasePerformance +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.modulemap b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.modulemap new file mode 100644 index 0000000..f118f6f --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.modulemap @@ -0,0 +1,6 @@ +framework module FirebasePerformance { + umbrella header "FirebasePerformance-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.release.xcconfig b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.release.xcconfig new file mode 100644 index 0000000..115a5d9 --- /dev/null +++ b/Pods/Target Support Files/FirebasePerformance/FirebasePerformance.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebasePerformance +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfig" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 FIRPerformance_LIB_VERSION=11.1.0 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfig" -framework "FirebaseSessions" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebasePerformance +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-Info.plist b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-dummy.m b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-dummy.m new file mode 100644 index 0000000..641c58f --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseRemoteConfig : NSObject +@end +@implementation PodsDummy_FirebaseRemoteConfig +@end diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-umbrella.h b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-umbrella.h new file mode 100644 index 0000000..a9a8d06 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig-umbrella.h @@ -0,0 +1,18 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FirebaseRemoteConfig.h" +#import "FIRRemoteConfig.h" + +FOUNDATION_EXPORT double FirebaseRemoteConfigVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseRemoteConfigVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.debug.xcconfig b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.debug.xcconfig new file mode 100644 index 0000000..46794b2 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.debug.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfig +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "FirebaseABTesting" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfigInterop" -framework "FirebaseSharedSwift" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseRemoteConfig +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.modulemap b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.modulemap new file mode 100644 index 0000000..b6bcfa8 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseRemoteConfig { + umbrella header "FirebaseRemoteConfig-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.release.xcconfig b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.release.xcconfig new file mode 100644 index 0000000..46794b2 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/FirebaseRemoteConfig.release.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfig +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseABTesting" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "FirebaseABTesting" -framework "FirebaseCore" -framework "FirebaseInstallations" -framework "FirebaseRemoteConfigInterop" -framework "FirebaseSharedSwift" -framework "Foundation" -framework "GoogleUtilities" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseRemoteConfig +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseRemoteConfig/ResourceBundle-FirebaseRemoteConfig_Privacy-FirebaseRemoteConfig-Info.plist b/Pods/Target Support Files/FirebaseRemoteConfig/ResourceBundle-FirebaseRemoteConfig_Privacy-FirebaseRemoteConfig-Info.plist new file mode 100644 index 0000000..b1ec047 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfig/ResourceBundle-FirebaseRemoteConfig_Privacy-FirebaseRemoteConfig-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-Info.plist b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-dummy.m b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-dummy.m new file mode 100644 index 0000000..5d07229 --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseRemoteConfigInterop : NSObject +@end +@implementation PodsDummy_FirebaseRemoteConfigInterop +@end diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-umbrella.h b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-umbrella.h new file mode 100644 index 0000000..192520e --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double FirebaseRemoteConfigInteropVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseRemoteConfigInteropVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.debug.xcconfig b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.debug.xcconfig new file mode 100644 index 0000000..9cec78a --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseRemoteConfigInterop +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.modulemap b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.modulemap new file mode 100644 index 0000000..45f9a1a --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseRemoteConfigInterop { + umbrella header "FirebaseRemoteConfigInterop-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.release.xcconfig b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.release.xcconfig new file mode 100644 index 0000000..9cec78a --- /dev/null +++ b/Pods/Target Support Files/FirebaseRemoteConfigInterop/FirebaseRemoteConfigInterop.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseRemoteConfigInterop +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseRemoteConfigInterop +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-Info.plist b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-dummy.m b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-dummy.m new file mode 100644 index 0000000..43c1d3d --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseSessions : NSObject +@end +@implementation PodsDummy_FirebaseSessions +@end diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-umbrella.h b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-umbrella.h new file mode 100644 index 0000000..f0032f8 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions-umbrella.h @@ -0,0 +1,18 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FIRSESNanoPBHelpers.h" +#import "sessions.nanopb.h" + +FOUNDATION_EXPORT double FirebaseSessionsVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseSessionsVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.debug.xcconfig b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.debug.xcconfig new file mode 100644 index 0000000..5dc654e --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.debug.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseCoreExtension" -framework "FirebaseInstallations" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Promises" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseSessions +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.modulemap b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.modulemap new file mode 100644 index 0000000..5989a78 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseSessions { + umbrella header "FirebaseSessions-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.release.xcconfig b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.release.xcconfig new file mode 100644 index 0000000..5dc654e --- /dev/null +++ b/Pods/Target Support Files/FirebaseSessions/FirebaseSessions.release.xcconfig @@ -0,0 +1,18 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSessions +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCore" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreExtension" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseCoreInternal" "${PODS_CONFIGURATION_BUILD_DIR}/FirebaseInstallations" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "CoreTelephony" -framework "FirebaseCore" -framework "FirebaseCoreExtension" -framework "FirebaseInstallations" -framework "Foundation" -framework "GoogleDataTransport" -framework "GoogleUtilities" -framework "Promises" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "nanopb" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseSessions +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-Info.plist b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-Info.plist new file mode 100644 index 0000000..c9b5eb3 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 11.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-dummy.m b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-dummy.m new file mode 100644 index 0000000..0e9c3a1 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_FirebaseSharedSwift : NSObject +@end +@implementation PodsDummy_FirebaseSharedSwift +@end diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-umbrella.h b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-umbrella.h new file mode 100644 index 0000000..273677a --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double FirebaseSharedSwiftVersionNumber; +FOUNDATION_EXPORT const unsigned char FirebaseSharedSwiftVersionString[]; + diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.debug.xcconfig b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.debug.xcconfig new file mode 100644 index 0000000..df94f10 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseSharedSwift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.modulemap b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.modulemap new file mode 100644 index 0000000..a4ee23b --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.modulemap @@ -0,0 +1,6 @@ +framework module FirebaseSharedSwift { + umbrella header "FirebaseSharedSwift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.release.xcconfig b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.release.xcconfig new file mode 100644 index 0000000..df94f10 --- /dev/null +++ b/Pods/Target Support Files/FirebaseSharedSwift/FirebaseSharedSwift.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FirebaseSharedSwift +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/FirebaseSharedSwift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-input-files.xcfilelist b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-input-files.xcfilelist new file mode 100644 index 0000000..269becc --- /dev/null +++ b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-input-files.xcfilelist @@ -0,0 +1,3 @@ +${PODS_ROOT}/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks.sh +${PODS_ROOT}/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework +${PODS_ROOT}/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework \ No newline at end of file diff --git a/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-output-files.xcfilelist b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-output-files.xcfilelist new file mode 100644 index 0000000..3e590c7 --- /dev/null +++ b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks-output-files.xcfilelist @@ -0,0 +1,2 @@ +${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport/GoogleAppMeasurementIdentitySupport.framework +${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport/GoogleAppMeasurement.framework \ No newline at end of file diff --git a/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks.sh b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks.sh new file mode 100755 index 0000000..c006b82 --- /dev/null +++ b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement-xcframeworks.sh @@ -0,0 +1,182 @@ +#!/bin/sh +set -e +set -u +set -o pipefail + +function on_error { + echo "$(realpath -mq "${0}"):$1: error: Unexpected failure" +} +trap 'on_error $LINENO' ERR + + +# This protects against multiple targets copying the same framework dependency at the same time. The solution +# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html +RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????") + + +variant_for_slice() +{ + case "$1" in + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64") + echo "" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst") + echo "maccatalyst" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator") + echo "simulator" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64") + echo "" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64") + echo "" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator") + echo "simulator" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64") + echo "" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst") + echo "maccatalyst" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator") + echo "simulator" + ;; + "GoogleAppMeasurement.xcframework/macos-arm64_x86_64") + echo "" + ;; + "GoogleAppMeasurement.xcframework/tvos-arm64") + echo "" + ;; + "GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator") + echo "simulator" + ;; + esac +} + +archs_for_slice() +{ + case "$1" in + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64") + echo "arm64" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-maccatalyst") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/ios-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/macos-arm64_x86_64") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64") + echo "arm64" + ;; + "GoogleAppMeasurementIdentitySupport.xcframework/tvos-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64") + echo "arm64" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64_x86_64-maccatalyst") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurement.xcframework/ios-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurement.xcframework/macos-arm64_x86_64") + echo "arm64 x86_64" + ;; + "GoogleAppMeasurement.xcframework/tvos-arm64") + echo "arm64" + ;; + "GoogleAppMeasurement.xcframework/tvos-arm64_x86_64-simulator") + echo "arm64 x86_64" + ;; + esac +} + +copy_dir() +{ + local source="$1" + local destination="$2" + + # Use filter instead of exclude so missing patterns don't throw errors. + echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" \"${source}*\" \"${destination}\"" + rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" "${source}"/* "${destination}" +} + +SELECT_SLICE_RETVAL="" + +select_slice() { + local xcframework_name="$1" + xcframework_name="${xcframework_name##*/}" + local paths=("${@:2}") + # Locate the correct slice of the .xcframework for the current architectures + local target_path="" + + # Split archs on space so we can find a slice that has all the needed archs + local target_archs=$(echo $ARCHS | tr " " "\n") + + local target_variant="" + if [[ "$PLATFORM_NAME" == *"simulator" ]]; then + target_variant="simulator" + fi + if [[ ! -z ${EFFECTIVE_PLATFORM_NAME+x} && "$EFFECTIVE_PLATFORM_NAME" == *"maccatalyst" ]]; then + target_variant="maccatalyst" + fi + for i in ${!paths[@]}; do + local matched_all_archs="1" + local slice_archs="$(archs_for_slice "${xcframework_name}/${paths[$i]}")" + local slice_variant="$(variant_for_slice "${xcframework_name}/${paths[$i]}")" + for target_arch in $target_archs; do + if ! [[ "${slice_variant}" == "$target_variant" ]]; then + matched_all_archs="0" + break + fi + + if ! echo "${slice_archs}" | tr " " "\n" | grep -F -q -x "$target_arch"; then + matched_all_archs="0" + break + fi + done + + if [[ "$matched_all_archs" == "1" ]]; then + # Found a matching slice + echo "Selected xcframework slice ${paths[$i]}" + SELECT_SLICE_RETVAL=${paths[$i]} + break + fi + done +} + +install_xcframework() { + local basepath="$1" + local name="$2" + local package_type="$3" + local paths=("${@:4}") + + # Locate the correct slice of the .xcframework for the current architectures + select_slice "${basepath}" "${paths[@]}" + local target_path="$SELECT_SLICE_RETVAL" + if [[ -z "$target_path" ]]; then + echo "warning: [CP] $(basename ${basepath}): Unable to find matching slice in '${paths[@]}' for the current build architectures ($ARCHS) and platform (${EFFECTIVE_PLATFORM_NAME-${PLATFORM_NAME}})." + return + fi + local source="$basepath/$target_path" + + local destination="${PODS_XCFRAMEWORKS_BUILD_DIR}/${name}" + + if [ ! -d "$destination" ]; then + mkdir -p "$destination" + fi + + copy_dir "$source/" "$destination" + echo "Copied $source to $destination" +} + +install_xcframework "${PODS_ROOT}/GoogleAppMeasurement/Frameworks/GoogleAppMeasurementIdentitySupport.xcframework" "GoogleAppMeasurement/AdIdSupport" "framework" "ios-arm64" "ios-arm64_x86_64-maccatalyst" "ios-arm64_x86_64-simulator" +install_xcframework "${PODS_ROOT}/GoogleAppMeasurement/Frameworks/GoogleAppMeasurement.xcframework" "GoogleAppMeasurement/WithoutAdIdSupport" "framework" "ios-arm64" "ios-arm64_x86_64-maccatalyst" "ios-arm64_x86_64-simulator" + diff --git a/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.debug.xcconfig b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.debug.xcconfig new file mode 100644 index 0000000..b6670fb --- /dev/null +++ b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.debug.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleAppMeasurement +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -l"c++" -l"sqlite3" -l"z" -framework "StoreKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleAppMeasurement +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.release.xcconfig b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.release.xcconfig new file mode 100644 index 0000000..b6670fb --- /dev/null +++ b/Pods/Target Support Files/GoogleAppMeasurement/GoogleAppMeasurement.release.xcconfig @@ -0,0 +1,14 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleAppMeasurement +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" "${PODS_ROOT}/GoogleAppMeasurement/Frameworks" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/AdIdSupport" "${PODS_XCFRAMEWORKS_BUILD_DIR}/GoogleAppMeasurement/WithoutAdIdSupport" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +OTHER_LDFLAGS = $(inherited) -l"c++" -l"sqlite3" -l"z" -framework "StoreKit" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleAppMeasurement +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist new file mode 100644 index 0000000..3ce28c0 --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 10.1.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m new file mode 100644 index 0000000..9a08ec3 --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleDataTransport : NSObject +@end +@implementation PodsDummy_GoogleDataTransport +@end diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h new file mode 100644 index 0000000..368a3aa --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport-umbrella.h @@ -0,0 +1,26 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GDTCORClock.h" +#import "GDTCORConsoleLogger.h" +#import "GDTCOREndpoints.h" +#import "GDTCOREvent.h" +#import "GDTCOREventDataObject.h" +#import "GDTCOREventTransformer.h" +#import "GDTCORProductData.h" +#import "GDTCORTargets.h" +#import "GDTCORTransport.h" +#import "GoogleDataTransport.h" + +FOUNDATION_EXPORT double GoogleDataTransportVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleDataTransportVersionString[]; + diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig new file mode 100644 index 0000000..4557a14 --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.debug.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1GDTCOR_VERSION=10.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap new file mode 100644 index 0000000..8a67414 --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.modulemap @@ -0,0 +1,6 @@ +framework module GoogleDataTransport { + umbrella header "GoogleDataTransport-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig new file mode 100644 index 0000000..4557a14 --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/GoogleDataTransport.release.xcconfig @@ -0,0 +1,17 @@ +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleDataTransport +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" "${PODS_CONFIGURATION_BUILD_DIR}/nanopb" +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1GDTCOR_VERSION=10.1.0 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}/" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "CoreTelephony" -framework "FBLPromises" -framework "SystemConfiguration" -framework "nanopb" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleDataTransport +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist b/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist new file mode 100644 index 0000000..728a55b --- /dev/null +++ b/Pods/Target Support Files/GoogleDataTransport/ResourceBundle-GoogleDataTransport_Privacy-GoogleDataTransport-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 10.1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist new file mode 100644 index 0000000..b5f52ed --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 8.0.2 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m new file mode 100644 index 0000000..98ac4e9 --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_GoogleUtilities : NSObject +@end +@implementation PodsDummy_GoogleUtilities +@end diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h new file mode 100644 index 0000000..907b89e --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities-umbrella.h @@ -0,0 +1,36 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "GULAppDelegateSwizzler.h" +#import "GULApplication.h" +#import "GULSceneDelegateSwizzler.h" +#import "GULAppEnvironmentUtil.h" +#import "GULKeychainStorage.h" +#import "GULKeychainUtils.h" +#import "GULNetworkInfo.h" +#import "GULLogger.h" +#import "GULLoggerLevel.h" +#import "GULOriginalIMPConvenienceMacros.h" +#import "GULSwizzler.h" +#import "GULNSData+zlib.h" +#import "GULMutableDictionary.h" +#import "GULNetwork.h" +#import "GULNetworkConstants.h" +#import "GULNetworkLoggerProtocol.h" +#import "GULNetworkMessageCode.h" +#import "GULNetworkURLSession.h" +#import "GULReachabilityChecker.h" +#import "GULUserDefaults.h" + +FOUNDATION_EXPORT double GoogleUtilitiesVersionNumber; +FOUNDATION_EXPORT const unsigned char GoogleUtilitiesVersionString[]; + diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig new file mode 100644 index 0000000..cacc27c --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.debug.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap new file mode 100644 index 0000000..491dd0a --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.modulemap @@ -0,0 +1,6 @@ +framework module GoogleUtilities { + umbrella header "GoogleUtilities-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig new file mode 100644 index 0000000..cacc27c --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/GoogleUtilities.release.xcconfig @@ -0,0 +1,15 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/GoogleUtilities +GCC_C_LANGUAGE_STANDARD = c99 +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +HEADER_SEARCH_PATHS = $(inherited) "${PODS_TARGET_SRCROOT}" +OTHER_LDFLAGS = $(inherited) -l"z" -framework "Security" -framework "SystemConfiguration" +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/GoogleUtilities +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist b/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist new file mode 100644 index 0000000..16e1da6 --- /dev/null +++ b/Pods/Target Support Files/GoogleUtilities/ResourceBundle-GoogleUtilities_Privacy-GoogleUtilities-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 8.0.2 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist b/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist new file mode 100644 index 0000000..2780533 --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m b/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m new file mode 100644 index 0000000..ab1f210 --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PromisesObjC : NSObject +@end +@implementation PodsDummy_PromisesObjC +@end diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h b/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h new file mode 100644 index 0000000..5b014a8 --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC-umbrella.h @@ -0,0 +1,36 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "FBLPromise+All.h" +#import "FBLPromise+Always.h" +#import "FBLPromise+Any.h" +#import "FBLPromise+Async.h" +#import "FBLPromise+Await.h" +#import "FBLPromise+Catch.h" +#import "FBLPromise+Delay.h" +#import "FBLPromise+Do.h" +#import "FBLPromise+Race.h" +#import "FBLPromise+Recover.h" +#import "FBLPromise+Reduce.h" +#import "FBLPromise+Retry.h" +#import "FBLPromise+Testing.h" +#import "FBLPromise+Then.h" +#import "FBLPromise+Timeout.h" +#import "FBLPromise+Validate.h" +#import "FBLPromise+Wrap.h" +#import "FBLPromise.h" +#import "FBLPromiseError.h" +#import "FBLPromises.h" + +FOUNDATION_EXPORT double FBLPromisesVersionNumber; +FOUNDATION_EXPORT const unsigned char FBLPromisesVersionString[]; + diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig b/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig new file mode 100644 index 0000000..132f10c --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC.debug.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap b/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap new file mode 100644 index 0000000..7d485cd --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC.modulemap @@ -0,0 +1,6 @@ +framework module FBLPromises { + umbrella header "PromisesObjC-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig b/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig new file mode 100644 index 0000000..132f10c --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/PromisesObjC.release.xcconfig @@ -0,0 +1,13 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC +DEFINES_MODULE = YES +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesObjC +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist b/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist new file mode 100644 index 0000000..1f1f0af --- /dev/null +++ b/Pods/Target Support Files/PromisesObjC/ResourceBundle-FBLPromises_Privacy-PromisesObjC-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift-Info.plist b/Pods/Target Support Files/PromisesSwift/PromisesSwift-Info.plist new file mode 100644 index 0000000..2780533 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift-dummy.m b/Pods/Target Support Files/PromisesSwift/PromisesSwift-dummy.m new file mode 100644 index 0000000..460baba --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_PromisesSwift : NSObject +@end +@implementation PodsDummy_PromisesSwift +@end diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift-prefix.pch b/Pods/Target Support Files/PromisesSwift/PromisesSwift-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift-umbrella.h b/Pods/Target Support Files/PromisesSwift/PromisesSwift-umbrella.h new file mode 100644 index 0000000..06b1212 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift-umbrella.h @@ -0,0 +1,16 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + + +FOUNDATION_EXPORT double PromisesVersionNumber; +FOUNDATION_EXPORT const unsigned char PromisesVersionString[]; + diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift.debug.xcconfig b/Pods/Target Support Files/PromisesSwift/PromisesSwift.debug.xcconfig new file mode 100644 index 0000000..cfaa023 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift.debug.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesSwift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift.modulemap b/Pods/Target Support Files/PromisesSwift/PromisesSwift.modulemap new file mode 100644 index 0000000..59800c6 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift.modulemap @@ -0,0 +1,6 @@ +framework module Promises { + umbrella header "PromisesSwift-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/PromisesSwift/PromisesSwift.release.xcconfig b/Pods/Target Support Files/PromisesSwift/PromisesSwift.release.xcconfig new file mode 100644 index 0000000..cfaa023 --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/PromisesSwift.release.xcconfig @@ -0,0 +1,16 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromisesSwift +FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/PromisesObjC" +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 +LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift +OTHER_LDFLAGS = $(inherited) -framework "FBLPromises" +OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromisesSwift +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/PromisesSwift/ResourceBundle-Promises_Privacy-PromisesSwift-Info.plist b/Pods/Target Support Files/PromisesSwift/ResourceBundle-Promises_Privacy-PromisesSwift-Info.plist new file mode 100644 index 0000000..1f1f0af --- /dev/null +++ b/Pods/Target Support Files/PromisesSwift/ResourceBundle-Promises_Privacy-PromisesSwift-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.4.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist b/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist new file mode 100644 index 0000000..b5d917c --- /dev/null +++ b/Pods/Target Support Files/nanopb/ResourceBundle-nanopb_Privacy-nanopb-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + BNDL + CFBundleShortVersionString + 3.30910.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/nanopb/nanopb-Info.plist b/Pods/Target Support Files/nanopb/nanopb-Info.plist new file mode 100644 index 0000000..e39b8ca --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + ${PODS_DEVELOPMENT_LANGUAGE} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + ${PRODUCT_BUNDLE_IDENTIFIER} + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.30910.0 + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + NSPrincipalClass + + + diff --git a/Pods/Target Support Files/nanopb/nanopb-dummy.m b/Pods/Target Support Files/nanopb/nanopb-dummy.m new file mode 100644 index 0000000..b3fa595 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb-dummy.m @@ -0,0 +1,5 @@ +#import +@interface PodsDummy_nanopb : NSObject +@end +@implementation PodsDummy_nanopb +@end diff --git a/Pods/Target Support Files/nanopb/nanopb-prefix.pch b/Pods/Target Support Files/nanopb/nanopb-prefix.pch new file mode 100644 index 0000000..beb2a24 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb-prefix.pch @@ -0,0 +1,12 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + diff --git a/Pods/Target Support Files/nanopb/nanopb-umbrella.h b/Pods/Target Support Files/nanopb/nanopb-umbrella.h new file mode 100644 index 0000000..07e77b3 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb-umbrella.h @@ -0,0 +1,26 @@ +#ifdef __OBJC__ +#import +#else +#ifndef FOUNDATION_EXPORT +#if defined(__cplusplus) +#define FOUNDATION_EXPORT extern "C" +#else +#define FOUNDATION_EXPORT extern +#endif +#endif +#endif + +#import "pb.h" +#import "pb_common.h" +#import "pb_decode.h" +#import "pb_encode.h" +#import "pb.h" +#import "pb_decode.h" +#import "pb_common.h" +#import "pb.h" +#import "pb_encode.h" +#import "pb_common.h" + +FOUNDATION_EXPORT double nanopbVersionNumber; +FOUNDATION_EXPORT const unsigned char nanopbVersionString[]; + diff --git a/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig b/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig new file mode 100644 index 0000000..b682973 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb.debug.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/Target Support Files/nanopb/nanopb.modulemap b/Pods/Target Support Files/nanopb/nanopb.modulemap new file mode 100644 index 0000000..e8d4b53 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb.modulemap @@ -0,0 +1,6 @@ +framework module nanopb { + umbrella header "nanopb-umbrella.h" + + export * + module * { export * } +} diff --git a/Pods/Target Support Files/nanopb/nanopb.release.xcconfig b/Pods/Target Support Files/nanopb/nanopb.release.xcconfig new file mode 100644 index 0000000..b682973 --- /dev/null +++ b/Pods/Target Support Files/nanopb/nanopb.release.xcconfig @@ -0,0 +1,12 @@ +CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO +CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/nanopb +GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 $(inherited) PB_FIELD_32BIT=1 PB_NO_PACKED_STRUCTS=1 PB_ENABLE_MALLOC=1 +PODS_BUILD_DIR = ${BUILD_DIR} +PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) +PODS_DEVELOPMENT_LANGUAGE = ${DEVELOPMENT_LANGUAGE} +PODS_ROOT = ${SRCROOT} +PODS_TARGET_SRCROOT = ${PODS_ROOT}/nanopb +PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates +PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} +SKIP_INSTALL = YES +USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES diff --git a/Pods/nanopb/LICENSE.txt b/Pods/nanopb/LICENSE.txt new file mode 100644 index 0000000..d11c9af --- /dev/null +++ b/Pods/nanopb/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2011 Petteri Aimonen + +This software is provided 'as-is', without any express or +implied warranty. In no event will the authors be held liable +for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any +purpose, including commercial applications, and to alter it and +redistribute it freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. diff --git a/Pods/nanopb/README.md b/Pods/nanopb/README.md new file mode 100644 index 0000000..1a73cdd --- /dev/null +++ b/Pods/nanopb/README.md @@ -0,0 +1,71 @@ +Nanopb - Protocol Buffers for Embedded Systems +============================================== + +[![Build Status](https://travis-ci.org/nanopb/nanopb.svg?branch=master)](https://travis-ci.org/nanopb/nanopb) + +Nanopb is a small code-size Protocol Buffers implementation in ansi C. It is +especially suitable for use in microcontrollers, but fits any memory +restricted system. + +* **Homepage:** https://jpa.kapsi.fi/nanopb/ +* **Documentation:** https://jpa.kapsi.fi/nanopb/docs/ +* **Downloads:** https://jpa.kapsi.fi/nanopb/download/ +* **Forum:** https://groups.google.com/forum/#!forum/nanopb + + + +Using the nanopb library +------------------------ +To use the nanopb library, you need to do two things: + +1. Compile your .proto files for nanopb, using `protoc`. +2. Include *pb_encode.c*, *pb_decode.c* and *pb_common.c* in your project. + +The easiest way to get started is to study the project in "examples/simple". +It contains a Makefile, which should work directly under most Linux systems. +However, for any other kind of build system, see the manual steps in +README.txt in that folder. + + + +Using the Protocol Buffers compiler (protoc) +-------------------------------------------- +The nanopb generator is implemented as a plugin for the Google's own `protoc` +compiler. This has the advantage that there is no need to reimplement the +basic parsing of .proto files. However, it does mean that you need the +Google's protobuf library in order to run the generator. + +If you have downloaded a binary package for nanopb (either Windows, Linux or +Mac OS X version), the `protoc` binary is included in the 'generator-bin' +folder. In this case, you are ready to go. Simply run this command: + + generator-bin/protoc --nanopb_out=. myprotocol.proto + +However, if you are using a git checkout or a plain source distribution, you +need to provide your own version of `protoc` and the Google's protobuf library. +On Linux, the necessary packages are `protobuf-compiler` and `python-protobuf`. +On Windows, you can either build Google's protobuf library from source or use +one of the binary distributions of it. In either case, if you use a separate +`protoc`, you need to manually give the path to nanopb generator: + + protoc --plugin=protoc-gen-nanopb=nanopb/generator/protoc-gen-nanopb ... + + + +Running the tests +----------------- +If you want to perform further development of the nanopb core, or to verify +its functionality using your compiler and platform, you'll want to run the +test suite. The build rules for the test suite are implemented using Scons, +so you need to have that installed (ex: `sudo apt install scons` on Ubuntu). To run the tests: + + cd tests + scons + +This will show the progress of various test cases. If the output does not +end in an error, the test cases were successful. + +Note: Mac OS X by default aliases 'clang' as 'gcc', while not actually +supporting the same command line options as gcc does. To run tests on +Mac OS X, use: "scons CC=clang CXX=clang". Same way can be used to run +tests with different compilers on any platform. diff --git a/Pods/nanopb/pb.h b/Pods/nanopb/pb.h new file mode 100644 index 0000000..2bd4568 --- /dev/null +++ b/Pods/nanopb/pb.h @@ -0,0 +1,599 @@ +/* Common parts of the nanopb library. Most of these are quite low-level + * stuff. For the high-level interface, see pb_encode.h and pb_decode.h. + */ + +#ifndef PB_H_INCLUDED +#define PB_H_INCLUDED + +/***************************************************************** + * Nanopb compilation time options. You can change these here by * + * uncommenting the lines, or on the compiler command line. * + *****************************************************************/ + +/* Enable support for dynamically allocated fields */ +/* #define PB_ENABLE_MALLOC 1 */ + +/* Define this if your CPU / compiler combination does not support + * unaligned memory access to packed structures. */ +/* #define PB_NO_PACKED_STRUCTS 1 */ + +/* Increase the number of required fields that are tracked. + * A compiler warning will tell if you need this. */ +/* #define PB_MAX_REQUIRED_FIELDS 256 */ + +/* Add support for tag numbers > 255 and fields larger than 255 bytes. */ +/* #define PB_FIELD_16BIT 1 */ + +/* Add support for tag numbers > 65536 and fields larger than 65536 bytes. */ +/* #define PB_FIELD_32BIT 1 */ + +/* Disable support for error messages in order to save some code space. */ +/* #define PB_NO_ERRMSG 1 */ + +/* Disable support for custom streams (support only memory buffers). */ +/* #define PB_BUFFER_ONLY 1 */ + +/* Switch back to the old-style callback function signature. + * This was the default until nanopb-0.2.1. */ +/* #define PB_OLD_CALLBACK_STYLE */ + + +/* Don't encode scalar arrays as packed. This is only to be used when + * the decoder on the receiving side cannot process packed scalar arrays. + * Such example is older protobuf.js. */ +/* #define PB_ENCODE_ARRAYS_UNPACKED 1 */ + +/****************************************************************** + * You usually don't need to change anything below this line. * + * Feel free to look around and use the defined macros, though. * + ******************************************************************/ + + +/* Version of the nanopb library. Just in case you want to check it in + * your own program. */ +#define NANOPB_VERSION nanopb-0.3.9.10 + +/* Include all the system headers needed by nanopb. You will need the + * definitions of the following: + * - strlen, memcpy, memset functions + * - [u]int_least8_t, uint_fast8_t, [u]int_least16_t, [u]int32_t, [u]int64_t + * - size_t + * - bool + * + * If you don't have the standard header files, you can instead provide + * a custom header that defines or includes all this. In that case, + * define PB_SYSTEM_HEADER to the path of this file. + */ +#ifdef PB_SYSTEM_HEADER +#include PB_SYSTEM_HEADER +#else +#include +#include +#include +#include + +#ifdef PB_ENABLE_MALLOC +#include +#endif +#endif + +/* Macro for defining packed structures (compiler dependent). + * This just reduces memory requirements, but is not required. + */ +#if defined(PB_NO_PACKED_STRUCTS) + /* Disable struct packing */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#elif defined(__GNUC__) || defined(__clang__) + /* For GCC and clang */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed __attribute__((packed)) +#elif defined(__ICCARM__) || defined(__CC_ARM) + /* For IAR ARM and Keil MDK-ARM compilers */ +# define PB_PACKED_STRUCT_START _Pragma("pack(push, 1)") +# define PB_PACKED_STRUCT_END _Pragma("pack(pop)") +# define pb_packed +#elif defined(_MSC_VER) && (_MSC_VER >= 1500) + /* For Microsoft Visual C++ */ +# define PB_PACKED_STRUCT_START __pragma(pack(push, 1)) +# define PB_PACKED_STRUCT_END __pragma(pack(pop)) +# define pb_packed +#else + /* Unknown compiler */ +# define PB_PACKED_STRUCT_START +# define PB_PACKED_STRUCT_END +# define pb_packed +#endif + +/* Handly macro for suppressing unreferenced-parameter compiler warnings. */ +#ifndef PB_UNUSED +#define PB_UNUSED(x) (void)(x) +#endif + +/* Compile-time assertion, used for checking compatible compilation options. + * If this does not work properly on your compiler, use + * #define PB_NO_STATIC_ASSERT to disable it. + * + * But before doing that, check carefully the error message / place where it + * comes from to see if the error has a real cause. Unfortunately the error + * message is not always very clear to read, but you can see the reason better + * in the place where the PB_STATIC_ASSERT macro was called. + */ +#ifndef PB_NO_STATIC_ASSERT +#ifndef PB_STATIC_ASSERT +#define PB_STATIC_ASSERT(COND,MSG) typedef char PB_STATIC_ASSERT_MSG(MSG, __LINE__, __COUNTER__)[(COND)?1:-1]; +#define PB_STATIC_ASSERT_MSG(MSG, LINE, COUNTER) PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) +#define PB_STATIC_ASSERT_MSG_(MSG, LINE, COUNTER) pb_static_assertion_##MSG##LINE##COUNTER +#endif +#else +#define PB_STATIC_ASSERT(COND,MSG) +#endif + +/* Number of required fields to keep track of. */ +#ifndef PB_MAX_REQUIRED_FIELDS +#define PB_MAX_REQUIRED_FIELDS 64 +#endif + +#if PB_MAX_REQUIRED_FIELDS < 64 +#error You should not lower PB_MAX_REQUIRED_FIELDS from the default value (64). +#endif + +/* List of possible field types. These are used in the autogenerated code. + * Least-significant 4 bits tell the scalar type + * Most-significant 4 bits specify repeated/required/packed etc. + */ + +typedef uint_least8_t pb_type_t; + +/**** Field data types ****/ + +/* Numeric types */ +#define PB_LTYPE_BOOL 0x00 /* bool */ +#define PB_LTYPE_VARINT 0x01 /* int32, int64, enum, bool */ +#define PB_LTYPE_UVARINT 0x02 /* uint32, uint64 */ +#define PB_LTYPE_SVARINT 0x03 /* sint32, sint64 */ +#define PB_LTYPE_FIXED32 0x04 /* fixed32, sfixed32, float */ +#define PB_LTYPE_FIXED64 0x05 /* fixed64, sfixed64, double */ + +/* Marker for last packable field type. */ +#define PB_LTYPE_LAST_PACKABLE 0x05 + +/* Byte array with pre-allocated buffer. + * data_size is the length of the allocated PB_BYTES_ARRAY structure. */ +#define PB_LTYPE_BYTES 0x06 + +/* String with pre-allocated buffer. + * data_size is the maximum length. */ +#define PB_LTYPE_STRING 0x07 + +/* Submessage + * submsg_fields is pointer to field descriptions */ +#define PB_LTYPE_SUBMESSAGE 0x08 + +/* Extension pseudo-field + * The field contains a pointer to pb_extension_t */ +#define PB_LTYPE_EXTENSION 0x09 + +/* Byte array with inline, pre-allocated byffer. + * data_size is the length of the inline, allocated buffer. + * This differs from PB_LTYPE_BYTES by defining the element as + * pb_byte_t[data_size] rather than pb_bytes_array_t. */ +#define PB_LTYPE_FIXED_LENGTH_BYTES 0x0A + +/* Number of declared LTYPES */ +#define PB_LTYPES_COUNT 0x0B +#define PB_LTYPE_MASK 0x0F + +/**** Field repetition rules ****/ + +#define PB_HTYPE_REQUIRED 0x00 +#define PB_HTYPE_OPTIONAL 0x10 +#define PB_HTYPE_REPEATED 0x20 +#define PB_HTYPE_ONEOF 0x30 +#define PB_HTYPE_MASK 0x30 + +/**** Field allocation types ****/ + +#define PB_ATYPE_STATIC 0x00 +#define PB_ATYPE_POINTER 0x80 +#define PB_ATYPE_CALLBACK 0x40 +#define PB_ATYPE_MASK 0xC0 + +#define PB_ATYPE(x) ((x) & PB_ATYPE_MASK) +#define PB_HTYPE(x) ((x) & PB_HTYPE_MASK) +#define PB_LTYPE(x) ((x) & PB_LTYPE_MASK) + +/* Data type used for storing sizes of struct fields + * and array counts. + */ +#if defined(PB_FIELD_32BIT) + typedef uint32_t pb_size_t; + typedef int32_t pb_ssize_t; +#elif defined(PB_FIELD_16BIT) + typedef uint_least16_t pb_size_t; + typedef int_least16_t pb_ssize_t; +#else + typedef uint_least8_t pb_size_t; + typedef int_least8_t pb_ssize_t; +#endif +#define PB_SIZE_MAX ((pb_size_t)-1) + +/* Data type for storing encoded data and other byte streams. + * This typedef exists to support platforms where uint8_t does not exist. + * You can regard it as equivalent on uint8_t on other platforms. + */ +typedef uint_least8_t pb_byte_t; + +/* This structure is used in auto-generated constants + * to specify struct fields. + * You can change field sizes if you need structures + * larger than 256 bytes or field tags larger than 256. + * The compiler should complain if your .proto has such + * structures. Fix that by defining PB_FIELD_16BIT or + * PB_FIELD_32BIT. + */ +PB_PACKED_STRUCT_START +typedef struct pb_field_s pb_field_t; +struct pb_field_s { + pb_size_t tag; + pb_type_t type; + pb_size_t data_offset; /* Offset of field data, relative to previous field. */ + pb_ssize_t size_offset; /* Offset of array size or has-boolean, relative to data */ + pb_size_t data_size; /* Data size in bytes for a single item */ + pb_size_t array_size; /* Maximum number of entries in array */ + + /* Field definitions for submessage + * OR default value for all other non-array, non-callback types + * If null, then field will zeroed. */ + const void *ptr; +} pb_packed; +PB_PACKED_STRUCT_END + +/* Make sure that the standard integer types are of the expected sizes. + * Otherwise fixed32/fixed64 fields can break. + * + * If you get errors here, it probably means that your stdint.h is not + * correct for your platform. + */ +#ifndef PB_WITHOUT_64BIT +PB_STATIC_ASSERT(sizeof(int64_t) == 2 * sizeof(int32_t), INT64_T_WRONG_SIZE) +PB_STATIC_ASSERT(sizeof(uint64_t) == 2 * sizeof(uint32_t), UINT64_T_WRONG_SIZE) +#endif + +/* This structure is used for 'bytes' arrays. + * It has the number of bytes in the beginning, and after that an array. + * Note that actual structs used will have a different length of bytes array. + */ +#define PB_BYTES_ARRAY_T(n) struct { pb_size_t size; pb_byte_t bytes[n]; } +#define PB_BYTES_ARRAY_T_ALLOCSIZE(n) ((size_t)n + offsetof(pb_bytes_array_t, bytes)) + +struct pb_bytes_array_s { + pb_size_t size; + pb_byte_t bytes[1]; +}; +typedef struct pb_bytes_array_s pb_bytes_array_t; + +/* This structure is used for giving the callback function. + * It is stored in the message structure and filled in by the method that + * calls pb_decode. + * + * The decoding callback will be given a limited-length stream + * If the wire type was string, the length is the length of the string. + * If the wire type was a varint/fixed32/fixed64, the length is the length + * of the actual value. + * The function may be called multiple times (especially for repeated types, + * but also otherwise if the message happens to contain the field multiple + * times.) + * + * The encoding callback will receive the actual output stream. + * It should write all the data in one call, including the field tag and + * wire type. It can write multiple fields. + * + * The callback can be null if you want to skip a field. + */ +typedef struct pb_istream_s pb_istream_t; +typedef struct pb_ostream_s pb_ostream_t; +typedef struct pb_callback_s pb_callback_t; +struct pb_callback_s { +#ifdef PB_OLD_CALLBACK_STYLE + /* Deprecated since nanopb-0.2.1 */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void *arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, const void *arg); + } funcs; +#else + /* New function signature, which allows modifying arg contents in callback. */ + union { + bool (*decode)(pb_istream_t *stream, const pb_field_t *field, void **arg); + bool (*encode)(pb_ostream_t *stream, const pb_field_t *field, void * const *arg); + } funcs; +#endif + + /* Free arg for use by callback */ + void *arg; +}; + +/* Wire types. Library user needs these only in encoder callbacks. */ +typedef enum { + PB_WT_VARINT = 0, + PB_WT_64BIT = 1, + PB_WT_STRING = 2, + PB_WT_32BIT = 5 +} pb_wire_type_t; + +/* Structure for defining the handling of unknown/extension fields. + * Usually the pb_extension_type_t structure is automatically generated, + * while the pb_extension_t structure is created by the user. However, + * if you want to catch all unknown fields, you can also create a custom + * pb_extension_type_t with your own callback. + */ +typedef struct pb_extension_type_s pb_extension_type_t; +typedef struct pb_extension_s pb_extension_t; +struct pb_extension_type_s { + /* Called for each unknown field in the message. + * If you handle the field, read off all of its data and return true. + * If you do not handle the field, do not read anything and return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*decode)(pb_istream_t *stream, pb_extension_t *extension, + uint32_t tag, pb_wire_type_t wire_type); + + /* Called once after all regular fields have been encoded. + * If you have something to write, do so and return true. + * If you do not have anything to write, just return true. + * If you run into an error, return false. + * Set to NULL for default handler. + */ + bool (*encode)(pb_ostream_t *stream, const pb_extension_t *extension); + + /* Free field for use by the callback. */ + const void *arg; +}; + +struct pb_extension_s { + /* Type describing the extension field. Usually you'll initialize + * this to a pointer to the automatically generated structure. */ + const pb_extension_type_t *type; + + /* Destination for the decoded data. This must match the datatype + * of the extension field. */ + void *dest; + + /* Pointer to the next extension handler, or NULL. + * If this extension does not match a field, the next handler is + * automatically called. */ + pb_extension_t *next; + + /* The decoder sets this to true if the extension was found. + * Ignored for encoding. */ + bool found; +}; + +/* Memory allocation functions to use. You can define pb_realloc and + * pb_free to custom functions if you want. */ +#ifdef PB_ENABLE_MALLOC +# ifndef pb_realloc +# define pb_realloc(ptr, size) realloc(ptr, size) +# endif +# ifndef pb_free +# define pb_free(ptr) free(ptr) +# endif +#endif + +/* This is used to inform about need to regenerate .pb.h/.pb.c files. */ +#define PB_PROTO_HEADER_VERSION 30 + +/* These macros are used to declare pb_field_t's in the constant array. */ +/* Size of a structure member, in bytes. */ +#define pb_membersize(st, m) (sizeof ((st*)0)->m) +/* Number of entries in an array. */ +#define pb_arraysize(st, m) (pb_membersize(st, m) / pb_membersize(st, m[0])) +/* Delta from start of one member to the start of another member. */ +#define pb_delta(st, m1, m2) ((int)offsetof(st, m1) - (int)offsetof(st, m2)) +/* Marks the end of the field list */ +#define PB_LAST_FIELD {0,(pb_type_t) 0,0,0,0,0,0} + +/* Macros for filling in the data_offset field */ +/* data_offset for first field in a message */ +#define PB_DATAOFFSET_FIRST(st, m1, m2) (offsetof(st, m1)) +/* data_offset for subsequent fields */ +#define PB_DATAOFFSET_OTHER(st, m1, m2) (offsetof(st, m1) - offsetof(st, m2) - pb_membersize(st, m2)) +/* data offset for subsequent fields inside an union (oneof) */ +#define PB_DATAOFFSET_UNION(st, m1, m2) (PB_SIZE_MAX) +/* Choose first/other based on m1 == m2 (deprecated, remains for backwards compatibility) */ +#define PB_DATAOFFSET_CHOOSE(st, m1, m2) (int)(offsetof(st, m1) == offsetof(st, m2) \ + ? PB_DATAOFFSET_FIRST(st, m1, m2) \ + : PB_DATAOFFSET_OTHER(st, m1, m2)) + +/* Required fields are the simplest. They just have delta (padding) from + * previous field end, and the size of the field. Pointer is used for + * submessages and default values. + */ +#define PB_REQUIRED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional fields add the delta to the has_ variable. */ +#define PB_OPTIONAL_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, \ + pb_delta(st, has_ ## m, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Repeated fields have a _count field and also the maximum number of entries. */ +#define PB_REPEATED_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | ltype, \ + fd, \ + pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), \ + pb_arraysize(st, m), ptr} + +/* Allocated fields carry the size of the actual data, not the pointer */ +#define PB_REQUIRED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Optional fields don't need a has_ variable, as information would be redundant */ +#define PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Same as optional fields*/ +#define PB_SINGULAR_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m[0]), 0, ptr} + +/* Repeated fields have a _count field and a pointer to array of pointers */ +#define PB_REPEATED_POINTER(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_REPEATED | ltype, \ + fd, pb_delta(st, m ## _count, m), \ + pb_membersize(st, m[0]), 0, ptr} + +/* Callbacks are much like required fields except with special datatype. */ +#define PB_REQUIRED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REQUIRED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_SINGULAR_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_OPTIONAL | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +#define PB_REPEATED_CALLBACK(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_CALLBACK | PB_HTYPE_REPEATED | ltype, \ + fd, 0, pb_membersize(st, m), 0, ptr} + +/* Optional extensions don't have the has_ field, as that would be redundant. + * Furthermore, the combination of OPTIONAL without has_ field is used + * for indicating proto3 style fields. Extensions exist in proto2 mode only, + * so they should be encoded according to proto2 rules. To avoid the conflict, + * extensions are marked as REQUIRED instead. + */ +#define PB_OPTEXT_STATIC(tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REQUIRED | ltype, \ + 0, \ + 0, \ + pb_membersize(st, m), 0, ptr} + +#define PB_OPTEXT_POINTER(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_POINTER(tag, st, m, fd, ltype, ptr) + +#define PB_OPTEXT_CALLBACK(tag, st, m, fd, ltype, ptr) \ + PB_OPTIONAL_CALLBACK(tag, st, m, fd, ltype, ptr) + +/* The mapping from protobuf types to LTYPEs is done using these macros. */ +#define PB_LTYPE_MAP_BOOL PB_LTYPE_BOOL +#define PB_LTYPE_MAP_BYTES PB_LTYPE_BYTES +#define PB_LTYPE_MAP_DOUBLE PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_ENUM PB_LTYPE_VARINT +#define PB_LTYPE_MAP_UENUM PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_FIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_FIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_FLOAT PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_INT32 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_INT64 PB_LTYPE_VARINT +#define PB_LTYPE_MAP_MESSAGE PB_LTYPE_SUBMESSAGE +#define PB_LTYPE_MAP_SFIXED32 PB_LTYPE_FIXED32 +#define PB_LTYPE_MAP_SFIXED64 PB_LTYPE_FIXED64 +#define PB_LTYPE_MAP_SINT32 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_SINT64 PB_LTYPE_SVARINT +#define PB_LTYPE_MAP_STRING PB_LTYPE_STRING +#define PB_LTYPE_MAP_UINT32 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_UINT64 PB_LTYPE_UVARINT +#define PB_LTYPE_MAP_EXTENSION PB_LTYPE_EXTENSION +#define PB_LTYPE_MAP_FIXED_LENGTH_BYTES PB_LTYPE_FIXED_LENGTH_BYTES + +/* This is the actual macro used in field descriptions. + * It takes these arguments: + * - Field tag number + * - Field type: BOOL, BYTES, DOUBLE, ENUM, UENUM, FIXED32, FIXED64, + * FLOAT, INT32, INT64, MESSAGE, SFIXED32, SFIXED64 + * SINT32, SINT64, STRING, UINT32, UINT64 or EXTENSION + * - Field rules: REQUIRED, OPTIONAL or REPEATED + * - Allocation: STATIC, CALLBACK or POINTER + * - Placement: FIRST or OTHER, depending on if this is the first field in structure. + * - Message name + * - Field name + * - Previous field name (or field name again for first field) + * - Pointer to default value or submsg fields. + */ + +#define PB_FIELD(tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ ## rules ## _ ## allocation(tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* Field description for repeated static fixed count fields.*/ +#define PB_REPEATED_FIXED_COUNT(tag, type, placement, message, field, prevfield, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_REPEATED | PB_LTYPE_MAP_ ## type, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + 0, \ + pb_membersize(message, field[0]), \ + pb_arraysize(message, field), ptr} + +/* Field description for oneof fields. This requires taking into account the + * union name also, that's why a separate set of macros is needed. + */ +#define PB_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m), 0, ptr} + +#define PB_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, u.m), \ + pb_membersize(st, u.m[0]), 0, ptr} + +#define PB_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, union_name.field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +#define PB_ANONYMOUS_ONEOF_STATIC(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_STATIC | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_POINTER(u, tag, st, m, fd, ltype, ptr) \ + {tag, PB_ATYPE_POINTER | PB_HTYPE_ONEOF | ltype, \ + fd, pb_delta(st, which_ ## u, m), \ + pb_membersize(st, m[0]), 0, ptr} + +#define PB_ANONYMOUS_ONEOF_FIELD(union_name, tag, type, rules, allocation, placement, message, field, prevfield, ptr) \ + PB_ANONYMOUS_ONEOF_ ## allocation(union_name, tag, message, field, \ + PB_DATAOFFSET_ ## placement(message, field, prevfield), \ + PB_LTYPE_MAP_ ## type, ptr) + +/* These macros are used for giving out error messages. + * They are mostly a debugging aid; the main error information + * is the true/false return value from functions. + * Some code space can be saved by disabling the error + * messages if not used. + * + * PB_SET_ERROR() sets the error message if none has been set yet. + * msg must be a constant string literal. + * PB_GET_ERROR() always returns a pointer to a string. + * PB_RETURN_ERROR() sets the error and returns false from current + * function. + */ +#ifdef PB_NO_ERRMSG +#define PB_SET_ERROR(stream, msg) PB_UNUSED(stream) +#define PB_GET_ERROR(stream) "(errmsg disabled)" +#else +#define PB_SET_ERROR(stream, msg) (stream->errmsg = (stream)->errmsg ? (stream)->errmsg : (msg)) +#define PB_GET_ERROR(stream) ((stream)->errmsg ? (stream)->errmsg : "(none)") +#endif + +#define PB_RETURN_ERROR(stream, msg) return PB_SET_ERROR(stream, msg), false + +#endif diff --git a/Pods/nanopb/pb_common.c b/Pods/nanopb/pb_common.c new file mode 100644 index 0000000..5799db2 --- /dev/null +++ b/Pods/nanopb/pb_common.c @@ -0,0 +1,106 @@ +/* pb_common.c: Common support functions for pb_encode.c and pb_decode.c. + * + * 2014 Petteri Aimonen + */ + +#include "pb_common.h" + +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct) +{ + iter->start = fields; + iter->pos = fields; + iter->required_field_index = 0; + iter->dest_struct = dest_struct; + + if (!dest_struct) + { + iter->pData = NULL; + iter->pSize = NULL; + } + else + { + iter->pData = (char*)dest_struct + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + } + + return (iter->pos->tag != 0); +} + +bool pb_field_iter_next(pb_field_iter_t *iter) +{ + const pb_field_t *prev_field = iter->pos; + + if (prev_field->tag == 0) + { + /* Handle empty message types, where the first field is already the terminator. + * In other cases, the iter->pos never points to the terminator. */ + return false; + } + + iter->pos++; + + if (iter->pos->tag == 0) + { + /* Wrapped back to beginning, reinitialize */ + (void)pb_field_iter_begin(iter, iter->start, iter->dest_struct); + return false; + } + else + { + /* Increment the pointers based on previous field size */ + size_t prev_size = prev_field->data_size; + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_ONEOF && + PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF && + iter->pos->data_offset == PB_SIZE_MAX) + { + /* Don't advance pointers inside unions */ + return true; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_STATIC && + PB_HTYPE(prev_field->type) == PB_HTYPE_REPEATED) + { + /* In static arrays, the data_size tells the size of a single entry and + * array_size is the number of entries */ + prev_size *= prev_field->array_size; + } + else if (PB_ATYPE(prev_field->type) == PB_ATYPE_POINTER) + { + /* Pointer fields always have a constant size in the main structure. + * The data_size only applies to the dynamically allocated area. */ + prev_size = sizeof(void*); + } + + if (PB_HTYPE(prev_field->type) == PB_HTYPE_REQUIRED) + { + /* Count the required fields, in order to check their presence in the + * decoder. */ + iter->required_field_index++; + } + + iter->pData = (char*)iter->pData + prev_size + iter->pos->data_offset; + iter->pSize = (char*)iter->pData + iter->pos->size_offset; + return true; + } +} + +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag) +{ + const pb_field_t *start = iter->pos; + + do { + if (iter->pos->tag == tag && + PB_LTYPE(iter->pos->type) != PB_LTYPE_EXTENSION) + { + /* Found the wanted field */ + return true; + } + + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + /* Searched all the way back to start, and found nothing. */ + return false; +} + + diff --git a/Pods/nanopb/pb_common.h b/Pods/nanopb/pb_common.h new file mode 100644 index 0000000..60b3d37 --- /dev/null +++ b/Pods/nanopb/pb_common.h @@ -0,0 +1,42 @@ +/* pb_common.h: Common support functions for pb_encode.c and pb_decode.c. + * These functions are rarely needed by applications directly. + */ + +#ifndef PB_COMMON_H_INCLUDED +#define PB_COMMON_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Iterator for pb_field_t list */ +struct pb_field_iter_s { + const pb_field_t *start; /* Start of the pb_field_t array */ + const pb_field_t *pos; /* Current position of the iterator */ + unsigned required_field_index; /* Zero-based index that counts only the required fields */ + void *dest_struct; /* Pointer to start of the structure */ + void *pData; /* Pointer to current field value */ + void *pSize; /* Pointer to count/has field */ +}; +typedef struct pb_field_iter_s pb_field_iter_t; + +/* Initialize the field iterator structure to beginning. + * Returns false if the message type is empty. */ +bool pb_field_iter_begin(pb_field_iter_t *iter, const pb_field_t *fields, void *dest_struct); + +/* Advance the iterator to the next field. + * Returns false when the iterator wraps back to the first field. */ +bool pb_field_iter_next(pb_field_iter_t *iter); + +/* Advance the iterator until it points at a field with the given tag. + * Returns false if no such field exists. */ +bool pb_field_iter_find(pb_field_iter_t *iter, uint32_t tag); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif + diff --git a/Pods/nanopb/pb_decode.c b/Pods/nanopb/pb_decode.c new file mode 100644 index 0000000..ebf7e85 --- /dev/null +++ b/Pods/nanopb/pb_decode.c @@ -0,0 +1,1570 @@ +/* pb_decode.c -- decode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +#include "pb.h" +#include "pb_decode.h" +#include "pb_common.h" + +/************************************** + * Declarations internal to this file * + **************************************/ + +typedef bool (*pb_decoder_t)(pb_istream_t *stream, const pb_field_t *field, void *dest) checkreturn; + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size); +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension); +static bool checkreturn default_extension_decoder(pb_istream_t *stream, pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type); +static bool checkreturn decode_extension(pb_istream_t *stream, uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter); +static bool checkreturn find_extension_field(pb_field_iter_t *iter); +static void pb_field_set_to_default(pb_field_iter_t *iter); +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct); +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof); +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest); +static bool checkreturn pb_skip_varint(pb_istream_t *stream); +static bool checkreturn pb_skip_string(pb_istream_t *stream); + +#ifdef PB_ENABLE_MALLOC +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size); +static bool checkreturn pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter); +static void pb_release_single_field(const pb_field_iter_t *iter); +#endif + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field decoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_decoder_t PB_DECODERS[PB_LTYPES_COUNT] = { + &pb_dec_bool, + &pb_dec_varint, + &pb_dec_uvarint, + &pb_dec_svarint, + &pb_dec_fixed32, + &pb_dec_fixed64, + + &pb_dec_bytes, + &pb_dec_string, + &pb_dec_submessage, + NULL, /* extensions */ + &pb_dec_fixed_length_bytes +}; + +/******************************* + * pb_istream_t implementation * + *******************************/ + +static bool checkreturn buf_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + size_t i; + const pb_byte_t *source = (const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + count; + + if (buf != NULL) + { + for (i = 0; i < count; i++) + buf[i] = source[i]; + } + + return true; +} + +bool checkreturn pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count) +{ + if (count == 0) + return true; + +#ifndef PB_BUFFER_ONLY + if (buf == NULL && stream->callback != buf_read) + { + /* Skip input bytes */ + pb_byte_t tmp[16]; + while (count > 16) + { + if (!pb_read(stream, tmp, 16)) + return false; + + count -= 16; + } + + return pb_read(stream, tmp, count); + } +#endif + + if (stream->bytes_left < count) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!buf_read(stream, buf, count)) + return false; +#endif + + stream->bytes_left -= count; + return true; +} + +/* Read a single byte from input stream. buf may not be NULL. + * This is an optimization for the varint decoding. */ +static bool checkreturn pb_readbyte(pb_istream_t *stream, pb_byte_t *buf) +{ + if (stream->bytes_left == 0) + PB_RETURN_ERROR(stream, "end-of-stream"); + +#ifndef PB_BUFFER_ONLY + if (!stream->callback(stream, buf, 1)) + PB_RETURN_ERROR(stream, "io error"); +#else + *buf = *(const pb_byte_t*)stream->state; + stream->state = (pb_byte_t*)stream->state + 1; +#endif + + stream->bytes_left--; + + return true; +} + +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize) +{ + pb_istream_t stream; + /* Cast away the const from buf without a compiler error. We are + * careful to use it only in a const manner in the callbacks. + */ + union { + void *state; + const void *c_state; + } state; +#ifdef PB_BUFFER_ONLY + stream.callback = NULL; +#else + stream.callback = &buf_read; +#endif + state.c_state = buf; + stream.state = state.state; + stream.bytes_left = bufsize; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +/******************** + * Helper functions * + ********************/ + +static bool checkreturn pb_decode_varint32_eof(pb_istream_t *stream, uint32_t *dest, bool *eof) +{ + pb_byte_t byte; + uint32_t result; + + if (!pb_readbyte(stream, &byte)) + { + if (stream->bytes_left == 0) + { + if (eof) + { + *eof = true; + } + } + + return false; + } + + if ((byte & 0x80) == 0) + { + /* Quick case, 1 byte value */ + result = byte; + } + else + { + /* Multibyte case */ + uint_fast8_t bitpos = 7; + result = byte & 0x7F; + + do + { + if (!pb_readbyte(stream, &byte)) + return false; + + if (bitpos >= 32) + { + /* Note: The varint could have trailing 0x80 bytes, or 0xFF for negative. */ + uint8_t sign_extension = (bitpos < 63) ? 0xFF : 0x01; + + if ((byte & 0x7F) != 0x00 && ((result >> 31) == 0 || byte != sign_extension)) + { + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + else + { + result |= (uint32_t)(byte & 0x7F) << bitpos; + } + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + if (bitpos == 35 && (byte & 0x70) != 0) + { + /* The last byte was at bitpos=28, so only bottom 4 bits fit. */ + PB_RETURN_ERROR(stream, "varint overflow"); + } + } + + *dest = result; + return true; +} + +bool checkreturn pb_decode_varint32(pb_istream_t *stream, uint32_t *dest) +{ + return pb_decode_varint32_eof(stream, dest, NULL); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_decode_varint(pb_istream_t *stream, uint64_t *dest) +{ + pb_byte_t byte; + uint_fast8_t bitpos = 0; + uint64_t result = 0; + + do + { + if (bitpos >= 64) + PB_RETURN_ERROR(stream, "varint overflow"); + + if (!pb_readbyte(stream, &byte)) + return false; + + result |= (uint64_t)(byte & 0x7F) << bitpos; + bitpos = (uint_fast8_t)(bitpos + 7); + } while (byte & 0x80); + + *dest = result; + return true; +} +#endif + +bool checkreturn pb_skip_varint(pb_istream_t *stream) +{ + pb_byte_t byte; + do + { + if (!pb_read(stream, &byte, 1)) + return false; + } while (byte & 0x80); + return true; +} + +bool checkreturn pb_skip_string(pb_istream_t *stream) +{ + uint32_t length; + if (!pb_decode_varint32(stream, &length)) + return false; + + return pb_read(stream, NULL, length); +} + +bool checkreturn pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof) +{ + uint32_t temp; + *eof = false; + *wire_type = (pb_wire_type_t) 0; + *tag = 0; + + if (!pb_decode_varint32_eof(stream, &temp, eof)) + { + return false; + } + + if (temp == 0) + { + *eof = true; /* Special feature: allow 0-terminated messages. */ + return false; + } + + *tag = temp >> 3; + *wire_type = (pb_wire_type_t)(temp & 7); + return true; +} + +bool checkreturn pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type) +{ + switch (wire_type) + { + case PB_WT_VARINT: return pb_skip_varint(stream); + case PB_WT_64BIT: return pb_read(stream, NULL, 8); + case PB_WT_STRING: return pb_skip_string(stream); + case PB_WT_32BIT: return pb_read(stream, NULL, 4); + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Read a raw value to buffer, for the purpose of passing it to callback as + * a substream. Size is maximum size on call, and actual size on return. + */ +static bool checkreturn read_raw_value(pb_istream_t *stream, pb_wire_type_t wire_type, pb_byte_t *buf, size_t *size) +{ + size_t max_size = *size; + switch (wire_type) + { + case PB_WT_VARINT: + *size = 0; + do + { + (*size)++; + if (*size > max_size) return false; + if (!pb_read(stream, buf, 1)) return false; + } while (*buf++ & 0x80); + return true; + + case PB_WT_64BIT: + *size = 8; + return pb_read(stream, buf, 8); + + case PB_WT_32BIT: + *size = 4; + return pb_read(stream, buf, 4); + + case PB_WT_STRING: + /* Calling read_raw_value with a PB_WT_STRING is an error. + * Explicitly handle this case and fallthrough to default to avoid + * compiler warnings. + */ + + default: PB_RETURN_ERROR(stream, "invalid wire_type"); + } +} + +/* Decode string length from stream and return a substream with limited length. + * Remember to close the substream using pb_close_string_substream(). + */ +bool checkreturn pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + uint32_t size; + if (!pb_decode_varint32(stream, &size)) + return false; + + *substream = *stream; + if (substream->bytes_left < size) + PB_RETURN_ERROR(stream, "parent stream too short"); + + substream->bytes_left = size; + stream->bytes_left -= size; + return true; +} + +bool checkreturn pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream) +{ + if (substream->bytes_left) { + if (!pb_read(substream, NULL, substream->bytes_left)) + return false; + } + + stream->state = substream->state; + +#ifndef PB_NO_ERRMSG + stream->errmsg = substream->errmsg; +#endif + return true; +} + +/************************* + * Decode a single field * + *************************/ + +static bool checkreturn decode_static_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_OPTIONAL: + if (iter->pSize != iter->pData) + *(bool*)iter->pSize = true; + return func(stream, iter->pos, iter->pData); + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + + pb_istream_t substream; + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left > 0 && *size < iter->pos->array_size) + { + void *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + (*size)++; + } + + if (substream.bytes_left != 0) + PB_RETURN_ERROR(stream, "array overflow"); + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Repeated field */ + pb_size_t *size = (pb_size_t*)iter->pSize; + char *pItem = (char*)iter->pData + iter->pos->data_size * (*size); + + if ((*size)++ >= iter->pos->array_size) + PB_RETURN_ERROR(stream, "array overflow"); + + return func(stream, iter->pos, pItem); + } + + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(pb_size_t*)iter->pSize != iter->pos->tag) + { + /* We memset to zero so that any callbacks are set to NULL. + * This is because the callbacks might otherwise have values + * from some other union field. */ + memset(iter->pData, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t*)iter->pos->ptr, iter->pData); + } + *(pb_size_t*)iter->pSize = iter->pos->tag; + + return func(stream, iter->pos, iter->pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +#ifdef PB_ENABLE_MALLOC +/* Allocate storage for the field and store the pointer at iter->pData. + * array_size is the number of entries to reserve in an array. + * Zero size is not allowed, use pb_free() for releasing. + */ +static bool checkreturn allocate_field(pb_istream_t *stream, void *pData, size_t data_size, size_t array_size) +{ + void *ptr = *(void**)pData; + + if (data_size == 0 || array_size == 0) + PB_RETURN_ERROR(stream, "invalid size"); + +#ifdef __AVR__ + /* Workaround for AVR libc bug 53284: http://savannah.nongnu.org/bugs/?53284 + * Realloc to size of 1 byte can cause corruption of the malloc structures. + */ + if (data_size == 1 && array_size == 1) + { + data_size = 2; + } +#endif + + /* Check for multiplication overflows. + * This code avoids the costly division if the sizes are small enough. + * Multiplication is safe as long as only half of bits are set + * in either multiplicand. + */ + { + const size_t check_limit = (size_t)1 << (sizeof(size_t) * 4); + if (data_size >= check_limit || array_size >= check_limit) + { + const size_t size_max = (size_t)-1; + if (size_max / array_size < data_size) + { + PB_RETURN_ERROR(stream, "size too large"); + } + } + } + + /* Allocate new or expand previous allocation */ + /* Note: on failure the old pointer will remain in the structure, + * the message must be freed by caller also on error return. */ + ptr = pb_realloc(ptr, array_size * data_size); + if (ptr == NULL) + PB_RETURN_ERROR(stream, "realloc failed"); + + *(void**)pData = ptr; + return true; +} + +/* Clear a newly allocated item in case it contains a pointer, or is a submessage. */ +static void initialize_pointer_field(void *pItem, pb_field_iter_t *iter) +{ + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_STRING || + PB_LTYPE(iter->pos->type) == PB_LTYPE_BYTES) + { + *(void**)pItem = NULL; + } + else if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* We memset to zero so that any callbacks are set to NULL. + * Then set any default values. */ + memset(pItem, 0, iter->pos->data_size); + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, pItem); + } +} +#endif + +static bool checkreturn decode_pointer_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifndef PB_ENABLE_MALLOC + PB_UNUSED(wire_type); + PB_UNUSED(iter); + PB_RETURN_ERROR(stream, "no malloc support"); +#else + pb_type_t type; + pb_decoder_t func; + + type = iter->pos->type; + func = PB_DECODERS[PB_LTYPE(type)]; + + switch (PB_HTYPE(type)) + { + case PB_HTYPE_REQUIRED: + case PB_HTYPE_OPTIONAL: + case PB_HTYPE_ONEOF: + if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && + *(void**)iter->pData != NULL) + { + /* Duplicate field, have to release the old allocation first. */ + pb_release_single_field(iter); + } + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = iter->pos->tag; + } + + if (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES) + { + return func(stream, iter->pos, iter->pData); + } + else + { + if (!allocate_field(stream, iter->pData, iter->pos->data_size, 1)) + return false; + + initialize_pointer_field(*(void**)iter->pData, iter); + return func(stream, iter->pos, *(void**)iter->pData); + } + + case PB_HTYPE_REPEATED: + if (wire_type == PB_WT_STRING + && PB_LTYPE(type) <= PB_LTYPE_LAST_PACKABLE) + { + /* Packed array, multiple items come in at once. */ + bool status = true; + pb_size_t *size = (pb_size_t*)iter->pSize; + size_t allocated_size = *size; + void *pItem; + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + while (substream.bytes_left) + { + if (*size == PB_SIZE_MAX) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = "too many array entries"; +#endif + status = false; + break; + } + + if ((size_t)*size + 1 > allocated_size) + { + /* Allocate more storage. This tries to guess the + * number of remaining entries. Round the division + * upwards. */ + size_t remain = (substream.bytes_left - 1) / iter->pos->data_size + 1; + if (remain < PB_SIZE_MAX - allocated_size) + allocated_size += remain; + else + allocated_size += 1; + + if (!allocate_field(&substream, iter->pData, iter->pos->data_size, allocated_size)) + { + status = false; + break; + } + } + + /* Decode the array entry */ + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + if (pItem == NULL) + { + /* Shouldn't happen, but satisfies static analyzers */ + status = false; + break; + } + initialize_pointer_field(pItem, iter); + if (!func(&substream, iter->pos, pItem)) + { + status = false; + break; + } + + (*size)++; + } + if (!pb_close_string_substream(stream, &substream)) + return false; + + return status; + } + else + { + /* Normal repeated field, i.e. only one item at a time. */ + pb_size_t *size = (pb_size_t*)iter->pSize; + void *pItem; + + if (*size == PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "too many array entries"); + + if (!allocate_field(stream, iter->pData, iter->pos->data_size, (size_t)(*size + 1))) + return false; + + pItem = *(char**)iter->pData + iter->pos->data_size * (*size); + (*size)++; + initialize_pointer_field(pItem, iter); + return func(stream, iter->pos, pItem); + } + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +#endif +} + +static bool checkreturn decode_callback_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_callback_t *pCallback = (pb_callback_t*)iter->pData; +#ifdef PB_OLD_CALLBACK_STYLE + void *arg; +#else + void **arg; +#endif + + if (pCallback == NULL || pCallback->funcs.decode == NULL) + return pb_skip_field(stream, wire_type); + +#ifdef PB_OLD_CALLBACK_STYLE + arg = pCallback->arg; +#else + arg = &(pCallback->arg); +#endif + + if (wire_type == PB_WT_STRING) + { + pb_istream_t substream; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + do + { + if (!pCallback->funcs.decode(&substream, iter->pos, arg)) + PB_RETURN_ERROR(stream, "callback failed"); + } while (substream.bytes_left); + + if (!pb_close_string_substream(stream, &substream)) + return false; + + return true; + } + else + { + /* Copy the single scalar value to stack. + * This is required so that we can limit the stream length, + * which in turn allows to use same callback for packed and + * not-packed fields. */ + pb_istream_t substream; + pb_byte_t buffer[10]; + size_t size = sizeof(buffer); + + if (!read_raw_value(stream, wire_type, buffer, &size)) + return false; + substream = pb_istream_from_buffer(buffer, size); + + return pCallback->funcs.decode(&substream, iter->pos, arg); + } +} + +static bool checkreturn decode_field(pb_istream_t *stream, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ +#ifdef PB_ENABLE_MALLOC + /* When decoding an oneof field, check if there is old data that must be + * released first. */ + if (PB_HTYPE(iter->pos->type) == PB_HTYPE_ONEOF) + { + if (!pb_release_union_field(stream, iter)) + return false; + } +#endif + + switch (PB_ATYPE(iter->pos->type)) + { + case PB_ATYPE_STATIC: + return decode_static_field(stream, wire_type, iter); + + case PB_ATYPE_POINTER: + return decode_pointer_field(stream, wire_type, iter); + + case PB_ATYPE_CALLBACK: + return decode_callback_field(stream, wire_type, iter); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +static void iter_from_extension(pb_field_iter_t *iter, pb_extension_t *extension) +{ + /* Fake a field iterator for the extension field. + * It is not actually safe to advance this iterator, but decode_field + * will not even try to. */ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + (void)pb_field_iter_begin(iter, field, extension->dest); + iter->pData = extension->dest; + iter->pSize = &extension->found; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + iter->pData = &extension->dest; + } +} + +/* Default handler for extension fields. Expects a pb_field_t structure + * in extension->type->arg. */ +static bool checkreturn default_extension_decoder(pb_istream_t *stream, + pb_extension_t *extension, uint32_t tag, pb_wire_type_t wire_type) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + pb_field_iter_t iter; + + if (field->tag != tag) + return true; + + iter_from_extension(&iter, extension); + extension->found = true; + return decode_field(stream, wire_type, &iter); +} + +/* Try to decode an unknown field as an extension field. Tries each extension + * decoder in turn, until one of them handles the field or loop ends. */ +static bool checkreturn decode_extension(pb_istream_t *stream, + uint32_t tag, pb_wire_type_t wire_type, pb_field_iter_t *iter) +{ + pb_extension_t *extension = *(pb_extension_t* const *)iter->pData; + size_t pos = stream->bytes_left; + + while (extension != NULL && pos == stream->bytes_left) + { + bool status; + if (extension->type->decode) + status = extension->type->decode(stream, extension, tag, wire_type); + else + status = default_extension_decoder(stream, extension, tag, wire_type); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/* Step through the iterator until an extension field is found or until all + * entries have been checked. There can be only one extension field per + * message. Returns false if no extension field is found. */ +static bool checkreturn find_extension_field(pb_field_iter_t *iter) +{ + const pb_field_t *start = iter->pos; + + do { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_EXTENSION) + return true; + (void)pb_field_iter_next(iter); + } while (iter->pos != start); + + return false; +} + +/* Initialize message fields to default values, recursively */ +static void pb_field_set_to_default(pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + pb_extension_t *ext = *(pb_extension_t* const *)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + ext->found = false; + iter_from_extension(&ext_iter, ext); + pb_field_set_to_default(&ext_iter); + ext = ext->next; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + bool init_data = true; + if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && iter->pSize != iter->pData) + { + /* Set has_field to false. Still initialize the optional field + * itself also. */ + *(bool*)iter->pSize = false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* REPEATED: Set array count to 0, no need to initialize contents. + ONEOF: Set which_field to 0. */ + *(pb_size_t*)iter->pSize = 0; + init_data = false; + } + + if (init_data) + { + if (PB_LTYPE(iter->pos->type) == PB_LTYPE_SUBMESSAGE) + { + /* Initialize submessage to defaults */ + pb_message_set_to_defaults((const pb_field_t *) iter->pos->ptr, iter->pData); + } + else if (iter->pos->ptr != NULL) + { + /* Initialize to default value */ + memcpy(iter->pData, iter->pos->ptr, iter->pos->data_size); + } + else + { + /* Initialize to zeros */ + memset(iter->pData, 0, iter->pos->data_size); + } + } + } + else if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL. */ + *(void**)iter->pData = NULL; + + /* Initialize array count to 0. */ + if (PB_HTYPE(type) == PB_HTYPE_REPEATED || + PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + *(pb_size_t*)iter->pSize = 0; + } + } + else if (PB_ATYPE(type) == PB_ATYPE_CALLBACK) + { + /* Don't overwrite callback */ + } +} + +static void pb_message_set_to_defaults(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_field_set_to_default(&iter); + } while (pb_field_iter_next(&iter)); +} + +/********************* + * Decode all fields * + *********************/ + +bool checkreturn pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + uint32_t fields_seen[(PB_MAX_REQUIRED_FIELDS + 31) / 32] = {0, 0}; + const uint32_t allbits = ~(uint32_t)0; + uint32_t extension_range_start = 0; + pb_field_iter_t iter; + + /* 'fixed_count_field' and 'fixed_count_size' track position of a repeated fixed + * count field. This can only handle _one_ repeated fixed count field that + * is unpacked and unordered among other (non repeated fixed count) fields. + */ + const pb_field_t *fixed_count_field = NULL; + pb_size_t fixed_count_size = 0; + + /* Return value ignored, as empty message types will be correctly handled by + * pb_field_iter_find() anyway. */ + (void)pb_field_iter_begin(&iter, fields, dest_struct); + + while (stream->bytes_left) + { + uint32_t tag; + pb_wire_type_t wire_type; + bool eof; + + if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) + { + if (eof) + break; + else + return false; + } + + if (!pb_field_iter_find(&iter, tag)) + { + /* No match found, check if it matches an extension. */ + if (tag >= extension_range_start) + { + if (!find_extension_field(&iter)) + extension_range_start = (uint32_t)-1; + else + extension_range_start = iter.pos->tag; + + if (tag >= extension_range_start) + { + size_t pos = stream->bytes_left; + + if (!decode_extension(stream, tag, wire_type, &iter)) + return false; + + if (pos != stream->bytes_left) + { + /* The field was handled */ + continue; + } + } + } + + /* No match found, skip data */ + if (!pb_skip_field(stream, wire_type)) + return false; + continue; + } + + /* If a repeated fixed count field was found, get size from + * 'fixed_count_field' as there is no counter contained in the struct. + */ + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REPEATED + && iter.pSize == iter.pData) + { + if (fixed_count_field != iter.pos) { + /* If the new fixed count field does not match the previous one, + * check that the previous one is NULL or that it finished + * receiving all the expected data. + */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + fixed_count_field = iter.pos; + fixed_count_size = 0; + } + + iter.pSize = &fixed_count_size; + } + + if (PB_HTYPE(iter.pos->type) == PB_HTYPE_REQUIRED + && iter.required_field_index < PB_MAX_REQUIRED_FIELDS) + { + uint32_t tmp = ((uint32_t)1 << (iter.required_field_index & 31)); + fields_seen[iter.required_field_index >> 5] |= tmp; + } + + if (!decode_field(stream, wire_type, &iter)) + return false; + } + + /* Check that all elements of the last decoded fixed count field were present. */ + if (fixed_count_field != NULL && + fixed_count_size != fixed_count_field->array_size) + { + PB_RETURN_ERROR(stream, "wrong size for fixed count field"); + } + + /* Check that all required fields were present. */ + { + /* First figure out the number of required fields by + * seeking to the end of the field array. Usually we + * are already close to end after decoding. + */ + unsigned req_field_count; + pb_type_t last_type; + unsigned i; + do { + req_field_count = iter.required_field_index; + last_type = iter.pos->type; + } while (pb_field_iter_next(&iter)); + + /* Fixup if last field was also required. */ + if (PB_HTYPE(last_type) == PB_HTYPE_REQUIRED && iter.pos->tag != 0) + req_field_count++; + + if (req_field_count > PB_MAX_REQUIRED_FIELDS) + req_field_count = PB_MAX_REQUIRED_FIELDS; + + if (req_field_count > 0) + { + /* Check the whole words */ + for (i = 0; i < (req_field_count >> 5); i++) + { + if (fields_seen[i] != allbits) + PB_RETURN_ERROR(stream, "missing required field"); + } + + /* Check the remaining bits (if any) */ + if ((req_field_count & 31) != 0) + { + if (fields_seen[req_field_count >> 5] != + (allbits >> (32 - (req_field_count & 31)))) + { + PB_RETURN_ERROR(stream, "missing required field"); + } + } + } + } + + return true; +} + +bool checkreturn pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + bool status; + pb_message_set_to_defaults(fields, dest_struct); + status = pb_decode_noinit(stream, fields, dest_struct); + +#ifdef PB_ENABLE_MALLOC + if (!status) + pb_release(fields, dest_struct); +#endif + + return status; +} + +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode_noinit(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + pb_istream_t substream; + bool status; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + status = pb_decode(&substream, fields, dest_struct); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct) +{ + /* This behaviour will be separated in nanopb-0.4.0, see issue #278. */ + return pb_decode(stream, fields, dest_struct); +} + +#ifdef PB_ENABLE_MALLOC +/* Given an oneof field, if there has already been a field inside this oneof, + * release it before overwriting with a different one. */ +static bool pb_release_union_field(pb_istream_t *stream, pb_field_iter_t *iter) +{ + pb_size_t old_tag = *(pb_size_t*)iter->pSize; /* Previous which_ value */ + pb_size_t new_tag = iter->pos->tag; /* New which_ value */ + + if (old_tag == 0) + return true; /* Ok, no old data in union */ + + if (old_tag == new_tag) + return true; /* Ok, old data is of same type => merge */ + + /* Release old data. The find can fail if the message struct contains + * invalid data. */ + if (!pb_field_iter_find(iter, old_tag)) + PB_RETURN_ERROR(stream, "invalid union tag"); + + pb_release_single_field(iter); + + /* Restore iterator to where it should be. + * This shouldn't fail unless the pb_field_t structure is corrupted. */ + if (!pb_field_iter_find(iter, new_tag)) + PB_RETURN_ERROR(stream, "iterator error"); + + if (PB_ATYPE(iter->pos->type) == PB_ATYPE_POINTER) + { + /* Initialize the pointer to NULL to make sure it is valid + * even in case of error return. */ + *(void**)iter->pData = NULL; + } + + return true; +} + +static void pb_release_single_field(const pb_field_iter_t *iter) +{ + pb_type_t type; + type = iter->pos->type; + + if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + if (*(pb_size_t*)iter->pSize != iter->pos->tag) + return; /* This is not the current field in the union */ + } + + /* Release anything contained inside an extension or submsg. + * This has to be done even if the submsg itself is statically + * allocated. */ + if (PB_LTYPE(type) == PB_LTYPE_EXTENSION) + { + /* Release fields from all extensions in the linked list */ + pb_extension_t *ext = *(pb_extension_t**)iter->pData; + while (ext != NULL) + { + pb_field_iter_t ext_iter; + iter_from_extension(&ext_iter, ext); + pb_release_single_field(&ext_iter); + ext = ext->next; + } + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE && PB_ATYPE(type) != PB_ATYPE_CALLBACK) + { + /* Release fields in submessage or submsg array */ + void *pItem = iter->pData; + pb_size_t count = 1; + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + pItem = *(void**)iter->pData; + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + if (PB_ATYPE(type) == PB_ATYPE_STATIC && iter->pSize == iter->pData) { + /* No _count field so use size of the array */ + count = iter->pos->array_size; + } else { + count = *(pb_size_t*)iter->pSize; + } + + if (PB_ATYPE(type) == PB_ATYPE_STATIC && count > iter->pos->array_size) + { + /* Protect against corrupted _count fields */ + count = iter->pos->array_size; + } + } + + if (pItem) + { + for (; count > 0; count--) + { + pb_release((const pb_field_t*)iter->pos->ptr, pItem); + pItem = (char*)pItem + iter->pos->data_size; + } + } + } + + if (PB_ATYPE(type) == PB_ATYPE_POINTER) + { + if (PB_HTYPE(type) == PB_HTYPE_REPEATED && + (PB_LTYPE(type) == PB_LTYPE_STRING || + PB_LTYPE(type) == PB_LTYPE_BYTES)) + { + /* Release entries in repeated string or bytes array */ + void **pItem = *(void***)iter->pData; + pb_size_t count = *(pb_size_t*)iter->pSize; + for (; count > 0; count--) + { + pb_free(*pItem); + *pItem++ = NULL; + } + } + + if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* We are going to release the array, so set the size to 0 */ + *(pb_size_t*)iter->pSize = 0; + } + + /* Release main item */ + pb_free(*(void**)iter->pData); + *(void**)iter->pData = NULL; + } +} + +void pb_release(const pb_field_t fields[], void *dest_struct) +{ + pb_field_iter_t iter; + + if (!dest_struct) + return; /* Ignore NULL pointers, similar to free() */ + + if (!pb_field_iter_begin(&iter, fields, dest_struct)) + return; /* Empty message type */ + + do + { + pb_release_single_field(&iter); + } while (pb_field_iter_next(&iter)); +} +#endif + +/* Field decoders */ + +bool pb_decode_bool(pb_istream_t *stream, bool *dest) +{ + return pb_dec_bool(stream, NULL, (void*)dest); +} + +bool pb_decode_svarint(pb_istream_t *stream, pb_int64_t *dest) +{ + pb_uint64_t value; + if (!pb_decode_varint(stream, &value)) + return false; + + if (value & 1) + *dest = (pb_int64_t)(~(value >> 1)); + else + *dest = (pb_int64_t)(value >> 1); + + return true; +} + +bool pb_decode_fixed32(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[4]; + + if (!pb_read(stream, bytes, 4)) + return false; + + *(uint32_t*)dest = ((uint32_t)bytes[0] << 0) | + ((uint32_t)bytes[1] << 8) | + ((uint32_t)bytes[2] << 16) | + ((uint32_t)bytes[3] << 24); + return true; +} + +#ifndef PB_WITHOUT_64BIT +bool pb_decode_fixed64(pb_istream_t *stream, void *dest) +{ + pb_byte_t bytes[8]; + + if (!pb_read(stream, bytes, 8)) + return false; + + *(uint64_t*)dest = ((uint64_t)bytes[0] << 0) | + ((uint64_t)bytes[1] << 8) | + ((uint64_t)bytes[2] << 16) | + ((uint64_t)bytes[3] << 24) | + ((uint64_t)bytes[4] << 32) | + ((uint64_t)bytes[5] << 40) | + ((uint64_t)bytes[6] << 48) | + ((uint64_t)bytes[7] << 56); + + return true; +} +#endif + +static bool checkreturn pb_dec_bool(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t value; + PB_UNUSED(field); + if (!pb_decode_varint32(stream, &value)) + return false; + + *(bool*)dest = (value != 0); + return true; +} + +static bool checkreturn pb_dec_varint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value; + pb_int64_t svalue; + pb_int64_t clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* See issue 97: Google's C++ protobuf allows negative varint values to + * be cast as int32_t, instead of the int64_t that should be used when + * encoding. Previous nanopb versions had a bug in encoding. In order to + * not break decoding of such messages, we cast <=32 bit fields to + * int32_t first to get the sign correct. + */ + if (field->data_size == sizeof(pb_int64_t)) + svalue = (pb_int64_t)value; + else + svalue = (int32_t)value; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = svalue; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)svalue; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)svalue; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)svalue; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != svalue) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_uvarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_uint64_t value, clamped; + if (!pb_decode_varint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_uint64_t)) + clamped = *(pb_uint64_t*)dest = value; + else if (field->data_size == sizeof(uint32_t)) + clamped = *(uint32_t*)dest = (uint32_t)value; + else if (field->data_size == sizeof(uint_least16_t)) + clamped = *(uint_least16_t*)dest = (uint_least16_t)value; + else if (field->data_size == sizeof(uint_least8_t)) + clamped = *(uint_least8_t*)dest = (uint_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_svarint(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + pb_int64_t value, clamped; + if (!pb_decode_svarint(stream, &value)) + return false; + + /* Cast to the proper field size, while checking for overflows */ + if (field->data_size == sizeof(pb_int64_t)) + clamped = *(pb_int64_t*)dest = value; + else if (field->data_size == sizeof(int32_t)) + clamped = *(int32_t*)dest = (int32_t)value; + else if (field->data_size == sizeof(int_least16_t)) + clamped = *(int_least16_t*)dest = (int_least16_t)value; + else if (field->data_size == sizeof(int_least8_t)) + clamped = *(int_least8_t*)dest = (int_least8_t)value; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + if (clamped != value) + PB_RETURN_ERROR(stream, "integer too large"); + + return true; +} + +static bool checkreturn pb_dec_fixed32(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); + return pb_decode_fixed32(stream, dest); +} + +static bool checkreturn pb_dec_fixed64(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_decode_fixed64(stream, dest); +#else + PB_UNUSED(dest); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_dec_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + pb_bytes_array_t *bdest; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + alloc_size = PB_BYTES_ARRAY_T_ALLOCSIZE(size); + if (size > alloc_size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + bdest = *(pb_bytes_array_t**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "bytes overflow"); + bdest = (pb_bytes_array_t*)dest; + } + + bdest->size = (pb_size_t)size; + return pb_read(stream, bdest->bytes, size); +} + +static bool checkreturn pb_dec_string(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + size_t alloc_size; + bool status; + if (!pb_decode_varint32(stream, &size)) + return false; + + /* Space for null terminator */ + alloc_size = size + 1; + + if (alloc_size < size) + PB_RETURN_ERROR(stream, "size too large"); + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { +#ifndef PB_ENABLE_MALLOC + PB_RETURN_ERROR(stream, "no malloc support"); +#else + if (stream->bytes_left < size) + PB_RETURN_ERROR(stream, "end-of-stream"); + + if (!allocate_field(stream, dest, alloc_size, 1)) + return false; + dest = *(void**)dest; +#endif + } + else + { + if (alloc_size > field->data_size) + PB_RETURN_ERROR(stream, "string overflow"); + } + + status = pb_read(stream, (pb_byte_t*)dest, size); + *((pb_byte_t*)dest + size) = 0; + return status; +} + +static bool checkreturn pb_dec_submessage(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + bool status; + pb_istream_t substream; + const pb_field_t* submsg_fields = (const pb_field_t*)field->ptr; + + if (!pb_make_string_substream(stream, &substream)) + return false; + + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + /* New array entries need to be initialized, while required and optional + * submessages have already been initialized in the top-level pb_decode. */ + if (PB_HTYPE(field->type) == PB_HTYPE_REPEATED) + status = pb_decode(&substream, submsg_fields, dest); + else + status = pb_decode_noinit(&substream, submsg_fields, dest); + + if (!pb_close_string_substream(stream, &substream)) + return false; + return status; +} + +static bool checkreturn pb_dec_fixed_length_bytes(pb_istream_t *stream, const pb_field_t *field, void *dest) +{ + uint32_t size; + + if (!pb_decode_varint32(stream, &size)) + return false; + + if (size > PB_SIZE_MAX) + PB_RETURN_ERROR(stream, "bytes overflow"); + + if (size == 0) + { + /* As a special case, treat empty bytes string as all zeros for fixed_length_bytes. */ + memset(dest, 0, field->data_size); + return true; + } + + if (size != field->data_size) + PB_RETURN_ERROR(stream, "incorrect fixed length bytes size"); + + return pb_read(stream, (pb_byte_t*)dest, field->data_size); +} diff --git a/Pods/nanopb/pb_decode.h b/Pods/nanopb/pb_decode.h new file mode 100644 index 0000000..3577c20 --- /dev/null +++ b/Pods/nanopb/pb_decode.h @@ -0,0 +1,178 @@ +/* pb_decode.h: Functions to decode protocol buffers. Depends on pb_decode.c. + * The main function is pb_decode. You also need an input stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_DECODE_H_INCLUDED +#define PB_DECODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom input streams. You will need to provide + * a callback function to read the bytes from your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause decoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer), + * and rely on pb_read to verify that no-body reads past bytes_left. + * 3) Your callback may be used with substreams, in which case bytes_left + * is different than from the main stream. Don't use bytes_left to compute + * any pointers. + */ +struct pb_istream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + */ + int *callback; +#else + bool (*callback)(pb_istream_t *stream, pb_byte_t *buf, size_t count); +#endif + + void *state; /* Free field for use by callback implementation */ + size_t bytes_left; + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main decoding functions * + ***************************/ + +/* Decode a single protocol buffers message from input stream into a C structure. + * Returns true on success, false on any failure. + * The actual struct pointed to by dest must match the description in fields. + * Callback fields of the destination structure must be initialized by caller. + * All other fields will be initialized by this function. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_istream_t stream; + * + * // ... read some data into buffer ... + * + * stream = pb_istream_from_buffer(buffer, count); + * pb_decode(&stream, MyMessage_fields, &msg); + */ +bool pb_decode(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except does not initialize the destination structure + * to default values. This is slightly faster if you need no default values + * and just do memset(struct, 0, sizeof(struct)) yourself. + * + * This can also be used for 'merging' two messages, i.e. update only the + * fields that exist in the new message. + * + * Note: If this function returns with an error, it will not release any + * dynamically allocated fields. You will need to call pb_release() yourself. + */ +bool pb_decode_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except expects the stream to start with the message size + * encoded as varint. Corresponds to parseDelimitedFrom() in Google's + * protobuf API. + */ +bool pb_decode_delimited(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode_delimited, except that it does not initialize the destination structure. + * See pb_decode_noinit + */ +bool pb_decode_delimited_noinit(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +/* Same as pb_decode, except allows the message to be terminated with a null byte. + * NOTE: Until nanopb-0.4.0, pb_decode() also allows null-termination. This behaviour + * is not supported in most other protobuf implementations, so pb_decode_delimited() + * is a better option for compatibility. + */ +bool pb_decode_nullterminated(pb_istream_t *stream, const pb_field_t fields[], void *dest_struct); + +#ifdef PB_ENABLE_MALLOC +/* Release any allocated pointer fields. If you use dynamic allocation, you should + * call this for any successfully decoded message when you are done with it. If + * pb_decode() returns with an error, the message is already released. + */ +void pb_release(const pb_field_t fields[], void *dest_struct); +#endif + + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an input stream for reading from a memory buffer. + * + * Alternatively, you can use a custom stream that reads directly from e.g. + * a file or a network socket. + */ +pb_istream_t pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize); + +/* Function to read from a pb_istream_t. You can use this if you need to + * read some custom header data, or to read data in field callbacks. + */ +bool pb_read(pb_istream_t *stream, pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Decode the tag for the next field in the stream. Gives the wire type and + * field tag. At end of the message, returns false and sets eof to true. */ +bool pb_decode_tag(pb_istream_t *stream, pb_wire_type_t *wire_type, uint32_t *tag, bool *eof); + +/* Skip the field payload data, given the wire type. */ +bool pb_skip_field(pb_istream_t *stream, pb_wire_type_t wire_type); + +/* Decode an integer in the varint format. This works for enum, int32, + * int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_varint(pb_istream_t *stream, uint64_t *dest); +#else +#define pb_decode_varint pb_decode_varint32 +#endif + +/* Decode an integer in the varint format. This works for enum, int32, + * and uint32 field types. */ +bool pb_decode_varint32(pb_istream_t *stream, uint32_t *dest); + +/* Decode a bool value in varint format. */ +bool pb_decode_bool(pb_istream_t *stream, bool *dest); + +/* Decode an integer in the zig-zagged svarint format. This works for sint32 + * and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_decode_svarint(pb_istream_t *stream, int64_t *dest); +#else +bool pb_decode_svarint(pb_istream_t *stream, int32_t *dest); +#endif + +/* Decode a fixed32, sfixed32 or float value. You need to pass a pointer to + * a 4-byte wide C variable. */ +bool pb_decode_fixed32(pb_istream_t *stream, void *dest); + +#ifndef PB_WITHOUT_64BIT +/* Decode a fixed64, sfixed64 or double value. You need to pass a pointer to + * a 8-byte wide C variable. */ +bool pb_decode_fixed64(pb_istream_t *stream, void *dest); +#endif + +/* Make a limited-length substream for reading a PB_WT_STRING field. */ +bool pb_make_string_substream(pb_istream_t *stream, pb_istream_t *substream); +bool pb_close_string_substream(pb_istream_t *stream, pb_istream_t *substream); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/Pods/nanopb/pb_encode.c b/Pods/nanopb/pb_encode.c new file mode 100644 index 0000000..f6e60c4 --- /dev/null +++ b/Pods/nanopb/pb_encode.c @@ -0,0 +1,911 @@ +/* pb_encode.c -- encode a protobuf using minimal resources + * + * 2011 Petteri Aimonen + */ + +#include "pb.h" +#include "pb_encode.h" +#include "pb_common.h" + +/* Use the GCC warn_unused_result attribute to check that all return values + * are propagated correctly. On other compilers and gcc before 3.4.0 just + * ignore the annotation. + */ +#if !defined(__GNUC__) || ( __GNUC__ < 3) || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) + #define checkreturn +#else + #define checkreturn __attribute__((warn_unused_result)) +#endif + +/************************************** + * Declarations internal to this file * + **************************************/ +typedef bool (*pb_encoder_t)(pb_ostream_t *stream, const pb_field_t *field, const void *src) checkreturn; + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, const void *pData, size_t count, pb_encoder_t func); +static bool checkreturn encode_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, const pb_extension_t *extension); +static bool checkreturn encode_extension_field(pb_ostream_t *stream, const pb_field_t *field, const void *pData); +static void *pb_const_cast(const void *p); +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src); +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src); + +#ifdef PB_WITHOUT_64BIT +#define pb_int64_t int32_t +#define pb_uint64_t uint32_t + +static bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value); +#else +#define pb_int64_t int64_t +#define pb_uint64_t uint64_t +#endif + +/* --- Function pointers to field encoders --- + * Order in the array must match pb_action_t LTYPE numbering. + */ +static const pb_encoder_t PB_ENCODERS[PB_LTYPES_COUNT] = { + &pb_enc_bool, + &pb_enc_varint, + &pb_enc_uvarint, + &pb_enc_svarint, + &pb_enc_fixed32, + &pb_enc_fixed64, + + &pb_enc_bytes, + &pb_enc_string, + &pb_enc_submessage, + NULL, /* extensions */ + &pb_enc_fixed_length_bytes +}; + +/******************************* + * pb_ostream_t implementation * + *******************************/ + +static bool checkreturn buf_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + size_t i; + pb_byte_t *dest = (pb_byte_t*)stream->state; + stream->state = dest + count; + + for (i = 0; i < count; i++) + dest[i] = buf[i]; + + return true; +} + +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize) +{ + pb_ostream_t stream; +#ifdef PB_BUFFER_ONLY + stream.callback = (void*)1; /* Just a marker value */ +#else + stream.callback = &buf_write; +#endif + stream.state = buf; + stream.max_size = bufsize; + stream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + stream.errmsg = NULL; +#endif + return stream; +} + +bool checkreturn pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count) +{ + if (count > 0 && stream->callback != NULL) + { + if (stream->bytes_written + count < stream->bytes_written || + stream->bytes_written + count > stream->max_size) + { + PB_RETURN_ERROR(stream, "stream full"); + } + +#ifdef PB_BUFFER_ONLY + if (!buf_write(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#else + if (!stream->callback(stream, buf, count)) + PB_RETURN_ERROR(stream, "io error"); +#endif + } + + stream->bytes_written += count; + return true; +} + +/************************* + * Encode a single field * + *************************/ + +/* Read a bool value without causing undefined behavior even if the value + * is invalid. See issue #434 and + * https://stackoverflow.com/questions/27661768/weird-results-for-conditional + */ +static bool safe_read_bool(const void *pSize) +{ + const char *p = (const char *)pSize; + size_t i; + for (i = 0; i < sizeof(bool); i++) + { + if (p[i] != 0) + return true; + } + return false; +} + +/* Encode a static array. Handles the size calculations and possible packing. */ +static bool checkreturn encode_array(pb_ostream_t *stream, const pb_field_t *field, + const void *pData, size_t count, pb_encoder_t func) +{ + size_t i; + const void *p; +#ifndef PB_ENCODE_ARRAYS_UNPACKED + size_t size; +#endif + + if (count == 0) + return true; + + if (PB_ATYPE(field->type) != PB_ATYPE_POINTER && count > field->array_size) + PB_RETURN_ERROR(stream, "array max size exceeded"); + +#ifndef PB_ENCODE_ARRAYS_UNPACKED + /* We always pack arrays if the datatype allows it. */ + if (PB_LTYPE(field->type) <= PB_LTYPE_LAST_PACKABLE) + { + if (!pb_encode_tag(stream, PB_WT_STRING, field->tag)) + return false; + + /* Determine the total size of packed array. */ + if (PB_LTYPE(field->type) == PB_LTYPE_FIXED32) + { + size = 4 * count; + } + else if (PB_LTYPE(field->type) == PB_LTYPE_FIXED64) + { + size = 8 * count; + } + else + { + pb_ostream_t sizestream = PB_OSTREAM_SIZING; + p = pData; + for (i = 0; i < count; i++) + { + if (!func(&sizestream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + size = sizestream.bytes_written; + } + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing.. */ + + /* Write the data */ + p = pData; + for (i = 0; i < count; i++) + { + if (!func(stream, field, p)) + return false; + p = (const char*)p + field->data_size; + } + } + else +#endif + { + p = pData; + for (i = 0; i < count; i++) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + /* Normally the data is stored directly in the array entries, but + * for pointer-type string and bytes fields, the array entries are + * actually pointers themselves also. So we have to dereference once + * more to get to the actual data. */ + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER && + (PB_LTYPE(field->type) == PB_LTYPE_STRING || + PB_LTYPE(field->type) == PB_LTYPE_BYTES)) + { + if (!func(stream, field, *(const void* const*)p)) + return false; + } + else + { + if (!func(stream, field, p)) + return false; + } + p = (const char*)p + field->data_size; + } + } + + return true; +} + +/* In proto3, all fields are optional and are only encoded if their value is "non-zero". + * This function implements the check for the zero value. */ +static bool pb_check_proto3_default_value(const pb_field_t *field, const void *pData) +{ + pb_type_t type = field->type; + const void *pSize = (const char*)pData + field->size_offset; + + if (PB_HTYPE(type) == PB_HTYPE_REQUIRED) + { + /* Required proto2 fields inside proto3 submessage, pretty rare case */ + return false; + } + else if (PB_HTYPE(type) == PB_HTYPE_REPEATED) + { + /* Repeated fields inside proto3 submessage: present if count != 0 */ + if (field->size_offset != 0) + return *(const pb_size_t*)pSize == 0; + else if (PB_ATYPE(type) == PB_ATYPE_STATIC) + return false; /* Fixed length array */ + } + else if (PB_HTYPE(type) == PB_HTYPE_ONEOF) + { + /* Oneof fields */ + return *(const pb_size_t*)pSize == 0; + } + else if (PB_HTYPE(type) == PB_HTYPE_OPTIONAL && field->size_offset != 0) + { + /* Proto2 optional fields inside proto3 submessage */ + return safe_read_bool(pSize) == false; + } + + /* Rest is proto3 singular fields */ + + if (PB_ATYPE(type) == PB_ATYPE_STATIC) + { + if (PB_LTYPE(type) == PB_LTYPE_BYTES) + { + const pb_bytes_array_t *bytes = (const pb_bytes_array_t*)pData; + return bytes->size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_STRING) + { + return *(const char*)pData == '\0'; + } + else if (PB_LTYPE(type) == PB_LTYPE_FIXED_LENGTH_BYTES) + { + /* Fixed length bytes is only empty if its length is fixed + * as 0. Which would be pretty strange, but we can check + * it anyway. */ + return field->data_size == 0; + } + else if (PB_LTYPE(type) == PB_LTYPE_SUBMESSAGE) + { + /* Check all fields in the submessage to find if any of them + * are non-zero. The comparison cannot be done byte-per-byte + * because the C struct may contain padding bytes that must + * be skipped. + */ + pb_field_iter_t iter; + if (pb_field_iter_begin(&iter, (const pb_field_t*)field->ptr, pb_const_cast(pData))) + { + do + { + if (!pb_check_proto3_default_value(iter.pos, iter.pData)) + { + return false; + } + } while (pb_field_iter_next(&iter)); + } + return true; + } + } + + /* Compares pointers to NULL in case of FT_POINTER */ + if (PB_ATYPE(type) == PB_ATYPE_POINTER && PB_LTYPE(type) > PB_LTYPE_LAST_PACKABLE) + { + return !*(const void**)((uintptr_t)pData); + } + + { + /* Catch-all branch that does byte-per-byte comparison for zero value. + * + * This is for all pointer fields, and for static PB_LTYPE_VARINT, + * UVARINT, SVARINT, FIXED32, FIXED64, EXTENSION fields, and also + * callback fields. These all have integer or pointer value which + * can be compared with 0. + */ + pb_size_t i; + const char *p = (const char*)pData; + for (i = 0; i < field->data_size; i++) + { + if (p[i] != 0) + { + return false; + } + } + + return true; + } +} + +/* Encode a field with static or pointer allocation, i.e. one whose data + * is available to the encoder directly. */ +static bool checkreturn encode_basic_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + pb_encoder_t func; + bool implicit_has; + const void *pSize = &implicit_has; + + func = PB_ENCODERS[PB_LTYPE(field->type)]; + + if (field->size_offset) + { + /* Static optional, repeated or oneof field */ + pSize = (const char*)pData + field->size_offset; + } + else if (PB_HTYPE(field->type) == PB_HTYPE_OPTIONAL) + { + /* Proto3 style field, optional but without explicit has_ field. */ + implicit_has = !pb_check_proto3_default_value(field, pData); + } + else + { + /* Required field, always present */ + implicit_has = true; + } + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* pData is a pointer to the field, which contains pointer to + * the data. If the 2nd pointer is NULL, it is interpreted as if + * the has_field was false. + */ + pData = *(const void* const*)pData; + implicit_has = (pData != NULL); + } + + switch (PB_HTYPE(field->type)) + { + case PB_HTYPE_REQUIRED: + if (!pData) + PB_RETURN_ERROR(stream, "missing required field"); + if (!pb_encode_tag_for_field(stream, field)) + return false; + if (!func(stream, field, pData)) + return false; + break; + + case PB_HTYPE_OPTIONAL: + if (safe_read_bool(pSize)) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + case PB_HTYPE_REPEATED: { + pb_size_t count; + if (field->size_offset != 0) { + count = *(const pb_size_t*)pSize; + } else { + count = field->array_size; + } + if (!encode_array(stream, field, pData, count, func)) + return false; + break; + } + + case PB_HTYPE_ONEOF: + if (*(const pb_size_t*)pSize == field->tag) + { + if (!pb_encode_tag_for_field(stream, field)) + return false; + + if (!func(stream, field, pData)) + return false; + } + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return true; +} + +/* Encode a field with callback semantics. This means that a user function is + * called to provide and encode the actual data. */ +static bool checkreturn encode_callback_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_callback_t *callback = (const pb_callback_t*)pData; + +#ifdef PB_OLD_CALLBACK_STYLE + const void *arg = callback->arg; +#else + void * const *arg = &(callback->arg); +#endif + + if (callback->funcs.encode != NULL) + { + if (!callback->funcs.encode(stream, field, arg)) + PB_RETURN_ERROR(stream, "callback error"); + } + return true; +} + +/* Encode a single field of any callback or static type. */ +static bool checkreturn encode_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + switch (PB_ATYPE(field->type)) + { + case PB_ATYPE_STATIC: + case PB_ATYPE_POINTER: + return encode_basic_field(stream, field, pData); + + case PB_ATYPE_CALLBACK: + return encode_callback_field(stream, field, pData); + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } +} + +/* Default handler for extension fields. Expects to have a pb_field_t + * pointer in the extension->type->arg field. */ +static bool checkreturn default_extension_encoder(pb_ostream_t *stream, + const pb_extension_t *extension) +{ + const pb_field_t *field = (const pb_field_t*)extension->type->arg; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + { + /* For pointer extensions, the pointer is stored directly + * in the extension structure. This avoids having an extra + * indirection. */ + return encode_field(stream, field, &extension->dest); + } + else + { + return encode_field(stream, field, extension->dest); + } +} + +/* Walk through all the registered extensions and give them a chance + * to encode themselves. */ +static bool checkreturn encode_extension_field(pb_ostream_t *stream, + const pb_field_t *field, const void *pData) +{ + const pb_extension_t *extension = *(const pb_extension_t* const *)pData; + PB_UNUSED(field); + + while (extension) + { + bool status; + if (extension->type->encode) + status = extension->type->encode(stream, extension); + else + status = default_extension_encoder(stream, extension); + + if (!status) + return false; + + extension = extension->next; + } + + return true; +} + +/********************* + * Encode all fields * + *********************/ + +static void *pb_const_cast(const void *p) +{ + /* Note: this casts away const, in order to use the common field iterator + * logic for both encoding and decoding. */ + union { + void *p1; + const void *p2; + } t; + t.p2 = p; + return t.p1; +} + +bool checkreturn pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + pb_field_iter_t iter; + if (!pb_field_iter_begin(&iter, fields, pb_const_cast(src_struct))) + return true; /* Empty message type */ + + do { + if (PB_LTYPE(iter.pos->type) == PB_LTYPE_EXTENSION) + { + /* Special case for the extension field placeholder */ + if (!encode_extension_field(stream, iter.pos, iter.pData)) + return false; + } + else + { + /* Regular field */ + if (!encode_field(stream, iter.pos, iter.pData)) + return false; + } + } while (pb_field_iter_next(&iter)); + + return true; +} + +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + return pb_encode_submessage(stream, fields, src_struct); +} + +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + const pb_byte_t zero = 0; + + if (!pb_encode(stream, fields, src_struct)) + return false; + + return pb_write(stream, &zero, 1); +} + +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct) +{ + pb_ostream_t stream = PB_OSTREAM_SIZING; + + if (!pb_encode(&stream, fields, src_struct)) + return false; + + *size = stream.bytes_written; + return true; +} + +/******************** + * Helper functions * + ********************/ + +#ifdef PB_WITHOUT_64BIT +bool checkreturn pb_encode_negative_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + size_t compensation = 32;/* we need to compensate 32 bits all set to 1 */ + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + if (compensation) + { + /* re-set all the compensation bits we can or need */ + size_t bits = compensation > 7 ? 7 : compensation; + value ^= (pb_uint64_t)((0xFFu >> (8 - bits)) << 25); /* set the number of bits needed on the lowest of the most significant 7 bits */ + compensation -= bits; + } + i++; + } + buffer[i - 1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} +#endif + +bool checkreturn pb_encode_varint(pb_ostream_t *stream, pb_uint64_t value) +{ + pb_byte_t buffer[10]; + size_t i = 0; + + if (value <= 0x7F) + { + pb_byte_t v = (pb_byte_t)value; + return pb_write(stream, &v, 1); + } + + while (value) + { + buffer[i] = (pb_byte_t)((value & 0x7F) | 0x80); + value >>= 7; + i++; + } + buffer[i-1] &= 0x7F; /* Unset top bit on last byte */ + + return pb_write(stream, buffer, i); +} + +bool checkreturn pb_encode_svarint(pb_ostream_t *stream, pb_int64_t value) +{ + pb_uint64_t zigzagged; + if (value < 0) + zigzagged = ~((pb_uint64_t)value << 1); + else + zigzagged = (pb_uint64_t)value << 1; + + return pb_encode_varint(stream, zigzagged); +} + +bool checkreturn pb_encode_fixed32(pb_ostream_t *stream, const void *value) +{ + uint32_t val = *(const uint32_t*)value; + pb_byte_t bytes[4]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + return pb_write(stream, bytes, 4); +} + +#ifndef PB_WITHOUT_64BIT +bool checkreturn pb_encode_fixed64(pb_ostream_t *stream, const void *value) +{ + uint64_t val = *(const uint64_t*)value; + pb_byte_t bytes[8]; + bytes[0] = (pb_byte_t)(val & 0xFF); + bytes[1] = (pb_byte_t)((val >> 8) & 0xFF); + bytes[2] = (pb_byte_t)((val >> 16) & 0xFF); + bytes[3] = (pb_byte_t)((val >> 24) & 0xFF); + bytes[4] = (pb_byte_t)((val >> 32) & 0xFF); + bytes[5] = (pb_byte_t)((val >> 40) & 0xFF); + bytes[6] = (pb_byte_t)((val >> 48) & 0xFF); + bytes[7] = (pb_byte_t)((val >> 56) & 0xFF); + return pb_write(stream, bytes, 8); +} +#endif + +bool checkreturn pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number) +{ + pb_uint64_t tag = ((pb_uint64_t)field_number << 3) | wiretype; + return pb_encode_varint(stream, tag); +} + +bool checkreturn pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field) +{ + pb_wire_type_t wiretype; + switch (PB_LTYPE(field->type)) + { + case PB_LTYPE_BOOL: + case PB_LTYPE_VARINT: + case PB_LTYPE_UVARINT: + case PB_LTYPE_SVARINT: + wiretype = PB_WT_VARINT; + break; + + case PB_LTYPE_FIXED32: + wiretype = PB_WT_32BIT; + break; + + case PB_LTYPE_FIXED64: + wiretype = PB_WT_64BIT; + break; + + case PB_LTYPE_BYTES: + case PB_LTYPE_STRING: + case PB_LTYPE_SUBMESSAGE: + case PB_LTYPE_FIXED_LENGTH_BYTES: + wiretype = PB_WT_STRING; + break; + + default: + PB_RETURN_ERROR(stream, "invalid field type"); + } + + return pb_encode_tag(stream, wiretype, field->tag); +} + +bool checkreturn pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size) +{ + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + return pb_write(stream, buffer, size); +} + +bool checkreturn pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct) +{ + /* First calculate the message size using a non-writing substream. */ + pb_ostream_t substream = PB_OSTREAM_SIZING; + size_t size; + bool status; + + if (!pb_encode(&substream, fields, src_struct)) + { +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + return false; + } + + size = substream.bytes_written; + + if (!pb_encode_varint(stream, (pb_uint64_t)size)) + return false; + + if (stream->callback == NULL) + return pb_write(stream, NULL, size); /* Just sizing */ + + if (stream->bytes_written + size > stream->max_size) + PB_RETURN_ERROR(stream, "stream full"); + + /* Use a substream to verify that a callback doesn't write more than + * what it did the first time. */ + substream.callback = stream->callback; + substream.state = stream->state; + substream.max_size = size; + substream.bytes_written = 0; +#ifndef PB_NO_ERRMSG + substream.errmsg = NULL; +#endif + + status = pb_encode(&substream, fields, src_struct); + + stream->bytes_written += substream.bytes_written; + stream->state = substream.state; +#ifndef PB_NO_ERRMSG + stream->errmsg = substream.errmsg; +#endif + + if (substream.bytes_written != size) + PB_RETURN_ERROR(stream, "submsg size changed"); + + return status; +} + +/* Field encoders */ + +static bool checkreturn pb_enc_bool(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + uint32_t value = safe_read_bool(src) ? 1 : 0; + PB_UNUSED(field); + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_varint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + +#ifdef PB_WITHOUT_64BIT + if (value < 0) + return pb_encode_negative_varint(stream, (pb_uint64_t)value); + else +#endif + return pb_encode_varint(stream, (pb_uint64_t)value); +} + +static bool checkreturn pb_enc_uvarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_uint64_t value = 0; + + if (field->data_size == sizeof(uint_least8_t)) + value = *(const uint_least8_t*)src; + else if (field->data_size == sizeof(uint_least16_t)) + value = *(const uint_least16_t*)src; + else if (field->data_size == sizeof(uint32_t)) + value = *(const uint32_t*)src; + else if (field->data_size == sizeof(pb_uint64_t)) + value = *(const pb_uint64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_varint(stream, value); +} + +static bool checkreturn pb_enc_svarint(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + pb_int64_t value = 0; + + if (field->data_size == sizeof(int_least8_t)) + value = *(const int_least8_t*)src; + else if (field->data_size == sizeof(int_least16_t)) + value = *(const int_least16_t*)src; + else if (field->data_size == sizeof(int32_t)) + value = *(const int32_t*)src; + else if (field->data_size == sizeof(pb_int64_t)) + value = *(const pb_int64_t*)src; + else + PB_RETURN_ERROR(stream, "invalid data_size"); + + return pb_encode_svarint(stream, value); +} + +static bool checkreturn pb_enc_fixed64(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); +#ifndef PB_WITHOUT_64BIT + return pb_encode_fixed64(stream, src); +#else + PB_UNUSED(src); + PB_RETURN_ERROR(stream, "no 64bit support"); +#endif +} + +static bool checkreturn pb_enc_fixed32(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + PB_UNUSED(field); + return pb_encode_fixed32(stream, src); +} + +static bool checkreturn pb_enc_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + const pb_bytes_array_t *bytes = NULL; + + bytes = (const pb_bytes_array_t*)src; + + if (src == NULL) + { + /* Treat null pointer as an empty bytes field */ + return pb_encode_string(stream, NULL, 0); + } + + if (PB_ATYPE(field->type) == PB_ATYPE_STATIC && + bytes->size > field->data_size - offsetof(pb_bytes_array_t, bytes)) + { + PB_RETURN_ERROR(stream, "bytes size exceeded"); + } + + return pb_encode_string(stream, bytes->bytes, bytes->size); +} + +static bool checkreturn pb_enc_string(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + size_t size = 0; + size_t max_size = field->data_size; + const char *p = (const char*)src; + + if (PB_ATYPE(field->type) == PB_ATYPE_POINTER) + max_size = (size_t)-1; + + if (src == NULL) + { + size = 0; /* Treat null pointer as an empty string */ + } + else + { + /* strnlen() is not always available, so just use a loop */ + while (size < max_size && *p != '\0') + { + size++; + p++; + } + } + + return pb_encode_string(stream, (const pb_byte_t*)src, size); +} + +static bool checkreturn pb_enc_submessage(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + if (field->ptr == NULL) + PB_RETURN_ERROR(stream, "invalid field descriptor"); + + return pb_encode_submessage(stream, (const pb_field_t*)field->ptr, src); +} + +static bool checkreturn pb_enc_fixed_length_bytes(pb_ostream_t *stream, const pb_field_t *field, const void *src) +{ + return pb_encode_string(stream, (const pb_byte_t*)src, field->data_size); +} + diff --git a/Pods/nanopb/pb_encode.h b/Pods/nanopb/pb_encode.h new file mode 100644 index 0000000..b1d822f --- /dev/null +++ b/Pods/nanopb/pb_encode.h @@ -0,0 +1,170 @@ +/* pb_encode.h: Functions to encode protocol buffers. Depends on pb_encode.c. + * The main function is pb_encode. You also need an output stream, and the + * field descriptions created by nanopb_generator.py. + */ + +#ifndef PB_ENCODE_H_INCLUDED +#define PB_ENCODE_H_INCLUDED + +#include "pb.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Structure for defining custom output streams. You will need to provide + * a callback function to write the bytes to your storage, which can be + * for example a file or a network socket. + * + * The callback must conform to these rules: + * + * 1) Return false on IO errors. This will cause encoding to abort. + * 2) You can use state to store your own data (e.g. buffer pointer). + * 3) pb_write will update bytes_written after your callback runs. + * 4) Substreams will modify max_size and bytes_written. Don't use them + * to calculate any pointers. + */ +struct pb_ostream_s +{ +#ifdef PB_BUFFER_ONLY + /* Callback pointer is not used in buffer-only configuration. + * Having an int pointer here allows binary compatibility but + * gives an error if someone tries to assign callback function. + * Also, NULL pointer marks a 'sizing stream' that does not + * write anything. + */ + int *callback; +#else + bool (*callback)(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); +#endif + void *state; /* Free field for use by callback implementation. */ + size_t max_size; /* Limit number of output bytes written (or use SIZE_MAX). */ + size_t bytes_written; /* Number of bytes written so far. */ + +#ifndef PB_NO_ERRMSG + const char *errmsg; +#endif +}; + +/*************************** + * Main encoding functions * + ***************************/ + +/* Encode a single protocol buffers message from C structure into a stream. + * Returns true on success, false on any failure. + * The actual struct pointed to by src_struct must match the description in fields. + * All required fields in the struct are assumed to have been filled in. + * + * Example usage: + * MyMessage msg = {}; + * uint8_t buffer[64]; + * pb_ostream_t stream; + * + * msg.field1 = 42; + * stream = pb_ostream_from_buffer(buffer, sizeof(buffer)); + * pb_encode(&stream, MyMessage_fields, &msg); + */ +bool pb_encode(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but prepends the length of the message as a varint. + * Corresponds to writeDelimitedTo() in Google's protobuf API. + */ +bool pb_encode_delimited(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Same as pb_encode, but appends a null byte to the message for termination. + * NOTE: This behaviour is not supported in most other protobuf implementations, so pb_encode_delimited() + * is a better option for compatibility. + */ +bool pb_encode_nullterminated(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +/* Encode the message to get the size of the encoded data, but do not store + * the data. */ +bool pb_get_encoded_size(size_t *size, const pb_field_t fields[], const void *src_struct); + +/************************************** + * Functions for manipulating streams * + **************************************/ + +/* Create an output stream for writing into a memory buffer. + * The number of bytes written can be found in stream.bytes_written after + * encoding the message. + * + * Alternatively, you can use a custom stream that writes directly to e.g. + * a file or a network socket. + */ +pb_ostream_t pb_ostream_from_buffer(pb_byte_t *buf, size_t bufsize); + +/* Pseudo-stream for measuring the size of a message without actually storing + * the encoded data. + * + * Example usage: + * MyMessage msg = {}; + * pb_ostream_t stream = PB_OSTREAM_SIZING; + * pb_encode(&stream, MyMessage_fields, &msg); + * printf("Message size is %d\n", stream.bytes_written); + */ +#ifndef PB_NO_ERRMSG +#define PB_OSTREAM_SIZING {0,0,0,0,0} +#else +#define PB_OSTREAM_SIZING {0,0,0,0} +#endif + +/* Function to write into a pb_ostream_t stream. You can use this if you need + * to append or prepend some custom headers to the message. + */ +bool pb_write(pb_ostream_t *stream, const pb_byte_t *buf, size_t count); + + +/************************************************ + * Helper functions for writing field callbacks * + ************************************************/ + +/* Encode field header based on type and field number defined in the field + * structure. Call this from the callback before writing out field contents. */ +bool pb_encode_tag_for_field(pb_ostream_t *stream, const pb_field_t *field); + +/* Encode field header by manually specifying wire type. You need to use this + * if you want to write out packed arrays from a callback field. */ +bool pb_encode_tag(pb_ostream_t *stream, pb_wire_type_t wiretype, uint32_t field_number); + +/* Encode an integer in the varint format. + * This works for bool, enum, int32, int64, uint32 and uint64 field types. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_varint(pb_ostream_t *stream, uint64_t value); +#else +bool pb_encode_varint(pb_ostream_t *stream, uint32_t value); +#endif + +/* Encode an integer in the zig-zagged svarint format. + * This works for sint32 and sint64. */ +#ifndef PB_WITHOUT_64BIT +bool pb_encode_svarint(pb_ostream_t *stream, int64_t value); +#else +bool pb_encode_svarint(pb_ostream_t *stream, int32_t value); +#endif + +/* Encode a string or bytes type field. For strings, pass strlen(s) as size. */ +bool pb_encode_string(pb_ostream_t *stream, const pb_byte_t *buffer, size_t size); + +/* Encode a fixed32, sfixed32 or float value. + * You need to pass a pointer to a 4-byte wide C variable. */ +bool pb_encode_fixed32(pb_ostream_t *stream, const void *value); + +#ifndef PB_WITHOUT_64BIT +/* Encode a fixed64, sfixed64 or double value. + * You need to pass a pointer to a 8-byte wide C variable. */ +bool pb_encode_fixed64(pb_ostream_t *stream, const void *value); +#endif + +/* Encode a submessage field. + * You need to pass the pb_field_t array and pointer to struct, just like + * with pb_encode(). This internally encodes the submessage twice, first to + * calculate message size and then to actually write it out. + */ +bool pb_encode_submessage(pb_ostream_t *stream, const pb_field_t fields[], const void *src_struct); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif diff --git a/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy b/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy new file mode 100644 index 0000000..72e00ac --- /dev/null +++ b/Pods/nanopb/spm_resources/PrivacyInfo.xcprivacy @@ -0,0 +1,15 @@ + + + + + NSPrivacyAccessedAPITypes + + NSPrivacyCollectedDataTypes + + NSPrivacyTracking + + NSPrivacyTrackingDomains + + + +