Fabric, Crashlytic , Firebase - poloteh/iOSRoadmapTutorial GitHub Wiki
Fabric & Crashlytic
Add fabric in your project
Follow the setup Crashlytics
*** When adding run script, you may face the problem that Fabric cannot detect the run script
Solution: For Xcode 10 search "debug information format" in build setting and use DWARF with dSYM file.
Firebase
Import Firebase in cocoapod
Remote Config
Add remote config for MOST project (some are not needed)
To support multiple environments, add a folder as a reference with your Gooogle service plist.
Example code to add in AppDelegate
extension AppDelegate {
private func configureFirebaseAnalytics() {
var filePath:String!
// #if DEBUG || STAGING
// print("[FIREBASE] Development mode.")
// filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist", inDirectory: "Staging")
// #else
print("[FIREBASE] Production mode.")
filePath = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist")
// #endif
let options = FirebaseOptions.init(contentsOfFile: filePath)!
FirebaseApp.configure(options: options)
}
private func configureFirebaseremoteConfigsWithLaunchOptions(launchOptions: [UIApplicationLaunchOptionsKey: Any]?) {
// [START get_remote_config_instance]
remoteConfig = RemoteConfig.remoteConfig()
// [END get_remote_config_instance]
// Create a Remote Config Setting to enable developer mode, which you can use to increase
// the number of fetches available per hour during development. See Best Practices in the
// README for more information.
// [START enable_dev_mode]
remoteConfig.configSettings = RemoteConfigSettings(developerModeEnabled: true)
// [END enable_dev_mode]
// Set default Remote Config parameter values. An app uses the in-app default values, and
// when you need to adjust those defaults, you set an updated value for only the values you
// want to change in the Firebase console. See Best Practices in the README for more
// information.
// [START set_default_values]
// remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults")
// [END set_default_values]
fetchFirebaseRemoteConfig()
}
func startAppCondinator(){
}
func fetchFirebaseRemoteConfig() {
var expirationDuration = 3600
// If your app is using developer mode, expirationDuration is set to 0, so each fetch will
// retrieve values from the service.
if remoteConfig.configSettings.isDeveloperModeEnabled {
expirationDuration = 0
}
// [START fetch_config_with_callback]
// TimeInterval is set to expirationDuration here, indicating the next fetch request will use
// data fetched from the Remote Config service, rather than cached parameter values, if cached
// parameter values are more than expirationDuration seconds old. See Best Practices in the
// README for more information.
remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
if status == .success {
print("Config fetched!")
self.remoteConfig.activateFetched()
} else {
print("Config not fetched")
print("Error: \(error?.localizedDescription ?? "No error available.")")
self.startAppCondinator()
return
}
let forceUpdate = self.remoteConfig[FirebaseRemoteConfigKeys.FORCEUPDATEENABLEDIOS].boolValue
let serverVersion = self.remoteConfig[FirebaseRemoteConfigKeys.IOSVERSION].stringValue
let updateMessage = forceUpdate ? self.remoteConfig[FirebaseRemoteConfigKeys.FORCEUPDATEMESSAGE].stringValue : self.remoteConfig[FirebaseRemoteConfigKeys.UPDATEMESSAGE].stringValue
self.checkUpdateVersion(updateMessage: updateMessage!, serverVersion: serverVersion!, forceUpdate: forceUpdate)
}
// [END fetch_config_with_callback]
}
func checkUpdateVersion(updateMessage:String, serverVersion:String, forceUpdate:Bool) {
if let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String {
if serverVersion.compare(version, options: .numeric) == .orderedDescending {
showUpdateAlert(message: updateMessage, forceUpdate: forceUpdate)
} else {
startAppCondinator()
}
} else {
startAppCondinator()
}
}
func showUpdateAlert(message:String, forceUpdate:Bool) {
let alertController = UIAlertController(title: "App update request", message: message, preferredStyle: .actionSheet)
let okAction = UIAlertAction(title: "Update", style: UIAlertActionStyle.default) {
UIAlertAction in
#if DEBUG || STAGING
let downloadURL = AppURLs.stagingURL
#else
let downloadURL = AppURLs.appStoreURL
#endif
#if DEBUG || STAGING
UIApplication.shared.open(URL(string: downloadURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, options:[:], completionHandler: { (success) in
exit(0)
})
#else
if let url = URL(string: "itms-apps://" + downloadURL),
UIApplication.shared.canOpenURL(url){
UIApplication.shared.open(url, options:[:], completionHandler: { (success) in
exit(0)
})
} else {
UIApplication.shared.open(URL(string: downloadURL.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!)!, options:[:], completionHandler: { (success) in
exit(0)
})
}
#endif
}
let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.cancel) {
UIAlertAction in
if (forceUpdate) {
exit(0)
} else {
self.startAppCondinator()
}
}
alertController.addAction(okAction)
alertController.addAction(cancelAction)
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)
}
}
enum FirebaseRemoteConfigKeys {
static let FORCEUPDATEMESSAGE = "force_update_message"
static let UPDATEMESSAGE = "update_message"
static let IOSVERSION = "app_version"
static let FORCEUPDATEENABLEDIOS = "force_update_enabled"
}
enum AppURLs {
static let appStoreURL = "https://itunes.apple.com/us/app/(APPNAME)/(APP id)"
static let stagingURL = "(Own Server)"
}