iPhone Push Payload Info in App - iphone

I'm trying to process some more information from my payload. This is how I set up push notification for iPhone and the message comes through and this is how i create my payload:
// Create the payload body
$body['aps'] = array(
'alert' => $message,
'sound' => 'default',
'link_url' => $url,
);
In this is inside my app.
// WHEN a push notification comes in
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any]){
if let aps = userInfo["aps"] as? NSDictionary {
if let alert = aps["alert"] as? NSDictionary {
if (alert["message"] as? NSString) != nil {
//Do stuff
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// redirect to section
var initialViewController = storyboard.instantiateViewController(withIdentifier: "ViewBookings")
self.window?.rootViewController = initialViewController
self.window?.makeKeyAndVisible()
}
} else if (aps["alert"] as? NSString) != nil {
self.window = UIWindow(frame: UIScreen.main.bounds)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
// redirect to section
var initialViewController2 = storyboard.instantiateViewController(withIdentifier: "ViewBookings")
self.window?.rootViewController = initialViewController2
self.window?.makeKeyAndVisible()
}
}
}
But now i need to read link_url so my app can redirect to different sections or recommend an external link. (its not always an url)
I tried: let my_url = aps["link_url"] as? NSDictionary and then describe as string, but i get nothing.

It depends on how the $message and $url objects are defined. If they are strings then the following should work:
if let my_url = aps["link_url"] as? String {
print(my_url)
}
From your code it looks like your object looks like the following:
{ "aps" : {
"alert" : {
"message" : "some message"
},
"sound" : "default",
"link_url" : "www.example.com"
}
}

Related

How to change rootViewController in swift?

I am working on an application in which there is no login logout feature. When user opens the application he sees main screen. Now there is an option in setting page named as Pin Lock application. When user select this option a PinScreen comes(like OTP Screen) then user sets the Pin. After that When user closes the application the Pin lock screen comes first asking user to enter pin.
So how can i do that?
if UserDefaults.standard.bool(forKey: "LoggedIn") == false {
let story = UIStoryboard(name: "Main", bundle:nil)
let vc = story.instantiateViewController(withIdentifier: "EnterPin") as! UINavigationController
UIApplication.shared.windows.first?.rootViewController = vc
UIApplication.shared.windows.first?.makeKeyAndVisible()
let enterPinViewController = self.storyboard.instantiateViewController(identifier: "EnterPinViewController") as! EnterPinViewController
self.navigationController.present(enterPinViewController, animated: true, completion: nil)
} else if UserDefaults.standard.bool(forKey: "LoggedIn") == true {
let story = UIStoryboard(name: "Main", bundle:nil)
let vc = story.instantiateViewController(withIdentifier: "MainController") as! UINavigationController
UIApplication.shared.windows.first?.rootViewController = vc
UIApplication.shared.windows.first?.makeKeyAndVisible()
let mainViewController = self.storyboard.instantiateViewController(identifier: "ViewController") as! ViewController
self.navigationController.present(mainViewController, animated: true, completion: nil)
}
Currently i am setting UserDefaults value as true and false and saving Pin in UserDefaults itself. I have tried changing rootViewController but nothing happening means every time main screen is coming instead of Pin Screen.
First you need to get the Window from SceneDelegate and use that window for rootViewController.
Suggestion: Whenever we are using rootViewController then no need to do present and push thing it will automatically set as a main home viewcontroller(Intial viewController)
let window = (UIApplication.shared.connectedScenes.first!.delegate as! SceneDelegate).window
let storyboard = UIStoryboard(name: "Main", bundle:nil)
if UserDefaults.standard.bool(forKey: "LoggedIn") == false {
let vc =storyboard.instantiateViewController(withIdentifier: "EnterPin") as! UINavigationController
window?.rootViewController = vc
window?.makeKeyAndVisible()
} else if UserDefaults.standard.bool(forKey: "LoggedIn") == true {
let vc =storyboard.instantiateViewController(withIdentifier: "MainController") as! UINavigationController
window?.rootViewController = vc
window?.makeKeyAndVisible()
}
I suggest you do all this things in SceneDelegate file
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let scene = (scene as? UIWindowScene) else { return }
self.window = UIWindow(windowScene: scene)
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if UserDefaults.standard.bool(forKey: "LoggedIn") == false {
let vc = storyboard.instantiateViewController(withIdentifier: "EnterPin") as! UINavigationController
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
} else if UserDefaults.standard.bool(forKey: "LoggedIn") == true {
let vc = storyboard.instantiateViewController(withIdentifier: "MainController") as! UINavigationController
self.window?.rootViewController = vc
self.window?.makeKeyAndVisible()
}
}
I Hope it is helpful for you!
let viewController = MainViewController()
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else {
return
}
guard let window = appDelegate.window else {
return
}
window.rootViewController = viewController

How do I show the data retrieved from Firebase onto a view controller that is inside a tab bar controller?

