Using showBluetoothAccessoryPicker causes SceneDelegate presenting errors - ios

I currently have an app that will try to automatically discover a MFi bluetooth device.
The only way is to use the ExternalAccessory framework, as CoreBluetooth only files Ble devices.
Right now I have a button that executes:
EAAccessoryManager.shared().showBluetoothAccessoryPicker(withNameFilter: nil) { error in }
In order for the picker to appear, I need to add var window: UIWindow? inside my AppDelegate
So far this works. The picker shows, and will list the device I want to connect to. However When I try clicking the device for it to pair, I get this message:
2020-11-11 14:07:16.694761-0700 BT[500:48034] [Presentation] Attempt to present <UIAlertController: 0x105013a00> on <_TtGC7SwiftUI19UIHostingControllerV2BT11ContentView_: 0x104a0a510> (from <_TtGC7SwiftUI19UIHostingControllerV2BT11ContentView_: 0x104a0a510>) which is already presenting <UIAlertController: 0x105052800>.
Which does make sense. Currently the picker is presenting and then another alert is trying to be displayed to validate the pin and pair.
But if I delete the Application Scene Manifest in the info.plist, delete the SceneDelegate and remove all UISceneSession Lifecycle functions in the AppDelegate, it works..
The issue is I need the SceneDelegate as it's a swiftUI app and will fail to run otherwise.
Has anyone ran into this issue before?

Related

Is it safe to remove SceneDelegate from Existing project?

I have my project which supports minimum ios version 12.4 and I'm using swift 5.2 in my project. To suuport Zoom SDK I need to remove sceneDelegate.swift file and SceneManifest from info.plist. Is it safe to remove sceneDelegate from existing project?
In my thought AppDelegate will be responsible for the application lifecycle and setup. The SceneDelegate will be responsible for what is shown on the screen (Windows or Scenes) handle and manage the way your app is shown.So will there be any issues in UI Flow of my APP if I remove Scene Delegate?
If I remove sceneDelegate how will handle app Foreground and Background Events?
Yes it 100% safe to remove SceneDelegate from your iOS app.
Please refer below steps to remove it from your app
Remove SceneDelegate.swift file
Remove Application Scene Manifest from Info.plist file
Add var window: UIWindow? to AppDelegate.swift
Replace #main with #UIApplicationMain
Remove UISceneSession Lifecycle ( functions ) in AppDelegate
After deleting scene delegate you would not able to do following
In iOS 13 and later, users can create multiple copies of your app’s UI
and toggle between them in the app switcher. On iPad, users can also
display one copy of your app’s UI side by side with another copy. For
each copy of your app’s UI, you use a scene object to manage the
window, views, and view controllers that present the UI onscreen
https://developer.apple.com/documentation/uikit/app_and_environment/scenes/specifying_the_scenes_your_app_supports
To answer you question to regarding view life cycle please refer this - https://www.appypie.com/scene-delegate-app-delegate-xcode-11-ios-13#:~:text=On%20iOS%2013,at%20a%20time.

Is SceneDelegate mandatory? [duplicate]

This question already has answers here:
Opt out of UISceneDelegate/SwiftUI on iOS
(6 answers)
Closed 3 months ago.
The question says it all.
There's the following line in apple documentation,
Scenes are opt in, but you must support them if you want to display
multiple copies of your app’s UI simultaneously.
It's not mentioned whether the SceneDelegate is mandatory or optional or a recommendation (I'm aware that the SceneDelgate is used to handle the lifecycle of the scene).
In a iOS 13+ device, can I create an app without SceneDelegate?
I defined the UIWindow variable in the AppDelgate and set the ViewController in application(didFinishLaunchingWithOptions), like before iOS 13. But that doesn't work and displays a blank screen.
And thus, this question. Is Scenedelgate mandatory even if we don't opt for multiple scenes?
Here's my observation:
Multiple scenes are optional. But you still have to support at least
one scene... and for that, SceneDelegate is mandatory.
If I'm wrong and SceneDelegate is optional (like described in this stackoverflow post), please help with the flows.
In a iOS 13+ device, can I create an app without SceneDelegate?
Yes. All apps do have scenes, but if you go with the app-delegate-only architecture, a single UIWindowScene will be created behind the scenes (pun intended). The app will run perfectly well on both iPhone and iPad, with all the usual lifetime events arriving as usual into the app delegate (though I do not know what will happen on Apple Silicon).
I defined the UIWindow variable in the AppDelgate and set the ViewController in application(didFinishLaunchingWithOptions), like before iOS 13. But that doesn't work and displays a blank screen.
This is because you did not correctly convert from the scene delegate architecture, which is provided by the app template you started with, to an app delegate architecture. Basically, you've left pieces of the scene delegate architecture lying around. Perhaps you did not delete all references to the scene delegate; perhaps you forgot to delete the UIApplicationSceneManifest entry from the Info.plist. Whatever the reason, the result is that the runtime thinks this app still uses scene delegate architecture, and it then fails to find certain pieces that it's looking for and shows the blank screen.
So, just to sum up what to do when you've started with the built-in app template:
Delete the SceneDelegate.swift file.
In the App Delegate, delete the two UISceneSession methods.
In the App Delegate, add a window reference as an instance property: var window: UIWindow?
In the Info.plist, completely delete the entire UIApplicationSceneManifest entry (and save).
Profit.

