Created
April 13, 2020 13:38
-
-
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 :)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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