swift pushkit -> open call screen without open total app - swift

I have some problem with my app, the exactly I want is to only open call screen when get pushkit VOIP call. But the problem is that the app gets open again(when killed), so many request were sent to server, i just want to open only callscreen, then may exit app after call dismiss.
I will fully explain the problem now:
First, in app delegate i replace with this class(this class have same UI with splash Screen)
initiateFirstScreen("SplashScreen", storyboardName : "sheet")
Inside this class. I have to check token, user info, connect to signalr server, it's took about 5-8 seconds, and when all loaded, i call this function to navigate to the HomeScreen:
func checkLogin() {
if let oauth = AppDelegate.shared.authState, oauth.isAuthorized{
initiateFirstScreen("HomeVC", storyboardName : "main")
}else{
initiateFirstScreen("LoginVC", storyboardName : "main")
}
}
func initiateFirstScreen(_ vcName: String, storyboardName : String) {
guard let window = AppDelegate.shared.window else{
AlertUtils.alertMessageWithOkAction(vc: self, mes: Language.get("Something went wrong")){b in
exit(0)
}
return
}
let storyBoard: UIStoryboard = UIStoryboard(name: storyboardName, bundle: nil)
let vc = storyBoard.instantiateViewController(withIdentifier: vcName)
window.rootViewController = vc
window.makeKeyAndVisible()
}
Inside above code, im using window.rootViewController = vc to dislay HomeScreen without any animation.
The problem:
Because of long loading in SplashScreen, when I got pushKit -> show Callkit screen, user may took 3-4 seconds to answer(when the app is killed/swiped)
-> didFinishLaunchingWithOptions called
-> SplashScreen called, and while user is answering call, the "check token, user info, connect to signalr" is loaded
-> Hence, the below function called:
window.rootViewController = vc
window.makeKeyAndVisible()
-> It's clear my callscreen now, that is the problem.
So i want to solved this problem, sorry for my silly question, but it's make me waste 3 days but can not solved this :(

You can use the delegate
func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession)
This delegate gets call when you answer the call. So just navigate directly to call screen. and add a flag eg. isCall = true and prevent the user to navigate to Home Screen this time

Related

Using Document Browser View Controller with Mac Catalyst

I have just started experimenting with Catalyst. My app is a document browser based app.
The stock MacOS Finder dialog is indeed launched when the appropriate button is clicked. The main app window completely disappears when the Finder dialog appears, unless I choose in the IB for the document browser view controller to appear in "Automatic" mode.
Cancelling the operation indeed brings back the main window.
However, selecting a file will yield a blank screen and no results. A little debugging revealed that none of the file selection functions is being called, and I have implemented all of them:
func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentURLs documentURLs: [URL]) {...}
func documentBrowser(_ controller: UIDocumentBrowserViewController, didImportDocumentAt sourceURL: URL, toDestinationURL destinationURL: URL) {...}
func documentBrowser(_ controller: UIDocumentBrowserViewController, failedToImportDocumentAt documentURL: URL, error: Error?) {...}
Is there another function or handle used in Catalyst? I found nothing in the documentation.
EDIT:
I should clarify that I manipulated the app to present the DocumentViewController before the DocumentBrowserViewController, although Apple requires that the DocumentBrowserViewController is the initial view controller. I did it by changing the app delegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
...
// Set the documentViewController to appear first
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewController = storyboard.instantiateViewController(withIdentifier: "main")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
return true
}
Taking this out still doesn't change anything. And a default project created from the document browser template does seem to work. What could prevent these methods from being called?
I would suggest to implement func documentBrowser(_ controller: UIDocumentBrowserViewController, didPickDocumentsAt documentURLs: [URL]) as well

Receive SIGABRT error when trying to hijack root view controller

I am trying to have my application open a different view controller based upon whether an array is empty in the user's NSUserDefaults. Essentially, if the user has previously saved data in the app, the app will open up to where they can select the data. Otherwise, the app will open to a welcome screen.
However, when the array is empty, I see the background color that I set for the welcome screen, but not the text or button that I laid out in the storyboard. When the array is not empty and the data page should open, my app crashes with a SIGABRT error. I checked all of the outlets for the view controller in question and nothing seems to be disconnected. Additionally, when I comment out the code in the app delegate and set the data view controller as my initial starting view, the app runs fine.
The full error is "Thread 1: signal SIGABRT" and it is tagged in the class AppDelegate line.
The code I used in the App Delegate is below:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var accounts = loadAccounts()!
if accounts.isEmpty {
let welcomeController = WelcomeViewController()
self.window!.rootViewController = welcomeController
} else {
let tableController = AccountTableViewController()
self.window!.rootViewController = tableController
}
return true
}
func loadAccounts() -> [Account]? {
return NSKeyedUnarchiver.unarchiveObject(withFile: Account.ArchiveURL.path) as? [Account]
}
Maybe the UIWindow is not set properly.
let bounds = UIScreen.main.bounds
self.window = UIWindow(frame: bounds)
self.window?.rootViewController = `your view controller`
self.window?.makeKeyAndVisible()
What else can go wrong?
var accounts = loadAccounts()!
This line is the culprit for you. Precisely this symbol ! is I guess. You are trying to fetch data from a database or a filesystem and expect it will always be there.
Think about it, it can't be true all the time.
# check if account array is not empty; I would have returned nil if it would be empty and so we can avoid that extra check here.
if let accounts = loadAccounts(), !accounts.isEmpty {
let tableController = AccountTableViewController()
self.window!.rootViewController = tableController
return true
}
let welcomeController = WelcomeViewController()
self.window!.rootViewController = welcomeController
Also, if you can provide more info about the error message from your debug console. Then I would be able to help in a better way.

