firebase log level
This commit is contained in:
120
Pods/FirebaseSessions/FirebaseSessions/Sources/ApplicationInfo.swift
generated
Normal file
120
Pods/FirebaseSessions/FirebaseSessions/Sources/ApplicationInfo.swift
generated
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
75
Pods/FirebaseSessions/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift
generated
Normal file
75
Pods/FirebaseSessions/FirebaseSessions/Sources/Development/DevEventConsoleLogger.swift
generated
Normal file
@ -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, Error>) -> 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)
|
||||
}
|
||||
}
|
||||
131
Pods/FirebaseSessions/FirebaseSessions/Sources/Development/NanoPB+CustomStringConvertible.swift
generated
Normal file
131
Pods/FirebaseSessions/FirebaseSessions/Sources/Development/NanoPB+CustomStringConvertible.swift
generated
Normal file
@ -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 `<field>.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<pb_bytes_array_t>
|
||||
extension UnsafeMutablePointer: CustomStringConvertible where Pointee == pb_bytes_array_t {
|
||||
public var description: String {
|
||||
let decoded = FIRSESDecodeString(self)
|
||||
if decoded.count == 0 {
|
||||
return "<EMPTY>"
|
||||
}
|
||||
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<pb_bytes_array_t>?
|
||||
extension Optional: CustomStringConvertible
|
||||
where Wrapped == UnsafeMutablePointer<pb_bytes_array_t> {
|
||||
public var description: String {
|
||||
guard let this = self else {
|
||||
return "<NULL>"
|
||||
}
|
||||
return this.description
|
||||
}
|
||||
}
|
||||
54
Pods/FirebaseSessions/FirebaseSessions/Sources/EventGDTLogger.swift
generated
Normal file
54
Pods/FirebaseSessions/FirebaseSessions/Sources/EventGDTLogger.swift
generated
Normal file
@ -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, Error>) -> 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, Error>) -> 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)
|
||||
}
|
||||
}
|
||||
283
Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessions.swift
generated
Normal file
283
Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessions.swift
generated
Normal file
@ -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<Void>] = [:]
|
||||
|
||||
/// 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, FirebaseSessionsError>) -> 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<Void>.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)
|
||||
}]
|
||||
}
|
||||
}
|
||||
35
Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessionsError.swift
generated
Normal file
35
Pods/FirebaseSessions/FirebaseSessions/Sources/FirebaseSessionsError.swift
generated
Normal file
@ -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
|
||||
}
|
||||
41
Pods/FirebaseSessions/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift
generated
Normal file
41
Pods/FirebaseSessions/FirebaseSessions/Sources/GoogleDataTransport+GoogleDataTransportProtocol.swift
generated
Normal file
@ -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, Error>) -> Void)
|
||||
func eventForTransport() -> GDTCOREvent
|
||||
}
|
||||
|
||||
extension GDTCORTransport: GoogleDataTransportProtocol {
|
||||
func logGDTEvent(event: GDTCOREvent, completion: @escaping (Result<Void, Error>) -> Void) {
|
||||
sendDataEvent(event) { wasWritten, error in
|
||||
if let error {
|
||||
completion(.failure(error))
|
||||
} else if !wasWritten {
|
||||
completion(.failure(GoogleDataTransportProtocolErrors.writeFailure))
|
||||
} else {
|
||||
completion(.success(()))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
79
Pods/FirebaseSessions/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift
generated
Normal file
79
Pods/FirebaseSessions/FirebaseSessions/Sources/Installations+InstallationsProtocol.swift
generated
Normal file
@ -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 {}
|
||||
62
Pods/FirebaseSessions/FirebaseSessions/Sources/Logger.swift
generated
Normal file
62
Pods/FirebaseSessions/FirebaseSessions/Sources/Logger.swift
generated
Normal file
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
42
Pods/FirebaseSessions/FirebaseSessions/Sources/NetworkInfo.swift
generated
Normal file
42
Pods/FirebaseSessions/FirebaseSessions/Sources/NetworkInfo.swift
generated
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
32
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsDependencies.swift
generated
Normal file
32
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsDependencies.swift
generated
Normal file
@ -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<SessionsSubscriberName> = .init()
|
||||
|
||||
@objc public static func addDependency(name: SessionsSubscriberName) {
|
||||
SessionsDependencies.dependencies.insert(name)
|
||||
}
|
||||
}
|
||||
23
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsProvider.swift
generated
Normal file
23
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsProvider.swift
generated
Normal file
@ -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)
|
||||
}
|
||||
56
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsSubscriber.swift
generated
Normal file
56
Pods/FirebaseSessions/FirebaseSessions/Sources/Public/SessionsSubscriber.swift
generated
Normal file
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
81
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionCoordinator.swift
generated
Normal file
81
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionCoordinator.swift
generated
Normal file
@ -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, FirebaseSessionsError>) -> 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, FirebaseSessionsError>)
|
||||
-> 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, FirebaseSessionsError>)
|
||||
-> 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)))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
76
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionGenerator.swift
generated
Normal file
76
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionGenerator.swift
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
136
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionInitiator.swift
generated
Normal file
136
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionInitiator.swift
generated
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
300
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionStartEvent.swift
generated
Normal file
300
Pods/FirebaseSessions/FirebaseSessions/Sources/SessionStartEvent.swift
generated
Normal file
@ -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<pb_bytes_array_t>?] = [
|
||||
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<pb_bytes_array_t>? {
|
||||
guard let string = string else {
|
||||
return nil
|
||||
}
|
||||
return FIRSESEncodeString(string)
|
||||
}
|
||||
|
||||
private func makeProtoString(_ string: String) -> UnsafeMutablePointer<pb_bytes_array_t>? {
|
||||
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
|
||||
}
|
||||
}
|
||||
73
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/LocalOverrideSettings.swift
generated
Normal file
73
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/LocalOverrideSettings.swift
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
134
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/RemoteSettings.swift
generated
Normal file
134
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/RemoteSettings.swift
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
46
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SDKDefaultSettings.swift
generated
Normal file
46
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SDKDefaultSettings.swift
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
84
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SessionsSettings.swift
generated
Normal file
84
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SessionsSettings.swift
generated
Normal file
@ -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()
|
||||
}
|
||||
}
|
||||
95
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift
generated
Normal file
95
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsCacheClient.swift
generated
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
107
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift
generated
Normal file
107
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsDownloadClient.swift
generated
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
31
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProtocol.swift
generated
Normal file
31
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProtocol.swift
generated
Normal file
@ -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 }
|
||||
}
|
||||
35
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProvider.swift
generated
Normal file
35
Pods/FirebaseSessions/FirebaseSessions/Sources/Settings/SettingsProvider.swift
generated
Normal file
@ -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 }
|
||||
}
|
||||
31
Pods/FirebaseSessions/FirebaseSessions/Sources/Time.swift
generated
Normal file
31
Pods/FirebaseSessions/FirebaseSessions/Sources/Time.swift
generated
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
99
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h
generated
Normal file
99
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h
generated
Normal file
@ -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 <Foundation/Foundation.h>
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
#if __has_include("CoreTelephony/CTTelephonyNetworkInfo.h") && !TARGET_OS_MACCATALYST && \
|
||||
!TARGET_OS_OSX && !TARGET_OS_TV
|
||||
#define TARGET_HAS_MOBILE_CONNECTIVITY
|
||||
#import <CoreTelephony/CTCarrier.h>
|
||||
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
||||
#endif
|
||||
|
||||
#import <nanopb/pb.h>
|
||||
#import <nanopb/pb_decode.h>
|
||||
#import <nanopb/pb_encode.h>
|
||||
|
||||
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 */
|
||||
205
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m
generated
Normal file
205
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.m
generated
Normal file
@ -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 <Foundation/Foundation.h>
|
||||
|
||||
#import <GoogleUtilities/GULNetworkInfo.h>
|
||||
|
||||
#import "FirebaseSessions/SourcesObjC/NanoPB/FIRSESNanoPBHelpers.h"
|
||||
|
||||
#import "FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h"
|
||||
|
||||
@import FirebaseCoreExtension;
|
||||
|
||||
#import <nanopb/pb.h>
|
||||
#import <nanopb/pb_decode.h>
|
||||
#import <nanopb/pb_encode.h>
|
||||
#import <sys/sysctl.h>
|
||||
|
||||
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
|
||||
125
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.c
generated
Normal file
125
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.c
generated
Normal file
@ -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) */
|
||||
270
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h
generated
Normal file
270
Pods/FirebaseSessions/FirebaseSessions/SourcesObjC/Protogen/nanopb/sessions.nanopb.h
generated
Normal file
@ -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 <nanopb/pb.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 _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
|
||||
202
Pods/FirebaseSessions/LICENSE
generated
Normal file
202
Pods/FirebaseSessions/LICENSE
generated
Normal file
@ -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.
|
||||
302
Pods/FirebaseSessions/README.md
generated
Normal file
302
Pods/FirebaseSessions/README.md
generated
Normal file
@ -0,0 +1,302 @@
|
||||
<p align="center">
|
||||
<a href="https://cocoapods.org/pods/Firebase">
|
||||
<img src="https://img.shields.io/github/v/release/Firebase/firebase-ios-sdk?style=flat&label=CocoaPods"/>
|
||||
</a>
|
||||
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
|
||||
<img src="https://img.shields.io/github/v/release/Firebase/firebase-ios-sdk?style=flat&label=Swift%20Package%20Index&color=red"/>
|
||||
</a>
|
||||
<a href="https://cocoapods.org/pods/Firebase">
|
||||
<img src="https://img.shields.io/github/license/Firebase/firebase-ios-sdk?style=flat"/>
|
||||
</a><br/>
|
||||
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ffirebase%2Ffirebase-ios-sdk%2Fbadge%3Ftype%3Dplatforms"/>
|
||||
</a>
|
||||
<a href="https://swiftpackageindex.com/firebase/firebase-ios-sdk">
|
||||
<img src="https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Ffirebase%2Ffirebase-ios-sdk%2Fbadge%3Ftype%3Dswift-versions"/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
# 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/).
|
||||
Reference in New Issue
Block a user