Deeplinking to swift app when app is closed - swift

I am working on adding deep linking to my app so that the app will go to a separate page when launched through a deep link. This code that I have so far works perfectly the only issue is that it dosen't work when the app is closed. Is there any way to make this code work when the app is not already running? Thanks for any help in advance!
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
if let url = URLContexts.first?.url{
print(url)
let urlStr = url.absoluteString
if urlStr.contains("deeplinktopage") {
variable = "NotNone"
if variable != "None" {
DispatchQueue.main.async {
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homePage = mainStoryboard.instantiateViewController(withIdentifier: "VIEWCONTROLLER") as! VIEWCONTROLLER
self.window?.rootViewController = homePage
}
}
else {
DispatchQueue.main.async {
print("HERE")
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let homePage = mainStoryboard.instantiateViewController(withIdentifier: "VIEWCONTROLLER") as! VIEWCONTROLLER
self.window?.rootViewController = homePage
}
}
}
}
}
func pushToProductDetailSceen(productId: String)
{
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
}

Related

Navigation Controller does not appear, Xcode 14.2, IOS 16, Swift 5.7

I want the View Controller with Navigation Controller to be displayed when the application starts up, I use the following code to do this, but Navigation Controller is not displayed when the application starts up. I'm creating application without using Storyboard, and removed Storyboard itself
import UIKit
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var navController = UINavigationController()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: windowScene)
let viewController = ViewController()
self.navController = UINavigationController(rootViewController: viewController)
self.window?.rootViewController = navController
self.window?.backgroundColor = UIColor.yellow
self.window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}

Unable to access root view after adding SceneDelegate swift 5

I have an app where users can login / sign out and the functionality stopped working recently when I added a new SceneDelegate view and moved over the code from the AppDelegate. I'm not sure why it is not working but I suspect it has to do with using the shared delegate in my signOut function.
Something strange is happening, when I tap the sign out button nothing happens. However, when I close the app and open it again, I will be signed out.
Here is the code on my home screen for the sign out button:
#IBAction func signOutButtonTapped(_ sender: Any) {
KeychainWrapper.standard.removeObject(forKey: "accessToken")
KeychainWrapper.standard.removeObject(forKey: "userID")
// send user to splash page
let signInPage = self.storyboard?.instantiateViewController(withIdentifier: "splashController") as! splashViewController
let appDelegate = UIApplication.shared.delegate
appDelegate?.window??.rootViewController = signInPage
}
This is the code from my SceneDelegate.swift file:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
let accessToken: String? = KeychainWrapper.standard.string(forKey: "accessToken")
// If access token exists, skip login page
if accessToken != nil {
if let windowScene = scene as? UIWindowScene {
self.window = UIWindow(windowScene: windowScene)
let mainStoryboard:UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc = mainStoryboard.instantiateViewController(withIdentifier: "homeTabController") as! TabBarController
self.window!.rootViewController = vc
}
}
}
}
You've answered your own question. With a scene delegate, the window belongs to the scene delegate. The app delegate window is nil. So this line does nothing:
appDelegate?.window??.rootViewController = signInPage
Figured it out - add a new var in SceneDelegate
static weak var shared: SceneDelegate?
Then replace the appDelegate.window line with
let appDelegate = SceneDelegate.shared

Google AdMob showing full-screen ad on the side

I'm using the AdMob SDK to show ads in my app.
The problem is that on iPad the ad is on the side when iPad is on Landscape mode:
I was wondering if this is a bug and if there is a workaround for it.
This is the code in my SceneDelegate:
import UIKit
import GoogleMobileAds
class SceneDelegate: UIResponder, UIWindowSceneDelegate, GADFullScreenContentDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
guard let _ = (scene as? UIWindowScene) else { return }
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
tryToPresentAd()
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
// ADS
private var lastAdDate: Date?
func requestAppOpenAd() {
var appOpenAd: GADAppOpenAd? = nil
let request = GADRequest()
GADAppOpenAd.load(withAdUnitID: "ca-app-pub-3940256099942544/5662855259",
request: request,
orientation: UIInterfaceOrientation.portrait,
completionHandler: { [self] (appOpenAdIn, err) in
// Ad loaded
appOpenAd = appOpenAdIn
appOpenAd?.fullScreenContentDelegate = self
if let viewcontroller = adPresentationViewController() {
DispatchQueue.main.async {
appOpenAd?.present(fromRootViewController: viewcontroller)
}
}
self.lastAdDate = Date()
print("Ad is ready")
print(err as Any)
})
}
private func adPresentationViewController() -> UIViewController? {
return window?.rootViewController
}
private func tryToPresentAd() {
guard shouldShowFullScreenAd() else {
return
}
self.requestAppOpenAd()
}
/// Returns false if 5 minutes did not pass since last ad.
private func shouldShowFullScreenAd() -> Bool {
let now = Date()
guard let lastAdDate = lastAdDate else {
return true
}
let time: TimeInterval = 5 * 60 // 5 minutes
let shouldshow: Bool = now.timeIntervalSince(lastAdDate) >= time
return shouldshow
}
func ad(_ ad: GADFullScreenPresentingAd, didFailToPresentFullScreenContentWithError error: Error) {
print("Advert error")
print(error)
}
func adWillPresentFullScreenContent(_ ad: GADFullScreenPresentingAd) {
print("adWillPresentFullScreenContent")
}
}

Could not find keyboard scene delegate for interaction view

Below iOS 13 my UITextField correctly launches a keyboard and lets the user type in their answer.
Above iOS 13, textFieldDidBeginEditing() is triggered when I tap on the text field, but the keyboard is not shown, so the user cannot give their answer .
Debug console doesn't immediately throw any errors, but eventually the following message comes up, which I think is the key:
Could not find keyboard scene delegate for interaction view
I think the error appears in the later iOSs because scenes become the main thing - and somewhere I needed to set up a delegate to allow the keyboard to appear over the fron of the first scene.
No idea how to do this though!
My UITextField is totally standard. To reproduce the error, I have the following set up code in my SceneDelegate
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
let windowScene = UIWindowScene(session: session, connectionOptions: connectionOptions)
self.window = UIWindow(windowScene: windowScene)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "VC" )
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
guard let _ = (scene as? UIWindowScene) else { return }
}
In my actual app - I use this subroutine to launch a tutorial if the user is new (i.e. I need to be able to change the starting view controller)
Something appears to be out of sorts in your SceneDelegate function scene().
Try this code which I grabbed from another project I have at hand.
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: windowScene.coordinateSpace.bounds)
window?.windowScene = windowScene
self.window?.rootViewController = ViewController()
self.window?.makeKeyAndVisible()
}

Unbalanced calls to begin/end appearance transitions; what's the proper way to set up this transition?

I have an onboarding flow that I want to present to a new user before letting them into the app. I want to specifically use present() to do this so that I can nicely dismiss() the onboarding flow. This code is working, but I am getting the unbalanced transition warning on the TabBarController. Is there a better way to do this?
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let winScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: winScene)
Core.shared.setIsNewUser()
if Core.shared.isNewUser() {
let tabBarCon = TabBarController() // this is the root of the main app
let welcomeViewCon = UINavigationController.init(rootViewController: OBPage0()) // This is my onboarding flow
window?.rootViewController = tabBarCon
window?.makeKeyAndVisible()
welcomeViewCon.modalPresentationStyle = .fullScreen
tabBarCon.present(welcomeViewCon, animated: true, completion: nil)
}
Note: I know that there are many questions with a similar title, I have reviewed them and still not found an answer to this problem.