收到通知并启用 Touch ID 时如何打开特定的 ViewController
Posted
技术标签:
【中文标题】收到通知并启用 Touch ID 时如何打开特定的 ViewController【英文标题】:How to open a particular ViewController when notification received and Touch ID is enabled 【发布时间】:2019-05-23 05:52:07 【问题描述】:我是 ios Swift 的新手。我在我的应用程序中添加了 LocalAuthentication(TouchID) 功能。启用触摸 ID 后,我在仪表板页面上重定向用户,成功验证。现在,当收到推送通知时,如果它是类别类型的博客,我想打开博客页面,如果它是类别类型的支付,我想打开支付页面,如果是新闻我想打开通知页面。但是由于启用了触摸 id,我正在重定向到仪表板页面,而不是在收到通知的特定 ViewController 上。不明白如何处理这种情况。
收到通知后我在做什么:
func navigateToView(userInfo: [AnyHashable: Any])
let userInfo = userInfo
if userInfo[AnyHashable("click_action")] != nil
category = (userInfo[AnyHashable("click_action")] as? String)!
let userauthenticate = UserDefaults.standard.bool(forKey: "userauth")
print("USERINFOCOUNT: \(userInfo.count) \n CATEGORY : \(category) \n USERAUTH: \(userauthenticate)")
if(userauthenticate == true && category.isEmpty)
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "Dashboard") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
else if(userauthenticate == true && category == "notification")
saveNewNotificationInBackground(userInfo: userInfo)
NotificationCenter.default.post(name: NSNotification.Name(rawValue: "openNotifications"), object: nil)
defaults.set(userInfo, forKey: "userInfo")
defaults.synchronize()
我的认证功能如下:
import UIKit
import Foundation
import Firebase
import FirebaseMessaging
import UserNotifications
import FirebaseCore
import FirebaseInstanceID
import Alamofire
import SwiftyJSON
import SQLite3
import LocalAuthentication
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
var window: UIWindow?
let gcmMessageIDKey = "gcm.message_id"
var userid : String = ""
var type : String = ""
var image : String = ""
var body : String = ""
var title : String = ""
var subtitle : String = ""
var category : String = ""
var badge : Int32 = 0
var badgecount : Int32 = 0
var aps: NSDictionary = NSDictionary()
var alert: NSDictionary = NSDictionary()
var usernamelen : Int = 0
var passwordlen : Int = 0
var notificationLists = [NotificationObj]()
var db: OpaquePointer?
let logevent = LogEvents()
var bridge: RCTBridge!
var forceUpdateCount : Int = 0
var reach: Reachability?
let defaults = UserDefaults.standard
var notificationType : String = ""
var notificationTitle : String = ""
var message : String = ""
var link : String = ""
var image_url : String = ""
var read_status : String = ""
var isfirstitmelaunch : Bool = true
var cemail : String = ""
var cpass : String = ""
var cid : String = ""
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey : Any]?) -> Bool
if #available(iOS 10.0, *)
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(
options: authOptions,
completionHandler: _, _ in )
Messaging.messaging().delegate = self
else
let settings: UIUserNotificationSettings =
UIUserNotificationSettings(types: [.alert, .badge, .sound], categories: nil)
application.registerUserNotificationSettings(settings)
application.registerForRemoteNotifications()
FirebaseApp.configure()
NotificationCenter.default.addObserver(self,
selector: #selector(self.tokenRefreshNotification),
name: NSNotification.Name(rawValue: "pushNotification"),
object: nil)
UserDefaults.standard.removeObject(forKey: "checkcomingfrom")
UserDefaults.standard.set(false, forKey: "checkcomingfrom")
cemail = defaults.string(forKey: "username") ?? ""
cpass = defaults.string(forKey: "password") ?? ""
cid = defaults.string(forKey: "id") ?? ""
if(cid != nil)
logevent.logFirebaseEvent(name: "app_launch", params: ["userid" : cid])
if(launchOptions != nil)
let userInfo = launchOptions?[UIApplicationLaunchOptionsKey.remoteNotification]
if userInfo != nil
print("USERINFO \(String(describing: userInfo))")
if(cemail == nil)
usernamelen = 0
else
usernamelen = (cemail.count)
if(cpass == nil)
passwordlen = 0
else
passwordlen = (cpass.count)
let firstTime = UserDefaults.standard.object(forKey: "first_time") as? Bool // Here you look if the Bool value exists, if not it means that is the first time the app is opened
if(firstTime == nil)
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "NewCustomer", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "demoview") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
defaults.set(true, forKey: "first_time")
defaults.synchronize()
else if(usernamelen > 0 && passwordlen > 0) // if remeber me set to true open dashboard directly
// IsFirstTimeLaunch = false
let userauthenticate = UserDefaults.standard.bool(forKey: "userauth")
print("userauthenticateforeground \(userauthenticate)")
if(userauthenticate == true)
authenticationWithTouchID()
else
defaults.set(false, forKey: "first_time")
defaults.synchronize()
print("INITIALCONTROLLERISDASHBOARD")
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "Dashboard") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
else // else open login viewcontroller as a initial view controller
defaults.set(false, forKey: "first_time")
defaults.synchronize()
print("INITIALCONTROLLERISLOGIN")
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "NewLoginViewController") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
return true
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable: Any])
_ = userInfo["aps"] as? NSDictionary
NotificationCenter.default.post(name: NSNotification.Name("pushNotification"), object: nil, userInfo: userInfo)
//Called When Silent Push Notification Arrives
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void)
UIApplication.shared.applicationIconBadgeNumber = UIApplication.shared.applicationIconBadgeNumber + 1
_ = userInfo["aps"] as? NSDictionary
NotificationCenter.default.post(name: NSNotification.Name("pushNotification"), object: nil, userInfo: userInfo)
print("Message ID: \(userInfo["gcm.message_id"] ?? "")")
print("\(userInfo)")
let aps:NSDictionary = (userInfo[AnyHashable("aps")] as? NSDictionary)!
badge += 1
print("badgecount \(badge)")
if UIApplication.shared.applicationState == .inactive
print("APPLICATIONIS INACTIVE")
//navigateToView(userInfo: userInfo)
//completionHandler(.newData)
else if UIApplication.shared.applicationState == .background
print("APPLICATIONIS BACKGROUND")
//navigateToView(userInfo: userInfo)
//completionHandler(UIBackgroundFetchResult.newData)
else
print("APPLICATIONIS FOREGROUND")
// completionHandler(UIBackgroundFetchResult.newData)
completionHandler(UIBackgroundFetchResult.newData)
func applicationReceivedRemoteMessage(_ remoteMessage: MessagingRemoteMessage)
print("REMOTEDATA: \(remoteMessage.appData)")
// [END receive_message]
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?)
super.touchesBegan(touches, with: event)
let statusBarTappedNotification = Notification(name: Notification.Name(rawValue: "statusBarTappedNotification"))
let statusBarRect = UIApplication.shared.statusBarFrame
guard let touchPoint = event?.allTouches?.first?.location(in: self.window) else return
if statusBarRect.contains(touchPoint)
NotificationCenter.default.post(statusBarTappedNotification)
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error)
print("Unable to register for remote notifications: \(error.localizedDescription)")
// This function is added here only for debugging purposes, and can be removed if swizzling is enabled.
// If swizzling is disabled then this function must be implemented so that the APNs token can be paired to
// the FCM registration token.
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
print("APNs token retrieved: \(deviceToken)")
//InstanceID.instanceID().setAPNSToken(deviceToken, type: InstanceIDAPNSTokenType.unknown)
// With swizzling disabled you must set the APNs token here.
Messaging.messaging().apnsToken = deviceToken as Data
func applicationWillResignActive(_ application: UIApplication)
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
print("DIDRESIGNACTIVE")
func applicationDidEnterBackground(_ application: UIApplication)
print("DIDBACKGROUND")
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
Messaging.messaging().shouldEstablishDirectChannel = false
func applicationWillEnterForeground(_ application: UIApplication)
print("applicationWillEnterForegroundcalled")
let forcemail : String = defaults.string(forKey: "username") ?? ""
let forcpass : String = defaults.string(forKey: "password") ?? ""
print("CUNAME : \(forcemail) \n CPASS : \(forcpass)")
// let userauthenticate = UserDefaults.standard.bool(forKey: "userauth")
// if(forcemail.count > 0 && forcpass.count > 0)
// if(userauthenticate == true)
// authenticationWithTouchID()
//
//
//
func applicationDidBecomeActive(_ application: UIApplication)
print("DIDBECOMEACTIVE")
connectToFcm()
func applicationWillTerminate(_ application: UIApplication)
func registerFcmToken(token : String, id : String, logintoken : String)
let systemVersion = UIDevice.current.systemVersion //11.4
let modelName = UIDevice.modelName //iPhone 6s plus
let systemName = UIDevice.current.systemName //iOS
let name = UIDevice.current.name //Sagar's iPhone
print("APPDELEGATEFCM : \(token)")
let url : String = "https://moneyfrog.in/register-token"
let params : [String : String] = ["user_id":id , "device_type":"ios" ,"token_no":token, "device_os_version" : systemVersion, "device_api_level" : "","device_name" : name, "device_model" : modelName, "device_product": UIDevice.current.model, "login_token" : logintoken]
Alamofire.request(url, method: .post, parameters: params).responseString
response in
if response.result.isSuccess
print("DEVICEINFO \(params)")
//let data : String = String(response.result.value!)
print("responseis : \(response) \n TOKENDATA ADDED")
// [START refresh_token]
@objc func tokenRefreshNotification(_ notification: Notification)
if let refreshedToken = InstanceID.instanceID().token()
print("InstanceID token: \(refreshedToken)")
// [END refresh_token]
func connectToFcm()
// Won't connect since there is no token
guard InstanceID.instanceID().token() != nil else
return;
Messaging.messaging().shouldEstablishDirectChannel = true
func authenticationWithTouchID()
let localAuthenticationContext = LAContext()
localAuthenticationContext.localizedFallbackTitle = "Enter Passcode"
var _: AppDelegate? = (UIApplication.shared.delegate as? AppDelegate)
let backgrView = UIView(frame: CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(UIScreen.main.bounds.size.width), height: CGFloat(UIScreen.main.bounds.size.height)))
backgrView.backgroundColor = UIColor.black
//backgrView.alpha = 0.9
window?.addSubview(backgrView)
let blurEffect = UIBlurEffect(style: .light)
let blurVisualEffectView = UIVisualEffectView(effect: blurEffect)
blurVisualEffectView.frame = backgrView.bounds
backgrView.addSubview(blurVisualEffectView)
var authError: NSError?
let reasonString = "Please authenticate to use Moneyfrog"
if localAuthenticationContext.canEvaluatePolicy(.deviceOwnerAuthentication, error: &authError)
localAuthenticationContext.evaluatePolicy(.deviceOwnerAuthentication, localizedReason: reasonString) success, evaluateError in
if success
DispatchQueue.main.async
blurVisualEffectView.removeFromSuperview()
self.navigateToView(userInfo: [:])
else
//TODO: User did not authenticate successfully, look at error and take appropriate action
guard let error = evaluateError else
return
print(self.evaluateAuthenticationPolicyMessageForLA(errorCode: error._code))
//TODO: If you have choosen the 'Fallback authentication mechanism selected' (LAError.userFallback). Handle gracefully
else
guard let error = authError else
return
//TODO: Show appropriate alert if biometry/TouchID/FaceID is lockout or not enrolled
print("APP LOCKED : \(self.evaluatePolicyFailErrorMessageForLA(errorCode: error.code))")
func evaluatePolicyFailErrorMessageForLA(errorCode: Int) -> String
var message = ""
if #available(iOS 11.0, macOS 10.13, *)
switch errorCode
case LAError.biometryNotAvailable.rawValue:
message = "Authentication could not start because the device does not support biometric authentication."
case LAError.biometryLockout.rawValue:
message = "Authentication could not continue because the user has been locked out of biometric authentication, due to failing authentication too many times."
case LAError.biometryNotEnrolled.rawValue:
message = "Authentication could not start because the user has not enrolled in biometric authentication."
default:
message = "Did not find error code on LAError object"
else
switch errorCode
case LAError.touchIDLockout.rawValue:
message = "Too many failed attempts."
case LAError.touchIDNotAvailable.rawValue:
message = "TouchID is not available on the device"
case LAError.touchIDNotEnrolled.rawValue:
message = "TouchID is not enrolled on the device"
default:
message = "Did not find error code on LAError object"
return message;
func evaluateAuthenticationPolicyMessageForLA(errorCode: Int) -> String
var message = ""
switch errorCode
case LAError.authenticationFailed.rawValue:
message = "The user failed to provide valid credentials"
case LAError.appCancel.rawValue:
message = "Authentication was cancelled by application"
case LAError.invalidContext.rawValue:
message = "The context is invalid"
case LAError.notInteractive.rawValue:
message = "Not interactive"
case LAError.passcodeNotSet.rawValue:
message = "Passcode is not set on the device"
case LAError.systemCancel.rawValue:
message = "Authentication was cancelled by the system"
case LAError.userCancel.rawValue:
message = "The user did cancel"
exit(0);
case LAError.userFallback.rawValue:
message = "The user chose to use the fallback"
default:
message = evaluatePolicyFailErrorMessageForLA(errorCode: errorCode)
return message
// [START ios_10_message_handling]
@available(iOS 10, *)
extension AppDelegate : UNUserNotificationCenterDelegate
func userNotificationCenter(_ center: UNUserNotificationCenter,
willPresent notification: UNNotification,
withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void)
_ = notification.request.content.userInfo
//let userInfo = notification.request.content.userInfo
// navigateToView(userInfo: userInfo)
completionHandler([.alert, .badge, .sound])
print("NotificationCenter1 called")
//userNotificationCenter
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void)
print("NotificationReceived \(response.notification.request.content.userInfo)")
print("STEP NOTIFICATIONCALLED")
let userInfo = response.notification.request.content.userInfo
navigateToView(userInfo: userInfo)
completionHandler()
//userNotificationCenter2
/* navigate to specific view controller on notification received */
func navigateToView(userInfo: [AnyHashable: Any])
let userInfo = userInfo
if userInfo[AnyHashable("click_action")] != nil
category = (userInfo[AnyHashable("click_action")] as? String)!
let userauthenticate = UserDefaults.standard.bool(forKey: "userauth")
print("USERINFOCOUNT: \(userInfo.count) \n CATEGORY : \(category) \n USERAUTH: \(userauthenticate)")
if(userauthenticate == true && category.isEmpty)
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialViewControlleripad : UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "Dashboard") as UIViewController
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = initialViewControlleripad
self.window?.makeKeyAndVisible()
// else if(userauthenticate == true && category == "payout_alerts") // if notification is payout alert open payout alerts controller
//
//
// // post a notification
//
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "openPayoutAlerts"), object: nil)
//
// self.logevent.logFirebaseEvent(name: "notification_payout", params: ["userid": self.userid])
// /*this logs database events in the system*/
// let params : [String : String] = ["action" : "notification_payout" , "page" : "payout_alerts_screen" , "user_id" : self.userid, "source" : "iOS"] //post params
// self.logevent.logDatabaseEvents(parameters: params)
//
//
//
// else if(userauthenticate == true && category == "blog") // if notification is blogs alert open blogs controller
//
// print("OPENING BLOGS")
//
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "OpenBlogs"), object: nil)
//
// self.logevent.logFirebaseEvent(name: "notification_blog", params: ["userid": self.userid])
// /*this logs database events in the system*/
// let params : [String : String] = ["action" : "notification_blog" , "page" : "blogs_screen" , "user_id" : self.userid, "source" : "iOS"] //post params
// self.logevent.logDatabaseEvents(parameters: params)
//
// else if(userauthenticate == true && category == "chat") // if notification is mypost alert open My post controller
//
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "openMypostContoller"), object: nil)
//
// self.logevent.logFirebaseEvent(name: "notification_mypost", params: ["userid": self.userid])
// /*this logs database events in the system*/
// let params : [String : String] = ["action" : "notification_mypost" , "page" : "mypost_screen" , "user_id" : self.userid, "source" : "iOS"] //post params
// self.logevent.logDatabaseEvents(parameters: params)
//
//
else if(userInfo.count > 0 && category == "notification") // if notification is ingeneral notification open notification controller
// saveNewNotificationInBackground(userInfo: userInfo)
//
// NotificationCenter.default.post(name: NSNotification.Name(rawValue: "openNotifications"), object: nil)
//
//
// defaults.set(userInfo, forKey: "userInfo")
// defaults.synchronize()
if let controller = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "Notification") as? Notifications
if let navigator = self.window?.rootViewController as? UINavigationController
navigator.pushViewController(controller, animated: true)
self.logevent.logFirebaseEvent(name: "notification_received", params: ["userid": self.userid])
/*this logs database events in the system*/
let params : [String : String] = ["action" : "notification_received" , "page" : "notification_screen" , "user_id" : self.userid, "source" : "iOS"] //post params
self.logevent.logDatabaseEvents(parameters: params)
/*this function save data in NotificationDatabase.sqlite database and Notifications table*/
func saveNewNotificationInBackground(userInfo: [AnyHashable: Any]) -> Void
//save notification using sqlite data
// [END ios_10_message_handling]
extension AppDelegate : MessagingDelegate
// [START refresh_token]
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String)
print("Firebasetoken: \(fcmToken)")
Messaging.messaging().subscribe(toTopic: "blog") error in
print("subscribed to blog topic")
Messaging.messaging().subscribe(toTopic: "news") error in
print("subscribed to news topic")
let defaults = UserDefaults.standard
defaults.set(fcmToken, forKey: "token")
defaults.synchronize()
let dataDict:[String: String] = ["token": fcmToken]
NotificationCenter.default.post(name: Notification.Name("FCMToken"), object: nil, userInfo: dataDict)
let id : String? = defaults.string(forKey: "id")
let logintoken : String? = defaults.string(forKey: "login_token")
if(id != nil && logintoken != nil)
registerFcmToken(token: fcmToken, id: id!, logintoken: logintoken!)
func messaging(_ messaging: Messaging, didReceive remoteMessage: MessagingRemoteMessage)
Messaging.messaging().shouldEstablishDirectChannel = true
print("ReceivedDataMessage: \(remoteMessage.appData)")
// [END ios_10_data_message]
【问题讨论】:
看看这个link希望对你有帮助 此链接不符合我的目的。 能不能贴一下通知功能代码对你有帮助 请检查上述编辑代码中的 navigateToView() 函数。在收到通知和身份验证时,我正在调用相同的函数。 通过了解您的应用程序根并进一步查看控制器的层次结构。 【参考方案1】:将成功博客中的代码替换为这个,
func goToBlogVC()
DispatchQueue.main.async
let storyboard = UIStoryboard(name: "Main", bundle: nil)
if let mainView = storyboard.instantiateViewController(withIdentifier: "blogVC") as? blogVC
self.window = UIWindow(frame: UIScreen.main.bounds)
let nav1 = UINavigationController()
nav1.isNavigationBarHidden = true //Show or hide nav bar
nav1.viewControllers = [mainView]
self.window!.switchRootViewController(nav1)
self.window?.makeKeyAndVisible()
你能告诉我你被击中的地方吗,你的代码看起来很完美,但流程太庞大了一旦你收到通知然后触发 authenticationWithTouchID 成功转到相关控制器[失败让输入他们的密码],下面是我的代码
导航流程
func userNotificationCenter(_ center: UNUserNotificationCenter,
didReceive response: UNNotificationResponse,
withCompletionHandler completionHandler: @escaping () -> Void)
if isblog
self.jumpToScreen()
completionHandler()
func jumpToScreen()
if let vc = self.window?.visibleViewController
if vc.isKind(of: blogVC.self)
return
else if vc.isKind(of: DashboardVC.self)
self.goToBlogVC()
else
print("Other Screens")
【讨论】:
使用上面的代码让我知道应用程序是否仍然崩溃 我们可以单独聊聊吗 当然是sagarchavan 我已经更新了我的整个 appdelegate.swift 文件。我只是不明白为什么如果启用触摸 ID 并收到通知,我无法打开特定控制器 让我们continue this discussion in chat。以上是关于收到通知并启用 Touch ID 时如何打开特定的 ViewController的主要内容,如果未能解决你的问题,请参考以下文章