Handle deep link notification

I'm adding deep linking to my app and getting stuck at handing off the URL to the view controller. I try to use notification but it doesn't work all the times.
My App Delegate:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let notification = Notification(name: "DeepLink", object: url)
NotificationCenter.default.post(notification)
return true
}
}
And View Controller:
class ViewController: UIViewController {
func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(ViewController.handleDeepLink), name: "DeepLink", object: nil)
}
#objc private func handleDeepLink(notification: Notification) {
let url = notification.object as! URL
print(url)
}
}
Problem: when my app is cold launched the notification is not handled, which I guess is due to the View Controller not having time to register itself as the observer yet. If I press the Home button, go to Notes and click on the deep link a second time, everything works as it should.
Question: how can I register the View Controller to observe the notification when the app is cold launched? Or is there a better way to send the URL from the App Delegate to the View Controller?
I think an initial assumption is to assume your view controller does not have time to register itself which means that the connection between URL and View controller must be decoupled and reside outside of the view controller.
I would then use some kind of lookup to instantiate the view controller when a URL is received.
For example,
if url.contains(“x”) {
let vc = ViewController(...)
cv.url = URL // Pass contextual data to the view controller.
// Present or push cv
}
As your app gets more complex you have to manage more challenging scenarios, like standing-up entire controller stacks, or removing presented controllers.
I followed the example in the LaunchMe app. Here's what solved my problem:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
// My root view controller is a UINavigationController
// Cast this to whatever class your root view controller is
guard let navigationController = self.window?.rootViewController as? UINavigationController else {
return false
}
// Navigate to the view controller that handles the URL within the navigation stack
navigationController.popToRootViewController(animated: false)
// Handle the URL
let vc = navigationController.topViewController as! ViewController
vc.handleDeepLink(url: url)
return true
}
Store if notification is not handled and load it when viewDidLoad.
var pendingNotificationInfo: PushNotificationInfo?

How to call function from viewcontroller in appdelegate? (Swift)

So basically I am trying to run the function Refresh (Located in ViewController.swift) in AppDelegate.swift. After searching for the better part of 5 hours I can't figure out why this isnt working.
here is my function:
func Refresh(){
if(Count==0 && QuickActionChecker==true){
Previous.text=String(TipArray[CountCurrent])
Current.text=String(TipArray[CountCurrent])
Deliveries.text="\(Runs)"
}
if(Count>0 && QuickActionChecker==true){
Previous.text=String(TipArray[CountCurrent-1])
Current.text=String(Total)
Deliveries.text="\(Runs)"
}
}
In my Appdelegate.swift I have initialized the ViewController by setting it to Main:
let Main = ViewController()
and here is where I'm attempting to run the function from (force touch quick action from the homescreen):
func application(_ application: UIApplication, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: #escaping (Bool) -> Void) {
if shortcutItem.type == "com.Sicarix.Ticket.Add5"{
if(CountCurrent==0){
TipArray.append(5)
Count=Count+1
CountCurrent=CountCurrent+2
Total=TipArray.reduce(0) {$0+$1}
Runs=Runs+1
QuickActionChecker=true
Main.Refresh()
}
else{
TipArray.append(5)
Count=Count+1
CountCurrent=CountCurrent+1
Total=TipArray.reduce(0) {$0+$1}
Runs=Runs+1
QuickActionChecker=true
Main.Refresh()
}
}
}
however, when I try to use the shortcut it opens the app to a white screen and stays there. Console is spitting out:
fatal error: unexpectedly found nil while unwrapping an Optional value
the code runs fine when I remove the Main.Refresh(), it just doesn't update the labels in my app, hence the need for the function.
Please help, I'm so ready to move on past this bug....
also please bear in mind that I haven't even been coding in swift for a week yet, so please break down what was wrong as best you can. TIA
Change your viewController object
let nextVC = storyboard?.instantiateViewController(withIdentifier:"ViewController") as! ViewController
The problem is that you are instantiating a new ViewController using ViewController() and that ViewController isn't added to your view controller hierarchy.
You need to use your Storyboard to instantiate the ViewController by using let mainVC = UIStoryboard(name: "Main", bundle: "nil").instantiateViewController(withIdentifier:"ViewController") as! ViewController and make sure your identifier is set up in Storyboard.
If you are not using Storyboard, another solution is to store the text you want to display on the UI in data source variables and only update those variables in 'AppDelegate', then load the content of those variables onto your labels in 'viewDidLoad' or 'viewWillAppear'.

load viewController from class in swift

Hi i am start to develop in swift recently and i am little confuse.
I have login system that know if the user authenticate or not.
The model check if the user authenticate or not login - by loginManager type NSObject.
after the loginManager verfiy if the user login it need to load the correct storyBoard.
I have viewController -> ProfileViewController, how I can load programaticly this ViewController from loginManager in real Time?
Hi try to call this funcation but I get black Screen, I dont know what do to
override init() {
var profileViewController = profileViewController()
let storyboard:UIStoryboard = UIStoryboard(name:"Main", bundle:nil)
let vc:UIViewController = storyboard.instantiateViewControllerWithIdentifier("profileViewController") as profileViewController
vc.navigationController?.pushViewController(profileViewController, animated: true)
vc.viewWillAppear(true)
}