How to get UIWindow value in iOS 14 #main file? - ios

I can able to access didFinishLaunchingWithOptions by below implementation. But, I need UIWindow variable. I don't know how to get it. I'm using Xcode 12 beta. iOS14, SwiftUI lifecycle.
import SwiftUI
#main
struct SSOKit_DemoApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
print("hello world!!!")
return true
}
}

From iOS 13 onwards, it's safe to assume that the correct way to obtain a reference to the key window is via UIWindowSceneDelegate.
#main
struct DemoApp: App {
var window: UIWindow? {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
let window = windowSceneDelegate.window else {
return nil
}
return window
}
[...]
}

iOS 14.7
#main
struct TestApp: App {
var window: UIWindow? {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowScene = scene as? UIWindowScene else {
return nil
}
return .init(windowScene: windowScene)
}
}

Related

SwiftUI app doesn't run when supporting iOS 13

App was working fine when the deployment target was 15.2, but then I needed to change the deployment target to iOS 13 to support more devices. Still works fine on iOS 14+, but it crashes with exception Thread 1: signal SIGABRT, when it runs on iOS 13 on the simulator. Console shows no debug information:
CoreSimulator 802.6 - Device: iPhone 11 (iOS 13.0) (6CCC2B89-002B-4E83-8175-C244984BFC46) - Runtime: iOS 13.0 (17A577) - DeviceType: iPhone 11
Message from debugger: Terminated due to signal 9
Here are the related segments of the WeatherApp.swift file code along with a screenshot of the error:
#main
struct WeatherAppWrapper {
static func main() {
if #available(iOS 14.0, *) {
WeatherApp.main()
}
else {
UIApplicationMain(CommandLine.argc, CommandLine.unsafeArgv, nil, NSStringFromClass(SceneDelegate.self))
}
}
}
struct WeatherApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
#StateObject var loginStatus = UserLoginStatus()
#available(iOS 14.0, *)
var body: some Scene {
WindowGroup {
NavigationView{
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
MainView(loggedIn: $loginStatus.loggedIn)
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
} else {
LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
MainView(loggedIn: $loginStatus.loggedIn)
}
}
}
}
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//Some app-specific setup code
...
return true
}
}
}
class UserLoginStatus: ObservableObject {
#Published var loggedIn: Bool {
didSet {
print("The value of loggedIn changed from \(oldValue) to \(loggedIn)")
}
}
init () {
loggedIn = false
}
}
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
#StateObject var loginStatus = UserLoginStatus()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loggedIn: $loginStatus.loggedIn)
let loginView = LoginView(username: "", password: "", loggedIn: $loginStatus.loggedIn)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
if Methods.UserAccount.getFromUserDefaults()["username"] != nil {
window.rootViewController = UIHostingController(rootView: mainView)
} else {
window.rootViewController = UIHostingController(rootView: loginView)
}
self.window = window
window.makeKeyAndVisible()
}
}
}
Also, here is a screenshot of the Info.plist file, specifically expanding the related area:
The StateObject is available from SwiftUI 2.0 (iOS 14) and is designed to work in View, not in class (like SceneDelegate)
For provided scenario a possible solution is to use logicState as just property at top level (in delegate or main view), but inject it completely into child views (instead of just binding) and observe it internally.
So it should look like
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var loginStatus = UserLoginStatus() // << just hold here
// ...
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let mainView = MainView(loginStatus: loginStatus) // << here !!
and
struct MainView: View {
#ObservedObject var loginStatus: UserLoginStatus // << injected here
// ...
}
similar can be done in WeatherApp
According to Apple docs, StateObject is only available on iOS 14+.

Run a Swift UI Page from Flutter AppDelegate.swift file

I want to run a custom Swift UI page in my flutter application. I am trying to call ios platform specific code using method channel. My target is when i call a method using method channel i will present the Swift UI view in front of user.
My AppDelegate.swift file is below:
import UIKit
import Flutter
#UIApplicationMain
#objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let batteryChannel = FlutterMethodChannel(name: "yourpackageName/channelName",
binaryMessenger: controller.binaryMessenger)
batteryChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: #escaping FlutterResult) -> Void in
if call.method == "showPage"{
//run a swift ui view here
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
And my custom Swift UI file is below:
import SwiftUI
#available(iOS 13.0, *)
struct CustomPage: View {
var body: some View {
Text("Hello, World!")
}
}
#available(iOS 13.0, *)
struct CustomPage_Previews: PreviewProvider {
static var previews: some View {
CustomPage()
}
}
Is there any way i can achieve this?

Cannot call value of non-function type 'GIDSignIn'

I'm trying to implement google sign in into my app. But the problem is when i add this line of code to my App.swift file i'm getting an error. I tried to remove the () from the sharedInstance but if i do this i'm getting another error (Value of type 'GIDSignIn' has no member 'clientID'). I'm beginner on swift and swiftUI
The error:
Cannot call value of non-function type 'GIDSignIn'
Line of code:
GIDSignIn.sharedInstance.clientID = FirebaseApp.app()?.options.clientID
My App.swift File:
//
// iGrow_GoalsApp.swift
// iGrow Goals
//
// Created by George Sepetadelis on 3/8/21.
//
import SwiftUI
import Firebase
import FirebaseAuth
import GoogleSignIn
import UserNotifications
#main
struct iGrow_GoalsApp: App {
#UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var body: some Scene {
WindowGroup {
let viewModel = AppViewModel()
ContentView()
.environmentObject(viewModel)
}
}
}
extension iGrow_GoalsApp {
func setUpAthetication() {
FirebaseApp.configure()
}
}
class AppDelegate : NSObject, UIApplicationDelegate {
var window: UIWindow?
func application(
_ app: UIApplication,
open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]
) -> Bool {
var handled: Bool
handled = GIDSignIn.sharedInstance.handle(url)
if handled {
return true
}
// Handle other custom URL types.
// If not handled by this app, return false.
return false
}
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
FirebaseApp.configure()
GIDSignIn.sharedInstance.clientID = FirebaseApp.app()?.options.clientID
return true
}
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
(UIApplication.shared.delegate as? AppDelegate)?.self.window = window
guard let _ = (scene as? UIWindowScene) else { return }
}
}
I was having the same issue until I used this version of GoogleSignIn
pod 'GoogleSignIn', '~> 4.4.0'

Print DataBase in swift [duplicate]

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
}

iOS - Restore app state by coordinators after terminate

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?

Resources