How to configure Firebase App multiple times? [duplicate] - firebase

I have an app already that I was able to build completely with SwiftUI.
I was using Firebase for authentication and notifications using Cloud Functions.
Now with the new SwiftUI App->Scene->View construct, I am unable to add the setup to my app.
For example -> The initial FirebaseApp.configure() would initially go in didFinishLaunchingWithOptions in AppDelegate, now I am at a loss of where to add this configuration.
Same goes with setting up remote notifications.
PS: Please comment if more details/code of the previous app is required. I did not add any code, cause I felt it was unnecessary.

There are three approaches for initialising third part frameworks in the new SwiftUI life cycle:
Using the old life cycle model
You can still use the old life cycle model:
Option 1: Use the UIKit App Delegate life cycle
When creating a new SwiftUI project, you can choose the old life cycle model. This will create an AppDelegate and a SceneDelegate as before. Not as fancy as using SwiftUI all the way, I admit - but definitely the easiest and most straightforward way.
Using the new life cycle model
If you want to use the new life cycle model, use either one of the following approaches.
Option 2: Use the App's initialiser
You can override the default initialiser of your App class, like this:
import SwiftUI
import Firebase
#main
struct SO62626652_InitialiserApp: App {
init() {
FirebaseApp.configure()
}
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
Option 3: Use # UIApplicationDelegateAdaptor
In you App class, define a property that holds a reference to your AppDelegate, and let SwiftUI inject the AppDelegate using the # UIApplicationDelegateAdaptor property wrapper, like this:
import SwiftUI
import Firebase
#main
struct SO62626652_AppDelegateAdaptorApp: App {
#UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
FirebaseApp.configure()
return true
}
}

Found the answer on the link below:
hackingWithSwift
The code from the page is below:
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("Your code here")
FirebaseApp.configure()
return true
}
}
And inside the App
we need to add the below line:
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate.
The explanation is on the link.

Related

Ionic discards changes in global css variable after closing the app

