I am very new to both firebase and Xcode SwiftUI. I found many tutorial on the storyboard but could not find tutorials for SwiftUI. I downloaded firebase using pod and the instruction given to us by the firebase documents. I created an AppDelegate.swift and copied the following code:
import Foundation
import UIKit
import Firebase
import SwiftUI
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions:
[UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
}
In the Firebase database, I created a user collection with an example value to test if it works.
So by using this link https://firebase.google.com/docs/firestore/quickstart?authuser=0#swift_3, I looked at the read data section and wrote the code in the ContentView.swift:
db.collection("users").getDocuments() { (querySnapshot, err) in
if let err = err {
print("Error getting documents: \(err)")
} else {
for document in querySnapshot!.documents {
print("\(document.documentID) => \(document.data())")
}
}
}
But It says that it has to be a view.
How can I get the data in the firebase database into my Swiftui app?
Related
It looks like for my app the firebase app check is not working with iOS16. I have configured the app attest and its been working for more than a year, it's still working with older iOS versions but not iOS 16.
This is the code that I initialise app check
import SwiftUI
import Firebase
import FirebaseAppCheck
#main
struct appointmeparterAppApp: App {
#Environment(\.scenePhase) var scenePhase
#UIApplicationDelegateAdaptor(AppDelegate.self) var delegate
init() {
let providerFactory = YourAppCheckProviderFactory()
AppCheck.setAppCheckProviderFactory(providerFactory)
FirebaseApp.configure()
}
}
class YourAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
return AppAttestProvider(app: app)
}
}
I am sure the problem is app check because if it's not enforced everything works as expected, and if I enforce it then i get permissions error. (this happens only on iOS 16)
import SwiftUI
import Firebase
import FirebaseCore
import FirebaseAppCheck
class AppDelegate: NSObject, UIApplicationDelegate {
let providerFactory = ACFTAppCheckProviderFactory()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
AppCheck.setAppCheckProviderFactory(providerFactory)
FirebaseApp.configure()
return true
}
}
#main
struct ACFTApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class ACFTAppCheckProviderFactory: NSObject, AppCheckProviderFactory {
func createProvider(with app: FirebaseApp) -> AppCheckProvider? {
return AppAttestProvider(app: app)
}
}
Set the App attest env. to production. Ensure you add App Attest capability to your app target. Remove the -FIRDebugEnabled in your app scheme/run/arguments. Possibly ensure you add the debug token to your registered apps/manage tokens on FB.
I am following the setup https://www.raywenderlich.com/18579842-firebase-analytics-getting-started
I am using flag -FIRAnalyticsDebugEnabled
I view the real-time result in Firebase Analytics Debug View
I also check the console output of XCode.
However, I notice that, if I write my code in the following way
Not receiving any Firebase analytics event
import Firebase
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
But, if I write the code in the following way
Receiving Firebase analytics first_open event
import Firebase
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
let title = "xxx"
Analytics.logEvent(AnalyticsEventSelectContent, parameters: [
AnalyticsParameterItemID: "id-\(title)",
AnalyticsParameterItemName: title,
AnalyticsParameterContentType: "cont",
])
return true
}
I need to logEvent a dummy event explicitly, in order to receive first_open.
May I know why is it so? Is there a way, I can still receive first_open event automatically, without having to log a dummy event?
This is the code snippet I am using, to ensure first_open event is sent to Firebase console.
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
FirebaseApp.configure()
// Not sure why. We need to call this function for first_open to be sent automatically.
// https://stackoverflow.com/questions/73600417/why-firebase-analytics-first-open-event-is-not-sent-automatically-unless-i-first
Analytics.setAnalyticsCollectionEnabled(true)
return true
}
I have verified by looking at Firebase console. The first_open event is received.
Still, I am not sure why such extra code snippet is required. I thought it should be sent automatically?
In my app I have admob ads and analytics. My assumption is that because of admob sdk, analytics stops working. This is certainly a bug.
Solution:
You will have to request iOS ATT alert or UMP consent from Google.
I prefer UMP sdk because it solves ATT alert and GDPR.
UMP sdk: https://developers.google.com/admob/ump/ios/quick-start
How it works: https://support.google.com/admob/answer/10115027
#main
struct MyApp: App {
init() {
FirebaseApp.configure()
Analytics.setAnalyticsCollectionEnabled(true) //this is explicitly needed
showConsent()
}
var body: some Scene {
WindowGroup {
RouterView()
}
}
private func showConsent() {
//request UMP consent or IDFA consent
}
Following various tutorials most of which seem to be from a couple years ago, I am trying to connect to Firebase from an IOS app and having trouble with how and where to import the libraries and, in turn, connect to the database.
In my app delegate, I am able to establish a connection--I think---inside the difFinishLaunching method (I say I think because Firebase does not recognize the app in the console but this seems to be a frequent occurrence so I'm ignoring that and just trying to get the app to build in Xcode for now) as follows:
import UIKit
import FirebaseAnalytics
import FirebaseDatabase
import FirebaseCore
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
FirebaseApp.configure()
let myDB = Database.database().reference().child("items")
}
return true
}
That seems okay in that it builds.
When I try to put a reference to the database in a viewcontroller, however, it throws an error on Database:
import UIKit
import FirebaseCore
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
let ref = Database.database().reference(withPath: "items") //THIS LINE THROWS ERROR
What do I need to do to create a property for the Database in a view controller?
Edit: Looking at some other answers on SO, it seems I may have to create a singleton reference to the db connection. If so, where would I put this and how would I reference it?
Thanks for any suggestions
First, your AppDelegate should look something like this
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
FirebaseApp.configure()
return true
}
then, in your first viewController like this:
import UIKit
import Firebase
class ViewController: UIViewController {
var db: Firestore!
override func viewDidLoad() {
super.viewDidLoad()
self.db = Firestore.firestore()
//do something with Firestore
var ref: DocumentReference? = nil
ref = db.collection("users").addDocument(data: [
"first": "Ada",
"last": "Lovelace",
"born": 1815
]) { err in
if let err = err {
print("Error adding document: \(err)")
} else {
print("Document added with ID: \(ref!.documentID)")
}
}
}
}
Keep in mind I have set my Firestore rules to allow anyone to read/write, which is dangerous so please start working through the Authentication guide once you get this working.
Note that the above code pretty much came straight from the Getting Started guides Add Firebase To An App and Installation and setup
Based on advice, I would like to manage API keys using Firebase Remote Config to avoid hard-coding API keys like google_maps_flutter suggests. It has an AppDelegate.swift like:
import UIKit
import Flutter
import GoogleMaps
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GMSServices.provideAPIKey("YOUR KEY HERE")
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
How can the above be modified to fetch the API key from Firebase Remote Config and then pass it to GMSServices?
Based on this article, I came up with:
import UIKit
import Firebase
import Flutter
import GoogleMaps
//import os.log
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure()
RemoteConfig.remoteConfig().fetchAndActivate() { status, error in
let apiKey : String = RemoteConfig.remoteConfig()["Google_Maps_SDK_for_iOS_API_KEY"].stringValue ?? "MISSING";
// os_log("Google_Maps_SDK_for_iOS_API_KEY = '%#'", apiKey)
GMSServices.provideAPIKey(apiKey)
}
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Is there a better way?
I was thinking of making this as a comment, but decided to make it as my answer as it was too long.
I think it's one way of getting keys from remoteConfig, but again failure can happen where fetch config was not retrieved. One way to solve it is by having a force refresh when it fails, but then again you are relying on firebase for those keys and if for some reason (experienced it before firebase was acquired by google) it went down your app then will be unuseable (so as for many apps).
For me, I still put my API keys bundled with the app just to make sure all the important functionality works.
Another option will be having your API Keys bundled and then having a WebService call to check for new keys once the current keys you have has expired/change. That way you have the capability to immediately expire your keys and change it to another one.
I am new to firebase and trying to write some data to firebase.
My problem is below :
installed pod 'Firebase/Core'
pod 'Firebase/Database' coacopods
and import Firebase in Xcode, also changed realtime database rule both "read" and "write" are true, everything is connected to google firebase, but still can't write data in realtime database? anyone has same problem like me? can anyone help me to fix it?
code
part one(AppDelegate.swift):
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
**FirebaseApp.configure()**
return true
}
part two(ViewController.swift):
import UIKit
import Firebase
import FirebaseDatabase
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
**let ref = Database.database().reference()**
**ref.child("someid/name").setValue("mike")**
}
}
There is no any error message showing in Xcode or firebase.
I suggest you update your GoogleService-Info.plist by downloading from your console again. This solved my problem.
override func viewDidLoad() {
super.viewDidLoad()
let ref = Database.database().reference()
let value = [
"name": "mike"
] as [String: Any]
ref.child("someid/name").setValue(value)
}