FirebaseAppInternal.swift 4.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Copyright 2022 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. import FirebaseCore
  15. import ObjectiveC
  16. public extension FirebaseApp {
  17. /// A flag indicating if this is the default app (has the default app name). Redirects to the
  18. /// Obj-C property of the same name.
  19. var isDefaultApp: Bool {
  20. // First two arguments are the class (FirebaseApp) and the selector name.
  21. typealias VoidBoolFunc = @convention(c) (AnyObject, Selector) -> Bool
  22. let sel = NSSelectorFromString("isDefaultApp")
  23. let isDefaultAppFunc = generatePrivateFunc(sel, from: self, type: VoidBoolFunc.self)
  24. return isDefaultAppFunc(self, sel)
  25. }
  26. /// Checks if the default app is configured without trying to configure it. Redirects to the Obj-C
  27. /// method of the same name.
  28. static var isDefaultAppConfigured: Bool {
  29. // First two arguments are the class (FirebaseApp) and the selector name.
  30. typealias VoidBoolFunc = @convention(c) (AnyClass, Selector) -> Bool
  31. let sel = NSSelectorFromString("isDefaultAppConfigured")
  32. let isDefaultAppConfigured = generatePrivateClassFunc(sel, from: self, type: VoidBoolFunc.self)
  33. return isDefaultAppConfigured(self, sel)
  34. }
  35. /// Create a Firebase app for test purposes. Calls an internal Obj-C initializer. Visible only
  36. /// with `@testable import` due to its internal naming.
  37. internal static func initializedApp(name: String, options: FirebaseOptions) -> FirebaseApp {
  38. // Call `alloc` first to allocate memory for our new instance. The first two arguments are
  39. // the class (FirebaseApp) and the selector name.
  40. typealias AllocFunc = @convention(c) (AnyClass, Selector) -> FirebaseApp
  41. let allocSel = NSSelectorFromString("alloc")
  42. let allocFunc = generatePrivateClassFunc(allocSel, from: self, type: AllocFunc.self)
  43. let allocated: FirebaseApp = allocFunc(self, allocSel)
  44. // First two arguments are the object and the selector name.
  45. typealias AppInitFunc = @convention(c) (AnyObject, Selector, NSString, FirebaseOptions)
  46. -> FirebaseApp
  47. let initSel = NSSelectorFromString("initInstanceWithName:options:")
  48. let appInitFunc = generatePrivateFunc(initSel, from: allocated, type: AppInitFunc.self)
  49. return appInitFunc(allocated, initSel, NSString(string: name), options)
  50. }
  51. }
  52. /// Fetches a class function of the provided type using `NSStringFromSelector` and the given class.
  53. /// This may crash if the selector doesn't exist, so use at your own risk.
  54. private func generatePrivateFunc<T: NSObject, U>(_ selector: Selector,
  55. from instance: T,
  56. type funcType: U.Type) -> U {
  57. guard instance.responds(to: selector) else {
  58. fatalError("""
  59. Firebase tried to get a method named \(selector) from an instance of \(type(of: instance)) but
  60. it doesn't exist. It may have been changed recently. Please file an issue in the
  61. firebase-ios-sdk repo if you see this error, and mention the Swift products that you're using
  62. along with this message. Sorry about that!
  63. https://github.com/firebase/firebase-ios-sdk/issues/new/choose
  64. """)
  65. }
  66. let methodImp = instance.method(for: selector)
  67. return unsafeBitCast(methodImp, to: funcType)
  68. }
  69. /// Fetches a class function of the provided type using `NSStringFromSelector` and the given class.
  70. /// This may crash if the selector doesn't exist, so use at your own risk.
  71. private func generatePrivateClassFunc<T: NSObject, U>(_ selector: Selector,
  72. from klass: T.Type,
  73. type: U.Type) -> U {
  74. guard klass.responds(to: selector) else {
  75. fatalError("""
  76. Firebase tried to get a method named \(selector) from a class named \(klass) but it doesn't
  77. exist. It may have been changed recently. Please file an issue in the firebase-ios-sdk repo
  78. if you see this error, and mention the Swift products that you're using along with this
  79. message. Sorry about that!
  80. https://github.com/firebase/firebase-ios-sdk/issues/new/choose
  81. """)
  82. }
  83. let methodImp = klass.method(for: selector)
  84. return unsafeBitCast(methodImp, to: type)
  85. }