I want to enable my users to set certain global colors when using the app. Therefor I have created a 'dynamicVariables.css' file:
:root {
--my-color: violet;
}
It is imported in 'global.scss' file:
#import "./theme/dynamicVariables.css";
Also, I've added a colorpicker on one page and I can set the --my-color variable fine from there.
onColorChange(data: any) {
document.documentElement.style.setProperty('--my-color', data);
}
Just when closing the app on my device (I've deployed it with ionic capacitor run android), it resets the css variable, because when I run it again the color is back to its default value.
I'm pretty sure, I have a general misconception here and would be grateful for some clarification. I'm generally new to web development and would be grateful for any help.
Thanks in advance.
just like how Mustafa explained in comments, you need to make these changes outside app "runtime" and in the device's memory, that would stay there even after the app (whether web or native) is closed. for example you can use ionic storage and save your data with keys and values same as your css keys, and load it up whenever the app opens.
Thanks to the responds, I was able to solve the problem with the help of Ionic Storage.
First, I created a Storage Service:
import { Storage } from '#ionic/storage-angular';
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class StorageService {
private _storage: Storage | null = null;
constructor(private storage: Storage) {
}
async init() {
const storage = await this.storage.create();
this._storage = storage;
}
public set(key: string, value: any) {
this._storage?.set(key, value);
}
public get(key: string) {
return this._storage?.get(key);
}
}
When starting the app, I run the following code in the app.component.ts
async ngOnInit() {
await this.storageService.init();
let storedPathologicalColor = await this.storageService.get('--my-color');
if (storedPathologicalColor == null)
document.documentElement.style.setProperty('--my-color', getComputedStyle(document.documentElement).getPropertyValue('--my-color'))
else
document.documentElement.style.setProperty('--my-color', storedPathologicalColor);
}
It is important to init() the service from outside. When setting a new css variable, I also set a new key/value pair to the Storage.
Thanks again.

HOCs, Context API and Next Pages

Its possible to use Hoc with context api inside a next page?
I have a next page generated by SSR, and a HOC privateRoute to validate authorization on this page. But for every access, we have a authorization request and its sound's me like a problem.
My idea is to use contexApi to get data one time, and reuse that on auth private route.
Anyone has a minimal exemple about?
Thanks.
I found a solution.
The problem was to use Context inside react class component.
mport React, { Component } from 'react'
import UserContext from './UserContext'
class HomePage extends Component {
static contextType = UserContext
componentDidMount() {
const user = this.context
console.log(user) // { name: 'Tania', loggedIn: true }
}
for more, see https://www.taniarascia.com/using-context-api-in-react/
render() {
return <div>{user.name}</div>
}
}

SwiftUI : how to access UINavigationController from NavigationView

I am developing an app using SwiftUI. The app is based around a NavigationView.
I am using a third-party framework that provides UIKit components and the framework has not been updated to support SwiftUI yet.
One framework method is expecting a parameter of type UINavigationController
How can I supply this framework the NavigationController created by SwiftUI ? Or how can I create a UINavigationController that will replace SwiftUI's default ?
I read https://developer.apple.com/tutorials/swiftui/interfacing-with-uikit and https://sarunw.com/posts/uikit-in-swiftui but these seems to address another question : they explain how to use UIKit components in a SwiftUI app. My problem is the other way around, I want to use SwiftUI App and access underlying NavigationController object.
[UPDATE]
The code implementing my solution is available from this workshop : https://amplify-ios-workshop.go-aws.com/30_add_authentication/20_client_code.html#loginviewcontroller-swift
Thanks to Yonat's explanation I understood how to do this and here is my solution, hoping it will help others.
Part 1 : The UI View Controller that will be used from Swift UI. It calls a third-party authentication library, passing the UINavigationControler as parameter. The UINavigationController is an empty view, just there to allow the third-party authentication library to have a Navigation Controller to pop up the Login Screen.
struct LoginViewController: UIViewControllerRepresentable {
let navController = UINavigationController()
func makeUIViewController(context: Context) -> UINavigationController {
navController.setNavigationBarHidden(true, animated: false)
let viewController = UIViewController()
navController.addChild(viewController)
return navController
}
func updateUIViewController(_ pageViewController: UINavigationController, context: Context) {
}
func makeCoordinator() -> Coordinator {
return Coordinator(self)
}
class Coordinator: NSObject {
var parent: LoginViewController
init(_ loginViewController: LoginViewController) {
self.parent = loginViewController
}
}
func authenticate() {
let app = UIApplication.shared.delegate as! AppDelegate
let userData = app.userData
userData.authenticateWithDropinUI(navigationController: navController)
}
}
Part 2 : The Swift UI View is displaying the (empty) UINavigationControler and overlays a SwiftUI view on top of it.
import SwiftUI
struct LandingView: View {
#ObservedObject public var user : UserData
var body: some View {
let loginView = LoginViewController()
return VStack {
// .wrappedValue is used to extract the Bool from Binding<Bool> type
if (!$user.isSignedIn.wrappedValue) {
ZStack {
loginView
// build your welcome view here
Button(action: { loginView.authenticate() } ) {
UserBadge().scaleEffect(0.5)
}
}
} else {
// my main app view
// ...
}
}
}
}
I don't think you can do that right now. Looking at the view debugger for NavigationView I get the image below.
So it seems to you will have to go the other way around:
Start with a UINavigationController, and wrap the SwiftUI view(s) in UIHostingController.
I tried to do the same thing because I wanted to make the interactivePopGestureRecognizer work on the whole view.
I managed to access the current navigation controller using an UINavigationController extension and overriding viewDidAppear, checking if the interactivePopGestureRecognizer was enabled and changed it ( https://stackoverflow.com/a/58068947/1745000)
At the end my effort was pointless. When the navigation view presented the DetailHostingController, it toggled off interactivePopGestureRecognizer.isEnabled!
The hosting view via topViewController.view does contain a gesture recogniser of private type SwiftUI.UIGestureRecognizer. No targets are set though...
Embedding a traditional UINavigationController may also be preferred because navigation view's own pop gesture isn't cancellable (if you drag the view a little bit and stop, it snaps back and then dismiss the detail view.

Why my kotlin code for Firebase authentication not working?

I am enrolled in online CBT and learning Kotlin for android programming. The video tutes were made in 2017 and I got codes of the apps that were made in the to the tutorial series. I have followed every step till I connect my app with Firebase and even entered sample user data in Authentication and set Usage Rules to public, but to my surprise same Kotlin code which was shown to be working flawlessly in video tutorials does not work for me.
Then I tried sample LoginActivity.kt and RegisterActivity.kt codes from github, even those codes does not work. Please look at my codes and help me sort out this issue.
When I click on loginBtn the app crashes and not data is sent to Firebase. Logcat shows following error:
java.lang.IllegalStateException: Default FirebaseApp is not initialized in this process com.paramlowe.mypg2. Make sure to call
FirebaseApp.initializeApp(Context) first.
at com.google.firebase.FirebaseApp.getInstance(SourceFile:218)
at com.google.firebase.auth.FirebaseAuth.getInstance(Unknown Source:1)
at com.punjabweb.myapp.LoginActivity.loginUser(LoginActivity.kt:50)
at
com.punjabweb.myapp.LoginActivity.access$loginUser(LoginActivity.kt:25)
at
com.punjabweb.myapp.LoginActivity$onCreate$2.onClick(LoginActivity.kt:43)
and my kotlin code for LoginActivity.kt is here below:
package com.punjabweb.myapp2
import android.content.Intent
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.text.TextUtils
import android.view.View
import android.widget.Button
import android.widget.Toast
import com.google.firebase.auth.FirebaseAuth
import kotlinx.android.synthetic.main.activity_login.*
class LoginActivity : AppCompatActivity() {
//Firebase references
private var mAuth: FirebaseAuth? = null
// FirebaseApp.initializeApp(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
val loginBtn = findViewById<View>(R.id.btnLogin) as Button
loginBtn.setOnClickListener {
loginUser()
}
}
private fun loginUser() {
mAuth = FirebaseAuth.getInstance()
val email = etEmail?.text.toString()
val password = etPassword?.text.toString()
if (TextUtils.isEmpty(email) && TextUtils.isEmpty(password)) {
Toast.makeText(this, "Enter all details", Toast.LENGTH_SHORT).show()
} else {
mAuth!!.signInWithEmailAndPassword(email, password)
.addOnCompleteListener(this) { task ->
if (task.isSuccessful) {
// Sign in success, update UI with signed-in user's information
var firebasUser = FirebaseAuth.getInstance().currentUser!!
// updateUI()
} else {
// If sign in fails, display a message to the user.
Toast.makeText(
this#LoginActivity, "Authentication failed.",
Toast.LENGTH_SHORT
).show()
}
}
}
fun updateUI() {
val intent = Intent(this#LoginActivity, MainActivity::class.java)
// intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
startActivity(intent)
}
}
}
You need to enable the firebase email authentication in the console. Seems like your code is ok in the first look.
This could potentially be cause because you don't have the google-services plugin at the end of app gradle:
dependencies {
....
}
apply plugin: 'com.google.gms.google-services'

Some seemingly useless cruft when deriving from UINavigationController in swift

Why do I need so much (seemingly useless) pass through code that objc did not
require in a similar derivation:
class myNavigationController: UINavigationController {
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
}
...
repeat ad nauseam for every single view controller of mine loaded from xib.
This should not be an issue if your don't want to overload the designated initializer init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) your UINavigationController subclass. If you just want to make use of the default (super) initializer, you can remove both those methods from your class.
I.e., the following class
// MyNavigationController.swift
import UIKit
class MyNavigationController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
// I don't want to make use of this ...
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// ... nor this
}
// Things I do want to do with my nav. controller
}
can be reduced to
// MyNavigationController.swift
import UIKit
class MyNavigationController: UINavigationController {
// Things I do want to do with my nav. controller
}
Without any errors. (Verified in Swift 2.0, Xcode 7.2, simulator: iOS 9.2). This is expected behavior, see e.g. the accepted answer in thread 'required' initializer 'init(coder:)' must be provided by subclass of 'UITableViewCell'`.
If you still get an error when removing these for this subclass type, please give some details regarding your use of the class / Xcode version etc.

Resources