Skip to content

Instantly share code, notes, and snippets.

@steipete
Created April 13, 2020 13:38
Show Gist options
  • Save steipete/0f33c76302e7aae61d546171f76d1360 to your computer and use it in GitHub Desktop.
Save steipete/0f33c76302e7aae61d546171f76d1360 to your computer and use it in GitHub Desktop.
If you're as confused as I am that there's an API for custom options, yet Google still requires a file named GoogleService-Info.plist in your app, here's some swizzling that fixes that for ya. All Swift :)
class FirebaseCoordinator {
static let shared = FirebaseCoordinator()
static let initialize: Void = {
/// We modify Google Firebase (and eventually Analytics) to load the mac-specific plist at runtime.
/// Google enforces that we have a file named "GoogleService-Info.plist" in the app resources.
/// This is unfortunate since we need two different files based on iOS and Mac version
/// One solution is a custom build step that copies in the correct file:
/// https://stackoverflow.com/questions/37615405/use-different-googleservice-info-plist-for-different-build-schemes
/// However, this is basically impossible since Catalyst doesn't set any custom build variables, so detection is extremely difficult.
/// We swizzle to modify the loading times.
/// There is also official API: FirebaseApp.configure(options: firebaseOptions()) however this is too late for Google Analytics.
#if targetEnvironment(macCatalyst)
if !FirebaseOptions.configurePlistPath() {
print("Warning: Overriding Mac-specific plist failed in Firebase. Check plist override code")
}
#endif
FirebaseApp.configure()
#if DEBUG
print("Firebase Initialized. isDataCollectionDefaultEnabled: \(FirebaseApp.app()!.isDataCollectionDefaultEnabled)")
#endif
}()
private init() { }
static func configure() {
FirebaseCoordinator.initialize
}
}
extension FirebaseOptions {
/// Modifies the Google Firebase plist path to load GoogleService-Info-Mac if on Mac Catalyst.
static func configurePlistPath() -> Bool {
guard let klass = object_getClass(self) else { return false }
let sel = NSSelectorFromString("plistFilePathWithName:")
var origIMP : IMP? = nil
let newHandler: @convention(block) (AnyObject, String) -> String = { blockSelf, name in
typealias ClosureType = @convention(c) (AnyObject, Selector, String) -> String
let callableIMP = unsafeBitCast(origIMP, to: ClosureType.self)
return callableIMP(blockSelf, sel, name + (IsMacCatalyst() ? "-Mac" : ""))
}
guard let method = class_getClassMethod(klass, sel) else { return false }
origIMP = class_replaceMethod(klass, sel, imp_implementationWithBlock(newHandler), method_getTypeEncoding(method))
return origIMP != nil
}
}
// Future code: Currently Mac Catalyst doesn't support Google Analytics yet.
extension FirebaseCoordinator {
/// Modifies the path that Google Analytics uses to load the plist
static func configureGoogleAnalyticsPlistPath() -> Bool {
// id +[APMInfoPlistFileUtil googleServiceInfoPlistPath](id a1, SEL a2)
guard let klass = object_getClass(NSClassFromString("APMInfoPlistFileUtil")) else { return false }
let selector = NSSelectorFromString("googleServiceInfoPlistPath")
let newHandler: @convention(block) (AnyObject) -> String = { blockSelf in
let newName = "GoogleService-Info" + (IsMacCatalyst() ? "-Mac" : "")
return Bundle.main.path(forResource: newName, ofType: "plist") ?? ""
}
guard let method = class_getClassMethod(klass, selector) else { return false }
let origIMP = class_replaceMethod(klass, selector, imp_implementationWithBlock(newHandler), method_getTypeEncoding(method))
return origIMP != nil
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment