Firebase 无密码电子邮件身份验证无法在 iOS 上打开应用

Posted

技术标签:

【中文标题】Firebase 无密码电子邮件身份验证无法在 iOS 上打开应用【英文标题】:Firebase Passwordless Email Authentication doesn't open app on iOS 【发布时间】:2019-09-08 07:46:04 【问题描述】:

我正在尝试实现酷炫的 Firebase 电子邮件链接登录功能,但失败了。我成功设置发送电子邮件链接。但是,我无法获得打开应用程序的电子邮件链接。它只是打开预览页面,就像无法打开应用程序一样。

我已经测试了我设置的动态链接,我可以让它在设备中打开应用程序。我只是无法获得电子邮件链接来做同样的事情。

我的应用中的代码:

func sendFirebaseEmailLink() 

    let actionCodeSettings = ActionCodeSettings.init()

    // userEmail comes from a textField
    let email = userEmail

    actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.firebaseapp.com/?email=%@", email))
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = true
    actionCodeSettings.setiosBundleID(Bundle.main.bundleIdentifier!)

    Auth.auth().sendSignInLink(toEmail: email,
        actionCodeSettings: actionCodeSettings)  error in

        if let error = error 
            print(error.localizedDescription)
            return
        
        else 
            UserDefaults.standard.set(email, forKey: "Email")
            print("email sent to user")
        
    

当我说我已成功获得打开应用程序的动态链接时,我的意思是当我在安装了应用程序的设备上点击我创建的链接 (mylinkname.page.link/emaillogin) 时,它会打开应用程序。正因为如此,[这个有用的 Firebase 视频][1] 关于设置动态链接,我的这些细节似乎是正确的,问题出在代码上,但我是新手,所以我不确定.

我花了几天的时间来解决这个问题,并尝试解析密集的 Firebase 文档,因此非常感谢任何想法。

【问题讨论】:

【参考方案1】:

我终于明白了。代码很好。这是与动态链接相关的问题。我在 Firebase 中设置了几个链接,因为我必须在某一时刻创建一个新的 Bundle ID。当我在 Firebase 中删除旧邮件时,电子邮件链接开始工作。

它像这样出现在我的应用关联网站中,奇怪的是,即使我删除了旧链接,它仍然如此,但至少它现在可以工作了!

"applinks":"apps":[],"details":["appID":"TEAMID.com.OLDBUNDLEIDENTIFIER.APPNAME","paths":["NOT //*" ,"/*"],"appID":"TEAMID.com.NEWBUNDLEIDENTIFIER.APPNAME","paths":["NOT //","/"] ]

更新:我实现无密码电子邮件登录的完整代码如下。使用文档拼凑起来对我来说很痛苦,所以希望这可以为您省去麻烦。

假设您了解 Firebase 设置的基础知识的关键步骤。

1) 使用Firebase Video tutorial 设置动态链接。

2) 视图控制器中的代码:

var userEmail: String?
var link: String?

func sendFirebaseEmailLink() 

    let actionCodeSettings = ActionCodeSettings.init()
    let email = userEmail
    actionCodeSettings.url = URL.init(string: String(format: "https://<myappname>.page.link/emaillogin/?email=%@", email!))
    // The sign-in operation has to always be completed in the app.
    actionCodeSettings.handleCodeInApp = true
    actionCodeSettings.setIOSBundleID(Bundle.main.bundleIdentifier!)

    Auth.auth().sendSignInLink(toEmail: email!,
        actionCodeSettings: actionCodeSettings)  error in

        if let error = error 
            print(error.localizedDescription)
            return
        
        else 
            UserDefaults.standard.set(email, forKey: "Email")
            print("email sent to user")
        

        // TODO: Notify user to check email and click the link.
    


// Sign in user after they clicked email link called from AppDelegate
@objc func signInUserAfterEmailLinkClick() 

    // Get link url string from the dynamic link captured in AppDelegate.
    if let link = UserDefaults.standard.value(forKey: "Link") as? String 
        self.link = link
    

    // Sign user in with the link and email.
    Auth.auth().signIn(withEmail: userEmail!, link: link!)  (result, error) in

        if error == nil && result != nil 

            if (Auth.auth().currentUser?.isEmailVerified)! 
                print("User verified with passwordless email")

                // TODO: Do something after user verified like present a new View Controller

            
            else 
                print("User NOT verified by passwordless email")

            
        
        else 
            print("Error with passwordless email verfification: \(error?.localizedDescription ?? "Strangely, no error avaialble.")")
           
    

3) AppDelegate 中的代码

// For Passwordless Email Login to Handle Dynamic Link after User Clicks Email Link
func application(_ application: UIApplication, continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool 

    if let incomingURL = userActivity.webpageURL 
        print("Incoming URL is \(incomingURL)")

        // Parse incoming
        let linkHandled = DynamicLinks.dynamicLinks().handleUniversalLink(incomingURL)  (dynamicLink, error) in

            guard error == nil else 
                print("Found an error: \(error!.localizedDescription)")
                return
            
            if let dynamicLink = dynamicLink 
                self.handleIncomingDynamicLink(dynamicLink)
            
        
        if linkHandled 
            return true
        
        else 
            // Maybe do other things with dynamic links in future?
            return false
        
    
    return false


// Handles the link and saves it to userDefaults to assist with login.
func handleIncomingDynamicLink(_ dynamicLink: DynamicLink) 
    guard let url = dynamicLink.url else 
        print("My dynamic link object has no url")
        return
    
    print("Incoming link parameter is \(url.absoluteString)")

    let link = url.absoluteString
    if Auth.auth().isSignIn(withEmailLink: link) 

        // Save link to userDefaults to help finalize login.
        UserDefaults.standard.set(link, forKey: "Link")

        // Send notification to ViewController to push the First Time Login VC
        NotificationCenter.default.post(
            name: Notification.Name("SuccessfulPasswordlessEmailNotification"), object: nil, userInfo: nil)
    

【讨论】:

我也有类似的问题。大多数人可以通过链接进行身份验证,但有些人不能。它打开 App Store,显示已安装的应用程序,用户打开应用程序但登录过程被破坏。知道问题出在哪里吗? @Dpedriha 我建议在您的代码中发布一个单独的问题。 代码对 95% 的用户有效,所以问题不在代码中。 我也遇到过类似的问题。不完美的解决方案是取消链接登录方法的优先级并提供密码登录选项。

以上是关于Firebase 无密码电子邮件身份验证无法在 iOS 上打开应用的主要内容,如果未能解决你的问题,请参考以下文章

如果用户已经无密码登录,firebase 可以设置密码身份验证吗?

Flutter 在尝试 Firebase 身份验证时无法捕获 PlatformException

FireBase 身份验证 mAuth.createUserWithEmailAndPassword(电子邮件,密码)错误

该电子邮件地址已被另一个帐户使用(使用电子邮件/密码 Firebase 进行身份验证)

在 Flutter 上使用电子邮件和密码进行 Firebase 身份验证的示例?

设置最小密码长度 Firebase 电子邮件和密码身份验证