I have a ViewController that I would like to show the activity indicator while fetching username data from firebase and changing the username on the MenuViewController. After that, it would show the MenuViewController. But the problem I'm facing is the "menuVC.greetText = "Hi " + username" line doesn't work. There is no username being shown on the ViewController. Any advice is appreciated. Thanks in advance.
class LoadingViewController: UIViewController {
#IBOutlet var activityIndicator: UIActivityIndicatorView!
override func viewDidLoad() {
super.viewDidLoad()
startLoading {
switchToMenu()
}
// Do any additional setup after loading the view.
}
func startLoading(finished: () -> Void) {
activityIndicator.startAnimating()
authenticateUserAndConfigureView()
finished()
activityIndicator.stopAnimating()
}
func switchToMenu() {
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let mainViewController = storyboard.instantiateViewController(identifier: "MainVC")
self.view.window?.rootViewController = mainViewController
self.view.window?.makeKeyAndVisible()
}
}
func authenticateUserAndConfigureView() {
if Auth.auth().currentUser == nil {
DispatchQueue.main.async {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let loginController = storyboard.instantiateViewController(identifier: "LoginViewController")
self.view.window?.rootViewController = loginController
self.view.window?.makeKeyAndVisible()
}
}
else {
//let tabBar = segue.destination as! UITabBarController
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBar = storyboard.instantiateViewController(identifier: "MainVC") as! UITabBarController
let menuVC = tabBar.viewControllers?[0] as! MenuViewController
guard let uid = Auth.auth().currentUser?.uid else {return}
Database.database().reference().child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let username = value?["Username"] as? String ?? ""
menuVC.greetText = "Hi " + username
}
)
}
}
}
You are dealing with asynchronous function here and you are also inside closure, so meaning that as soon as you leave the closure, the assigned values inside closure will not be available. You need completionHandler to deal with it. You can make a separate function of it and then call it inside authenticateUserAndConfigureView.
func getName(completion:#escaping((String)->()) {
Database.database().reference().child(uid).observeSingleEvent(of: .value, with: { (snapshot) in
let value = snapshot.value as? NSDictionary
let username = value?["Username"] as? String ?? ""
completion(name)
}
And then you can call this function like this.
getName{(nameOfUser) in
print("Name is \(nameOfUser)")
}
In your case:
Calling inside authenticateUserAndConfigureView
func authenticateUserAndConfigureView() {
if (......) {
//All your code
}
else {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBar = storyboard.instantiateViewController(identifier: "MainVC") as! UITabBarController
let menuVC = tabBar.viewControllers?[0] as! MenuViewController
self.getName{(name) in
menuVC.greetText = "Hi" + name
}
}
}
You may need to use DispatchQueue here for possible timing issue, but I am not sure about that. If you do, let me know.

Present Subview inside a UINavigationController from Keyboard Extension

I have a keyboard extension and want the user to be able to tap on "settings", and be taken to the settings page inside the actual app. I was pretty excited when I got that working, but I realized that the page wasn't inside the navigation controller anymore!
Here is my code. How can I augment it to present a specific sub-screen inside my 'TransparentNavigationController'?
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let urlPath : String = url.path as String!
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
if(urlPath == "/inner"){
let innerPage: myStampsVC = mainStoryboard.instantiateViewController(withIdentifier: "myStampsVC") as! myStampsVC
self.window?.rootViewController = innerPage
}
self.window?.makeKeyAndVisible()
return true
}
I've tried different mixes of
let navigationController = window?.rootViewController as! UINavigationController
let innerPage = navigationController.viewControllers[4] as! myStampsVC
but I'm missing something. Thanks for any nudges in the right direction.
Here's the answer:
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
let urlPath = url.path
if(urlPath == "/inner"){
func showMyStamps(in navigationController: UINavigationController) {
navigationController.popToRootViewController(animated: false)
_ = navigationController.topViewController?.view
let innerViewController = myStampsVC() as UIViewController
navigationController.pushViewController(innerViewController, animated: false)
}
switch window!.rootViewController {
case let demo as DemoScreen:
if let navC = demo.presentedViewController as? UINavigationController {
showMyStamps(in: navC)
} else {
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let navC = storyBoard.instantiateViewController(withIdentifier: "TransparentNavController") as! UINavigationController
demo.present(navC, animated: false)
showMyStamps(in: navC)
}
case let navC as UINavigationController:
showMyStamps(in: navC)
default: assertionFailure()
}
}
return true
}

Swift Login app

