Identifiers.swift 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. //
  2. // Copyright 2022 Google LLC
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import Foundation
  16. @_implementationOnly import FirebaseInstallations
  17. let sessionIDUserDefaultsKey = "com.firebase.sessions.sessionID"
  18. let lastSessionIDUserDefaultsKey = "com.firebase.sessions.lastSessionID"
  19. protocol IdentifierProvider {
  20. var installationID: String {
  21. get
  22. }
  23. var sessionID: String {
  24. get
  25. }
  26. var previousSessionID: String {
  27. get
  28. }
  29. }
  30. ///
  31. /// Identifiers is responsible for:
  32. /// 1) Getting the Installation ID from Installations
  33. /// 2) Generating the Session ID
  34. /// 3) Persisting and reading the Session ID from the last session
  35. /// (Maybe) 4) Persisting, reading, and incrementing an increasing index
  36. ///
  37. class Identifiers: IdentifierProvider {
  38. private let installations: InstallationsProtocol
  39. private var _sessionID: UUID
  40. init(installations: InstallationsProtocol) {
  41. self.installations = installations
  42. _sessionID = UUID()
  43. }
  44. // Generates a new Session ID. If there was already a generated Session ID
  45. // from the last session during the app's lifecycle, it will also set the last Session ID
  46. func generateNewSessionID() {
  47. _sessionID = UUID()
  48. let lastStoredSessionID = UserDefaults.standard.string(forKey: sessionIDUserDefaultsKey) ?? ""
  49. UserDefaults.standard.set(lastStoredSessionID, forKey: lastSessionIDUserDefaultsKey)
  50. let newSessionID = _sessionID.uuidString.replacingOccurrences(of: "-", with: "").lowercased()
  51. UserDefaults.standard.set(newSessionID, forKey: sessionIDUserDefaultsKey)
  52. }
  53. // Fetches the Installation ID from Firebase Installation Service. This method must be run on a background thread due to how Firebase Installations
  54. // handles threading.
  55. var installationID: String {
  56. if Thread.isMainThread {
  57. Logger
  58. .logError(
  59. "Error: Identifiers.installationID getter must be called on a background thread. Using an empty ID"
  60. )
  61. return ""
  62. }
  63. var localInstallationID = ""
  64. let semaphore = DispatchSemaphore(value: 0)
  65. installations.installationID { result in
  66. switch result {
  67. case let .success(fiid):
  68. localInstallationID = fiid
  69. case let .failure(error):
  70. Logger
  71. .logError(
  72. "Error getting Firebase Installation ID: \(error). Using an empty ID"
  73. )
  74. }
  75. semaphore.signal()
  76. }
  77. switch semaphore.wait(timeout: DispatchTime.now() + 1.0) {
  78. case .success:
  79. break
  80. case .timedOut:
  81. Logger.logError("Error: took too long to get the Firebase Installation ID. Using an empty ID")
  82. }
  83. return localInstallationID
  84. }
  85. var sessionID: String {
  86. return UserDefaults.standard.string(forKey: sessionIDUserDefaultsKey) ?? ""
  87. }
  88. var previousSessionID: String {
  89. return UserDefaults.standard.string(forKey: lastSessionIDUserDefaultsKey) ?? ""
  90. }
  91. }