I'm using Firebase Remote Config, I have some troubles to update values.
My values are updated only if I close and relaunch the app.
But never if my app enters in foreground.
The developer is activated, with no cache delay.
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let _ = RCFirebaseValues.sharedInstance
}
}
My Firebase Remote Config class:
enum ValueKey: String {
case force_update
}
class RCFirebaseValues {
static let sharedInstance = RCFirebaseValues()
var loadingDoneCallback: (() -> ())?
var fetchComplete: Bool = false
private init() {
loadDefaultValues()
fetchCloudValues()
}
func loadDefaultValues() {
RemoteConfig.remoteConfig().setDefaults(fromPlist: "RemoteConfigDefaults")
}
func fetchCloudValues() {
#if DEBUG
let expirationDuration: TimeInterval = 0
RemoteConfig.remoteConfig().configSettings = RemoteConfigSettings(developerModeEnabled: true)
#else
let expirationDuration: TimeInterval = 3600
#endif
RemoteConfig.remoteConfig().fetch(withExpirationDuration: expirationDuration) {
[weak self] (status, error) in
guard error == nil else {
DLog(message:"Uh-oh. Got an error fetching remote values \(String(describing: error))")
return
}
RemoteConfig.remoteConfig().activateFetched()
self?.fetchComplete = true
self?.loadingDoneCallback?()
}
}
func bool(forKey key: ValueKey) -> Bool {
return RemoteConfig.remoteConfig()[key.rawValue].boolValue
}
func string(forKey key: ValueKey) -> String {
return RemoteConfig.remoteConfig()[key.rawValue].stringValue ?? ""
}
func double(forKey key: ValueKey) -> Double {
if let numberValue = RemoteConfig.remoteConfig()[key.rawValue].numberValue {
return numberValue.doubleValue
} else {
return 0.0
}
}
}
What's wrong?
EDIT after Mosbah's response:
class AppDelegate: UIResponder, UIApplicationDelegate {
var remoteConfig:RCFirebaseValues!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
self. remoteConfig = RCFirebaseValues.sharedInstance
}
}
Your RCFirebaseValues scope is wrong, it will be nil as soon as you are out of application: didFinishLaunchingWithOptions: so you should keep a strong reference to your object (create a var on AppDelegate).
Related
I'm trying to display an ad with GADAppOpenAd
The problem is, every initial login to the application, no advertisement is displayed, only when I go to the background and return to the application, then an advertisement appears,
I'm trying to have an advertisement appear on the initial login as well
var appOpenAd: GADAppOpenAd?
var loadTime = Date()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
GADMobileAds.sharedInstance().start(completionHandler: nil)
requestAppOpenAd()
return true
}
extension AppDelegate:GADFullScreenContentDelegate {
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
requestAppOpenAd()
}
func adDidDismissFullScreenContent(_ ad: GADFullScreenPresentingAd) {
requestAppOpenAd()
}
func requestAppOpenAd() {
let request = GADRequest()
GADAppOpenAd.load(withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
request: request,
orientation: UIInterfaceOrientation.portrait,
completionHandler: { (appOpenAdIn, _) in
self.appOpenAd = appOpenAdIn
self.appOpenAd?.fullScreenContentDelegate = self
self.loadTime = Date()
print("Ad is ready")
})
}
func tryToPresentAd() {
guard let rootViewController = (UIApplication.shared.connectedScenes.first?.delegate as? SceneDelegate)?.window?.rootViewController else {
return
}
if let gOpenAd = self.appOpenAd, wasLoadTimeLessThanNHoursAgo(thresholdN: 4){
gOpenAd.present(fromRootViewController: rootViewController)
} else {
self.requestAppOpenAd()
}
}
func wasLoadTimeLessThanNHoursAgo(thresholdN: Int) -> Bool {
let now = Date()
let timeIntervalBetweenNowAndLoadTime = now.timeIntervalSince(self.loadTime)
let secondsPerHour = 3600.0
let intervalInHours = timeIntervalBetweenNowAndLoadTime / secondsPerHour
return intervalInHours < Double(thresholdN)
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneDidBecomeActive(_ scene: UIScene) {
(UIApplication.shared.delegate as? AppDelegate)?.tryToPresentAd()
}
}
This question already has answers here:
Where to configure Firebase in my iOS app in the new SwiftUI App life cycle without AppDelegate and SceneDelegate?
(2 answers)
Closed 1 year ago.
I made the front end of an application but now I have to make the back end and therefore print a DB the problem is that I have an error "Failed to get FirebaseApp instance. Please call FirebaseApp.configure() before using Firestore" :
App delegate :
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}
DataBase :
struct New: Identifiable {
var id: String = UUID().uuidString
var news: String
}
class NewsViewModel: ObservableObject {
#Published var news = [New]()
private var db = Firestore.firestore()
func fetchDate() {
db.collection("News").addSnapshotListener { (querySnapshot, error) in
guard let documents = querySnapshot?.documents else {
print("No documents")
return
}
self.news = documents.map { (QueryDocumentSnapshot) -> New in
let data = QueryDocumentSnapshot.data()
let news = data["News"] as? String ?? "ya r"
return New(news: news)
}
}
}
}
Print DB :
NavigationView {
List(viewModel.news) { news in
VStack(alignment: .leading) {
Text(news.news)
}
.navigationTitle("News")
}
}
.onAppear() {
self.viewModel.fetchDate()
}
Thanks for help
Can you add it inside willFinishLaunchingWithOptions
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
I've created a number of links with a custom URL scheme in Firebase and while I am able to open the app when selecting the link in Notes, the dynamic link is always nil.
Here's the code calling the Dynamic Links api:
public struct FirebaseBridge {
public static func configure() {
FirebaseOptions.defaultOptions()?.deepLinkURLScheme = "mycustomurlscheme"
MyFirebase.configure(crashlyticsIncludeDeviceId: false)
}
public static func setPushMessagingDelegate(_ pushMessagingDelegate: MessagingDelegate) {
Messaging.messaging().delegate = pushMessagingDelegate
}
public static func openDynamicLinkFromURL(_ url: URL) -> Bool {
print(url.absoluteString)
if let dynamicLink = DynamicLinks.dynamicLinks().dynamicLink(fromCustomSchemeURL: url) {
self.handleIncomingDynamicLink(dynamicLink)
return true
}
return false
}
public static func handleUniversalLinkFromURL(_ url: URL) -> Bool {
let handled = DynamicLinks.dynamicLinks().handleUniversalLink(url) { (dynamiclLnk, error) in
guard error == nil, let dynamicLink = dynamiclLnk else {
print("error")
return
}
print(dynamicLink)
print(dynamiclLnk?.url ?? "no URL")
FirebaseBridge.handleIncomingDynamicLink(dynamicLink)
}
return handled
}
private static func handleIncomingDynamicLink(_ dynamicLink: DynamicLink) {
guard let url = dynamicLink.url else {
print(dynamicLink)
return
}
print(url.absoluteString)
}
public static func performDiagnostics() {
DynamicLinks.performDiagnostics(completion: { diagnostic, error in
print(diagnostic)
})
}
}
Here is the relevant code in the AppDelegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Keep this first at app launch.
FirebaseBridge.configure()
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return FirebaseBridge.openDynamicLinkFromURL(url)
}
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
guard let url = userActivity.webpageURL else {
return false
}
return FirebaseBridge.handleUniversalLinkFromURL(url)
}
}
Here's the output of the performDiagnostics call:
---- Firebase Dynamic Links diagnostic output start ----
Firebase Dynamic Links framework version 4.0.8
System information: OS iOS, OS version 13.3.1, model iPhone
Current date 2020-06-08 17:35:58 +0000
Device locale en-US (raw en_US), timezone America/Los_Angeles
Specified custom URL scheme is mycustomurlscheme and Info.plist contains such scheme in CFBundleURLTypes key.
AppID Prefix: prefix, Team ID: teamid, AppId Prefix equal to Team ID: YES
performDiagnostic completed successfully! No errors found.
---- Firebase Dynamic Links diagnostic output end ----
Any help would be appreciated!
Navigation system in my app contains coordinator pattern. when my application starts for the first time, everything works well. But when the app recedes into the background and phone system terminate it and I'm trying to get back to it, app starts for the first time again. So I need to restore my app state if system terminate app in background.
My AppDelegate class
import UIKit
import Swinject
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let container = Container()
private var appCoordinator: AppCoordinator!
func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
setupDependecies()
return true
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
appCoordinator = AppCoordinator(window: window!, container: container)
appCoordinator.start()
window?.makeKeyAndVisible()
return true
}
func application(_ application: UIApplication, shouldSaveSecureApplicationState coder: NSCoder) -> Bool {
return true
}
func application(_ application: UIApplication, shouldRestoreSecureApplicationState coder: NSCoder) -> Bool {
return true
}
}
AppCoordinator class
import Foundation
import UIKit
import Swinject
enum AppChildCoordinator {
case serial
case topic
}
final class AppCoordinator: Coordinator {
private let window: UIWindow
let container: Container
private var childCoordinators = [AppChildCoordinator: Coordinator]()
private let navigationController: UINavigationController
private let plistService: PlistService
init(window: UIWindow, container: Container) {
self.window = window
self.container = container
navigationController = UINavigationController()
self.window.rootViewController = navigationController
plistService = container.resolve(PlistService.self)!
}
func start() {
let isActivated: Bool?
isActivated = plistService.readPlist(namePlist: "Preferences", key: Constans.isActivated) as! Bool?
if isActivated != nil && isActivated! {
showTopic()
} else {
showSerial()
}
}
private func showSerial() {
let serialCoordinator = SerialCoordinator(container: container, navigationController: navigationController)
childCoordinators[.serial] = serialCoordinator
serialCoordinator.delegate = self
serialCoordinator.start()
}
private func showTopic() {
let topicCoordinator = TopicCoordinator(container: container, navigationController: navigationController)
childCoordinators[.topic] = topicCoordinator
topicCoordinator.delegate = self
topicCoordinator.start()
}
}
extension AppCoordinator: SerialCoordinatorDeligate {
func serialCoordinatorDidFinish() {
childCoordinators[.serial] = nil
showTopic()
}
}
extension AppCoordinator: TopicCoordinatorDeligate {
func topicCoordinatorDidFinish() {
childCoordinators[.topic] = nil
}
}
I understand that when my app starts it run Serial or Topic coordinator without restore logic. For example if user go to Topic coordinator, then to Auth coordinator (child of Topic coordinator), then to Home coordinator (child of Auth coordinator), how can I restore Home coordinator after start terminated by system app?
My ApplicationDelegate:
let customURLScheme = "dlscheme"
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIROptions.default().deepLinkURLScheme = self.customURLScheme
FIRApp.configure()
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any]) -> Bool {
return application(app, open: url, sourceApplication: nil, annotation: [:])
}
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let dynamicLink = FIRDynamicLinks.dynamicLinks()?.dynamicLink(fromCustomSchemeURL: url)
if let dynamicLink = dynamicLink {
let message = generateDynamicLinkMessage(dynamicLink)
if #available(iOS 8.0, *) {
showDeepLinkAlertView(withMessage: message)
}
return true
}
if #available(iOS 8.0, *) {
showDeepLinkAlertView(withMessage: "openURL:\n\(url)")
} else {
}
return false
}
#available(iOS 8.0, *)
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: #escaping ([Any]?) -> Void) -> Bool {
guard let dynamicLinks = FIRDynamicLinks.dynamicLinks() else {
return false
}
let handled = dynamicLinks.handleUniversalLink(userActivity.webpageURL!) { (dynamiclink, error) in
let message = self.generateDynamicLinkMessage(dynamiclink!)
self.showDeepLinkAlertView(withMessage: message)
}
return handled
}
func generateDynamicLinkMessage(_ dynamicLink: FIRDynamicLink) -> String {
let matchConfidence: String
if dynamicLink.matchConfidence == .weak {
matchConfidence = "Weak"
} else {
matchConfidence = "Strong"
}
let message = "App URL: \(dynamicLink.url)\nMatch Confidence: \(matchConfidence)\n"
return message
}
#available(iOS 8.0, *)
func showDeepLinkAlertView(withMessage message: String) {
let okAction = UIAlertAction.init(title: "OK", style: .default) { (action) -> Void in
print("OK")
}
let alertController = UIAlertController.init(title: "Deep-link Data", message: message, preferredStyle: .alert)
alertController.addAction(okAction)
self.window?.rootViewController?.present(alertController, animated: true, completion: nil)
}
Here is my code. I am working with firebase dynamic link, and implemented it like this tutorial:
https://firebase.google.com/docs/dynamic-links/ios
And this sample:
https://github.com/firebase/quickstart-ios/blob/master/dynamiclinks/DynamicLinksExampleSwift/AppDelegate.swift
Its working well when my app is in background. Open the app and show alert with url when I tap on dynamic link.
But in the case my app is inactive (not running), it not working. Just open the app and do nothing.
And my question: How can i handle dynamic link while app is inactive?
Sorry about my english
Swift 5
You can handle it in such way:
AppDelegate.swift
import Firebase
import FirebaseDynamicLinks
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// ... your other code here
FirebaseApp.configure()
let activityKey = NSString(string: "UIApplicationLaunchOptionsUserActivityKey")
if let userActivityDict = launchOptions?[.userActivityDictionary] as? [NSObject : AnyObject], let userActivity = userActivityDict[activityKey] as? NSUserActivity, let webPageUrl = userActivity.webpageURL {
DynamicLinks.dynamicLinks().handleUniversalLink(webPageUrl) { (dynamiclink, error) in
// do some stuff with dynamiclink
}
}
return true
}
I have do like this...
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool
{
if let option = launchOptions
{
if option.keys.contains(UIApplicationLaunchOptionsKey.userActivityDictionary)
{
if let userActivityDict = option[UIApplicationLaunchOptionsKey.userActivityDictionary] as? [AnyHashable:Any]
{
if userActivityDict.keys.contains(UIApplicationLaunchOptionsKey.userActivityType)
{
if let userActivity = userActivityDict["UIApplicationLaunchOptionsUserActivityKey"] as? NSUserActivity {
if let webpageURL = userActivity.webpageURL
{
// Write your code here.
}
}
}
}
}
}
}
I had a problem when application(_:open:options:) wasn't called when the app was in background. The Firebase SDK swizzles methods and that was the reason.
I solved this problem by setting FirebaseAppDelegateProxyEnabled = NO in Info.plist
For more detailed information on how it works and what it affects you can read here https://firebase.google.com/docs/cloud-messaging/ios/client#method_swizzling_in