I'm trying to make a new login app by Xcode. I had been written my code but something goes wrong with it.
The code looks like to be correct but when debugging its skip from "Task" to the end of code , any help ?
Here is my code:
#IBAction func myButton(sender: AnyObject) { //login button
let UserName = input.text!
let UserPassword = password.text!
if ( UserName.isEmpty || UserPassword.isEmpty) { return }
//send data user to server side
let myUrl = NSURL(string: "http://servertest.cf/Store.php?LoginUser=Test%40home.com&LoginPassword=123456789")
let myRequest = NSMutableURLRequest(URL: myUrl!)
myRequest.HTTPMethod = "POST"
let postString = "email=\(UserName)&Password=\(UserPassword)";
myRequest.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding)
let Task = NSURLSession.sharedSession().dataTaskWithRequest(myRequest)
{ data , response , error in
if error != nil {
println("error\(error)")
self.myLabel.text = "wrong user name"
}
var err : NSError?
var json = NSJSONSerialization.JSONObjectWithData(data, options: .MutableContainers , error: &err) as? NSDictionary
if let parseJson = json
{
var resultValue:String = parseJson["Status"] as! String!
println("result\(resultValue)")
if(resultValue == "Success" )
{
var storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
var vc: UINavigationController = storyboard.instantiateViewControllerWithIdentifier("SecondViewController") as! UINavigationController
self.presentViewController(vc, animated: true, completion: nil)
}
}
}
Task.resume()
}
The closure is queued to another queue and run in another thread. Add a breakpoint inside the closure if you want to run it line-by-line.

NSFetchRequest - entity - unexpectedly found nil while unwrapping an Optional value

I am currently working with Swift 2.0 and created a new "Master-Detail Application" in X-Code. I need that when the user clicks the BarButtomItem, a new View appears requesting a text field that will do a search in the internet.
The code to open the ViewController is as follows:
func insertNewObject(sender: AnyObject) {
let mainStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let vc : ISBNRequest = mainStoryboard.instantiateViewControllerWithIdentifier("myISBN") as! ISBNRequest
presentViewController(vc, animated: true, completion: nil)
}
Once the user enters the text, and the search is finished, I need to add the results into to the TableView. To do this, Im calling an update function from the view Controller:
Function in ViewController:
#IBAction func buscarLibro(sender: AnyObject) {
print ("aqui estamos")
let mainStoryboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let mvc :MasterViewController = mainStoryboard.instantiateViewControllerWithIdentifier("myMVC") as! MasterViewController
var titulo : String = String()
var autores : [String] = [String]()
var portada : UIImage = UIImage()
let isbnTxt = ISBN.text!
let urls = "https://openlibrary.org/api/books?jscmd=data&format=json&bibkeys=ISBN"+isbnTxt
let url = NSURL(string: urls)
let datos:NSData? = NSData(contentsOfURL: url!)
if (datos == nil) {
//No hacer nada
print("datos nil")
} else {
//let texto = NSString(data:datos!, encoding: NSUTF8StringEncoding)
//self.textView.text = texto! as String
print("empieza busqueda")
do {
let json = try NSJSONSerialization.JSONObjectWithData(datos!, options: NSJSONReadingOptions.MutableLeaves)
let dico1 = json as! NSDictionary
print(dico1.allKeys)
var tmp = dico1["ISBN"+isbnTxt]
if (tmp != nil && tmp is NSDictionary) {
let dico2 = tmp as! NSDictionary
tmp = dico2["authors"]
if (tmp != nil && tmp is NSArray) {
let dico3 = tmp as! NSArray
titulo = (dico2["title"] as! NSString as String)
for id in dico3 {
print(id["name"])
autores.append(id["name"] as! NSString as String)
}
let cover = dico2["cover"]
if (cover != nil && cover is NSDictionary) {
let covers = cover as! NSDictionary
let url = NSURL(string: covers["medium"] as! NSString as String)
if let data = NSData(contentsOfURL: url!) {
portada = UIImage(data: data)!
}
}
print("LIBRO:" + titulo)
let libro : Libro = Libro(nombre : titulo,autores: autores, portada: portada)
mvc.libros.append(libro)
for x in mvc.libros {
print (x.nombre)
}
mvc.actualiza(libro)
}
}
} catch _ {
}
}
}
The mvc.actualiza function does the following:
func actualiza (libro:Libro) {
let context = self.fetchedResultsController.managedObjectContext
let entity = self.fetchedResultsController.fetchRequest.entity!
let newManagedObject = NSEntityDescription.insertNewObjectForEntityForName(entity.name!, inManagedObjectContext: context)
// If appropriate, configure the new managed object.
// Normally you should use accessor methods, but using KVC here avoids the need to add a custom class to the template.
newManagedObject.setValue(libro as? AnyObject, forKey: "timeStamp")
// Save the context.
do {
try context.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
//print("Unresolved error \(error), \(error.userInfo)")
abort()
}
}
When executing the first line, in crashes here:
let entity = NSEntityDescription.entityForName("Event", inManagedObjectContext: self.managedObjectContext!)
And I am getting the following error message:
fatal error: unexpectedly found nil while unwrapping an Optional value
What am I missing to include in the transition from one view controller to another one?
That looks like self.managedObjectContext has not been initialised. You could try putting this before the faulting line to check:
print("managedObjectContext: \(self.managedObjectContext)")