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.
Related
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
}
android works well
2.from firebase site to iOS real device works well (below this push to ios is ok)
3. remote push from iOS to andriod works well
but remote push message to iOS not working
my Xcode
my info
my Appdelegate.swift
import UIKit
import Flutter
import Firebase
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
FirebaseApp.configure() //add this before the code below
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
Actually I had faced this issue , after long research realised that I haven't permit permission for notification, so used permission_handler plugin to ask permission for remote notification .
like this:
Future<Map<Permission, PermissionStatus>> requestPermission() async {
Map<Permission, PermissionStatus> statuses = await [
Permission.notification
].request();
return statuses;
}
Uninstall the application
add above code
Call this function at starting
give permission
How do i register all my plugins when presenting a view controller with implicit engine?
https://flutter.dev/docs/development/add-to-app/ios/add-flutter-screen#alternatively---create-a-flutterviewcontroller-with-an-implicit-flutterengine
When you create new project in Flutter it already ships with code the registers the plugin. Check if you have following;
Android
In your Android project find MainActivity.kt.
Important: Notice that FlutterActivity exist in both io.flutter.embedding.android and io.flutter.app but first one automatically registers all the plugins.
package com.example.myapp
import io.flutter.embedding.android.FlutterActivity
// do not import io.flutter.app.FlutterActivity instead
class MainActivity: FlutterActivity() {
}
iOS
In your iOS project find AppDelegate.swift
import UIKit
import Flutter
import FlutterPluginRegistrant
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
lazy var flutterEngine = FlutterEngine(name: "my flutter engine")
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
GeneratedPluginRegistrant.register(with: self.flutterEngine)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
P.S. Make sure you update the Flutter version to get most of it.
iOS reference
So I made a project that included lots of extra code so I could try out different things, and I am slowly copy-pasting the files from textedit into my new project.
I created a new Firebase account, added the google plist file, initialized and installed the pods needed (also changed the iOS version to 10.0 on the pod file)... yet it's still wanting me to use FirebaseApp.configure() instead of FIRApp.configure().
Should I just delete the whole thing and try again? I just created a new Xcode project, so if I had to delete it right now that would be fine.
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
override init() {
super.init()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
FIRApp.configure()
return true
}
There hasn't been much code written, but I can't figure out what could have made this happen... especially since I just started the new project.
FirebaseApp.configure() is correct. I checked out the documentation just now and FIRApp.configure() has been renamed FirebaseApp.configure(). I also ran pod update on one of my projects just to confirm, and my project had me change to using FirebaseApp.configure(). So no need to rebuild!
I can confirm that FIRApp.configure() can be changed to FirebaseApp.configure()
In firebase it suggest to add the following to app delegate:
"
import UIKit import Firebase
#UIApplicationMain class AppDelegate: UIResponder,
UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?)
-> Bool {
FirebaseApp.configure()
return true } }
"
This includes the FirebaseApp.configure() command
So I am attempting to integrate Google's Firebase into my SpriteKit game and was having a small issue.
The instruction from Firebase is..."Configure a FIRApp shared instance, typically in your application's application:didFinishLaunchingWithOptions: method:FirebaseApp.configure()".
Now I've located the file called AppDelegate.swift in my Xcode project but when I place it into the first function, which matches the named one in the instructions I get the following error Use of unresolved Identifier FirebaseApp.
And I remembered to import Firebase at the top of document. Any suggestions?
It is FIRApp, not FirebaseApp.
FIRApp.configure()
Note: Don't forget to import the Firebase module.
import Firebase
Your app delegate needs to look something like this:
import UIKit
import Firebase
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
FIRApp.configure()
return true
}
}
Make sure you call FIRApp.configure() before the return true and remember to import Firebase.