How to display lock sreen in task switcher and resume correctly

for the app I'm developing, I implemented a lock screen that allows the user to unlock the App by manual-pin or touch/Face-ID.
Everything is working OK during the normal use.
However, I need to show the lock screen when the app is resumed from background and even in the task switcher to avoid "peeking" at the content without having unlocked properly.
As recommended by Apple in this (old) article, I present the lock view controller in applicationDidEnterBackground:
func applicationDidEnterBackground(_ application: UIApplication) {
let lockVC = LoginViewController()
lockVC.loginType = LoginViewController.LoginType.resumeApp
if let topViewController = UIApplication.topViewController() {
topViewController.present(lockVC, animated: false, completion: nil)
}
}
where topViewControler is a useful extension to determnine the topmost view controller: Get top most UIViewController
.
The lockVC.loginType = ... is just to let the ViewController what type of login I need and customize its view a little bit
The results I get are a bit weird, both on simulator and real devices:
the task switcher preview for my app is completely black
when the app is resumed, the screen remains black as in preview and unresponsive. Only way to exit is to kill the app.
before obtaining the weird results above, I had to access all outlets as optional to avoid termination... that's fine for viewDidLoad stuff (I didn't expect the need for this when entering background, since the view had been loaded before - outlet wired) but the strange thing is that I had the same error for an IBAction in viewDidAppear (IBAction for touch-id button called automatically if touch/face-id is available - just a requirement).
I believe I'm missing something big here... but no other hints found.
No one of the ready-made lock screen solutions come with an example for the background/taskSwicth/resume case).
Note that the black/unresponsive screen seems to be same both if I use the mentioned extension for the topmost view controller to present or if I simply try to present it by
self.window?.rootViewController?.present(lockVC, animated: false)
(which I believe is wrong, but tried anyway)
Any help would be apreciated
I found a temporary workaround:
Display the lock screen when the app becomes active from background, as suggested by Dev_Tandel
Hide information in the task switcher by adding a blur effect on the current screen where the app is sent to background (applicationWillResignActive) and removing it when the app comes active again (applicationDidBecomeActive), as suggested here
As said, it's a temporary workaround that i wanted to share, but I don't like this 100%. It is required to show the lock screen in the task swtcher and Ive seen apps doing it (e.g. "oneSafe").
Still looking for help.
Solved, thanks to this post.
Apparently I was naive in trying to present a view controller with just its object instance.
If I use
let lockVC = topViewController.storyboard?.instantiateViewController(withIdentifier: "IDLoginViewController") as! LoginViewController
everything works, the lock screen is shown also in the task switcher, no need to blur!

AppDelegate: Show blocking view when something changes

I want something similar as the view shown in the "Friends" app when the iPhone is in flight mode. So my app shouldn't be usable when there is no internet and/or GPS so an empty view with an info message should pop up telling this the user. And of course vanish as soon as the internet/GPS is recovered. How can I do this?
EDIT: I know the reachabiljty class I only wonder how can I show and hide a view created in Storyboard directly from the app delegate?

state restoration in iOS

I am storing my application screen, so that when the application gets opened it will show the screen that was stored. The application is navigation based.
I have assigned the Restoration Ids to my two view controllers in main story board. The first controller is the root view controller of the navigation controller. I have also assigned Restoration Id to the navigation controller.
Now the problem is when I run the application I am getting the following warning:
Unable to create restoration in progress marker file.
Not sure what else need to be done.
I had the same warning before and fixed it by doing the followings.
I was using storyboard. My storyboard only included a navigation view controller and a view controller (which was the root view controller of that navigation view controller). In my case, it was caused by either of the two reasons:
The application was not set up correctly for state preservation
The followings need to be set:
In app delegate, override application:willFinishLaunching. One can simply return YES in that method.
For every view controllers and views (including the navigation view controllers and tab view controllers), set a restore ID
In app delegate, opt-in by overriding shouldSaveApplicationState and shouldRestoreApplicationState
If this warning still occurred, you could check how you run your app in Xcode. I ran my app in Xcode simulator and had to follow a specific sequence to trigger state preservation.
launch the app in Xcode simulator
In Xcode simulator, click the "Home" button to put the app into the background. The encodeRestorableStateWithCoder method of the view controller should be called
go back to Xcode, click the "stop" button to terminate the simulation
In Xcode simulator, double click the "Home" button and then remove the app from the app switcher and
go back to Xcode, run the app again.
That warning should not appear. When I used other sequences, I saw that warning appearing. When I debugged my app on my device using Xcode, I followed the same sequence and did not see the warning.
I think that warning indicated that because Xcode could not terminate the app correctly, the state restoration file was not correctly saved onto the disk.
Try to give your View a restoration ID. You can do so to open your xib or storyboard and assign the id to your View Controller.
more details: http://useyourloaf.com/blog/2013/05/21/state-preservation-and-restoration.html
Simulator:
This happens for the first time on the simulator when the app encodes. (not sure why)
Subsequent times this warning wouldn't be shown.
Device:
Try running on the device.
Run on device
Go to home screen.
Stop running on Xcode
Remove app from app switcher
Run on device again

Resources