diff --git a/config/ConfigExample/RemoteConfigViewController.swift b/config/ConfigExample/RemoteConfigViewController.swift index cca2c884f..b4454efa4 100644 --- a/config/ConfigExample/RemoteConfigViewController.swift +++ b/config/ConfigExample/RemoteConfigViewController.swift @@ -14,13 +14,14 @@ import UIKit import FirebaseRemoteConfig +import FirebaseRemoteConfigSwift class RemoteConfigViewController: UIViewController { private var remoteConfig: RemoteConfig! private var remoteConfigView: RemoteConfigView { view as! RemoteConfigView } private let topLabelKey = "topLabelKey" - private let recipeKey = "recipeKey" + private let typedRecipeKey = "typedRecipeKey" private let bottomLabelKey = "bottomLabelKey" override func loadView() { @@ -48,41 +49,42 @@ class RemoteConfigViewController: UIViewController { // MARK: - Firebase 🔥 + // Add additional keys that are in the console to see them in the log after fetching the config. + struct QSConfig: Codable { + let topLabelKey: String + let bottomLabelKey: String + let freeCount: Int + } + /// Initializes defaults from `RemoteConfigDefaults.plist` and sets config's settings to developer mode private func setupRemoteConfig() { remoteConfig = RemoteConfig.remoteConfig() - remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults") - + // This is an alternative to remoteConfig.setDefaults(fromPlist: "RemoteConfigDefaults")) + do { + try remoteConfig.setDefaults(from: QSConfig(topLabelKey: "myTopLabel", + bottomLabelKey: "Buy one get one free!", + freeCount: 4)) + } catch { + print("Failed to set Defaults.") + } let settings = RemoteConfigSettings() settings.minimumFetchInterval = 0 remoteConfig.configSettings = settings } - /// Fetches remote config values from the server - private func fetchRemoteConfig() { - remoteConfig.fetch { status, error in - guard error == nil else { return self.displayError(error) } - print("Remote config successfully fetched!") - } - } - - /// Activates remote config values, making them available to use in your app - private func activateRemoteConfig() { - remoteConfig.activate { success, error in - guard error == nil else { return self.displayError(error) } - print("Remote config successfully activated!") - DispatchQueue.main.async { - self.updateUI() - } - } - } - /// Fetches and activates remote config values @objc private func fetchAndActivateRemoteConfig() { remoteConfig.fetchAndActivate { status, error in guard error == nil else { return self.displayError(error) } print("Remote config successfully fetched & activated!") + do { + let qsConfig: QSConfig = try self.remoteConfig.decoded() + print(qsConfig) + } catch { + self.displayError(error) + return + } DispatchQueue.main.async { self.updateUI() } @@ -91,9 +93,19 @@ class RemoteConfigViewController: UIViewController { /// This method applies our remote config values to our UI private func updateUI() { - remoteConfigView.topLabel.text = remoteConfig["topLabelKey"].stringValue + remoteConfigView.topLabel.text = remoteConfig[decodedValue: "topLabelKey"] updateJSONView() - remoteConfigView.bottomLabel.text = remoteConfig["bottomLabelKey"].stringValue + if var bottomLabel: String = remoteConfig[decodedValue: "bottomLabelKey"], + let freeCount: Int = remoteConfig[decodedValue: "freeCount"], + freeCount > 1, + bottomLabel.contains("one") { + let formatter = NumberFormatter() + formatter.numberStyle = .spellOut + if let english = formatter.string(from: NSNumber(value: freeCount)) { + bottomLabel = bottomLabel.replacingOccurrences(of: "one free", with: "\(english) free") + } + remoteConfigView.bottomLabel.text = bottomLabel + } } // MARK: - Private Helpers @@ -125,35 +137,36 @@ class RemoteConfigViewController: UIViewController { } } - // Specify keys in the order we would like to display the information in - let keys = [ - "recipe_name", - "ingredients", - "prep_time", - "cook_time", - "instructions", - "yield", - "serving_size", - "notes", - ] - guard let recipeDictionary = remoteConfig[recipeKey].jsonValue as? [String: Any] else { return } - - keys.enumerated().forEach { index, key in - guard var value = recipeDictionary[key] else { return } - - if let list = value as? [String] { - let joinedValue = list.joined(separator: " • ") - value = joinedValue - } else if let stringValue = value as? String { - value = stringValue + struct Recipe: Decodable, CustomStringConvertible { + var recipe_name: String + var ingredients: [String] + var prep_time: Int + var cook_time: Int + var instructions: [String] + var yield: String + var serving_size: Int + var notes: String + + var description: String { + return "Recipe Name: \(recipe_name)\n" + + "Ingredients: \(ingredients)\n" + + "Prep Time: \(prep_time)\n" + + "Cook Time: \(cook_time)\n" + + "Instructions: \(instructions)\n" + + "Yield: \(yield)\n" + + "Serving Size: \(serving_size)\n" + + "Notes: \(notes)" } + } - guard let stringValue = value as? String else { return } - - let formattedKey = key - .capitalized - .replacingOccurrences(of: "_", with: " ") - .appending(": ") + guard let recipe: Recipe = try? remoteConfig[typedRecipeKey].decoded() else { + fatalError("Failed to decode JSON for \(typedRecipeKey)") + } + let lines = recipe.description.split(separator: "\n") + for (index, line) in lines.enumerated() { + let lineSplit = line.split(separator: ":") + let formattedKey = String(lineSplit[0]) + let stringValue = String(lineSplit[1]) let attributedKey = NSAttributedString( string: formattedKey, @@ -175,8 +188,8 @@ class RemoteConfigViewController: UIViewController { animateFadeIn(for: label, duration: 0.3) let height = jsonView.frame.height - let step = height / CGFloat(keys.count) - let offset = height * 0.2 * 1 / CGFloat(keys.count) + let step = height / CGFloat(lines.count) + let offset = height * 0.2 * 1 / CGFloat(lines.count) let x: CGFloat = jsonView.frame.width * 0.05 let y: CGFloat = step * CGFloat(index) + offset @@ -196,7 +209,7 @@ extension UIViewController { public func displayError(_ error: Error?, from function: StaticString = #function) { guard let error = error else { return } print("🚨 Error in \(function): \(error.localizedDescription)") - let message = "\(error.localizedDescription)\n\n Ocurred in \(function)" + let message = "\(error.localizedDescription)\n\n Occurred in \(function)" let errorAlertController = UIAlertController( title: "Error", message: message, diff --git a/config/Podfile b/config/Podfile index 3512d7d15..67a7e6ca2 100644 --- a/config/Podfile +++ b/config/Podfile @@ -7,6 +7,7 @@ target 'ConfigExample' do # Pods for ConfigExample pod 'FirebaseRemoteConfig' + pod 'FirebaseRemoteConfigSwift', "> 8.12-beta" target 'ConfigExampleTests' do inherit! :search_paths diff --git a/config/Podfile.lock b/config/Podfile.lock index 452f0a81e..fd3593d6a 100644 --- a/config/Podfile.lock +++ b/config/Podfile.lock @@ -21,6 +21,10 @@ PODS: - FirebaseInstallations (~> 8.0) - GoogleUtilities/Environment (~> 7.7) - "GoogleUtilities/NSData+zlib (~> 7.7)" + - FirebaseRemoteConfigSwift (8.12.0-beta): + - FirebaseRemoteConfig (~> 8.11) + - FirebaseSharedSwift (~> 8.11-beta) + - FirebaseSharedSwift (8.12.0) - GoogleDataTransport (9.1.2): - GoogleUtilities/Environment (~> 7.2) - nanopb (~> 2.30908.0) @@ -41,6 +45,7 @@ PODS: DEPENDENCIES: - FirebaseRemoteConfig + - FirebaseRemoteConfigSwift (> 8.12-beta) SPEC REPOS: trunk: @@ -49,6 +54,8 @@ SPEC REPOS: - FirebaseCoreDiagnostics - FirebaseInstallations - FirebaseRemoteConfig + - FirebaseRemoteConfigSwift + - FirebaseSharedSwift - GoogleDataTransport - GoogleUtilities - nanopb @@ -60,11 +67,13 @@ SPEC CHECKSUMS: FirebaseCoreDiagnostics: 3b40dfadef5b90433a60ae01f01e90fe87aa76aa FirebaseInstallations: 25764cf322e77f99449395870a65b2bef88e1545 FirebaseRemoteConfig: f174a7091ac8e69bf6d0de2bae2212edb922a0ab + FirebaseRemoteConfigSwift: 55de35ecdfed3758d69c0faa04c460989efd63db + FirebaseSharedSwift: baa1fb7870eb8589d6107946da9d2bf050939b03 GoogleDataTransport: 629c20a4d363167143f30ea78320d5a7eb8bd940 GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 nanopb: a0ba3315591a9ae0a16a309ee504766e90db0c96 PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58 -PODFILE CHECKSUM: 508a02096afdac3e2d945a0ec8c5748484e5097f +PODFILE CHECKSUM: 257ef6d5d16a32786088ce5e498068af81e1a28b COCOAPODS: 1.11.2