When I use the apple to log in, the selection box will pop up. I choose to use the password to continue and the prompt is not complete

佐手、 提交于 2020-07-18 10:22:14

问题


iOS13 (beta) Apple Login error

@available(iOS 13.0, *)
    func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
        // Handle error.
        crprint(error.localizedDescription)
    }

Failed to complete operation. (com.apple.AuthenticationServices.AuthorizationError error 1000.)


回答1:


In my case, launching ASAuthorizationController including a request for ASAuthorizationPasswordProvider was causing the error.

Failed to complete operation. (com.apple.AuthenticationServices.AuthorizationError error 1000.)


From the ASAuthorizationError.Code documentation; 1000 is for unknown

ASAuthorizationError.Code.unknown

The authorization attempt failed for an unknown reason.

Declaration

case unknown = 1000

Ref: https://developer.apple.com/documentation/authenticationservices/asauthorizationerror/code/unknown

Now that's not particularly helpful but did give me a clue to check my ASAuthorizationController setup which I was trying to launch with 2 requests from ASAuthorizationAppleIDProvider & ASAuthorizationPasswordProvider, like so:

func loginWithAppleButtonPressed() {
    let appleSignInRequest = ASAuthorizationAppleIDProvider().createRequest()
    appleSignInRequest.requestedScopes = [.fullName, .email]

    let anySignInRequest = ASAuthorizationPasswordProvider().createRequest()

    let controller = ASAuthorizationController(authorizationRequests: [appleSignInRequest, 
                                                                       anySignInRequest])
    controller.delegate = self
    controller.presentationContextProvider = self

    controller.performRequests()
}

I tried this on a simulator that had an Apple ID with 2FA enabled and also on a device with another Apple ID without 2FA, and both times it would just go to authorizationController(controller:didCompleteWithError error:) and that's it.


Solution:

So to keep it simple, I launched ASAuthorizationController with only ASAuthorizationAppleIDProvider like so:

func loginWithAppleButtonPressed() {
    let appleSignInRequest = ASAuthorizationAppleIDProvider().createRequest()
    appleSignInRequest.requestedScopes = [.fullName, .email]

    let controller = ASAuthorizationController(authorizationRequests: [appleSignInRequest])
    controller.delegate = self
    controller.presentationContextProvider = self

    controller.performRequests()
}

And voilà! This time things worked as expected:

  1. When using an Apple ID with 2FA
    • popped up with the login request
  2. When using an Apple ID without 2FA
    • popped up an error telling me to enable 2FA
    • called authorizationController(controller:didCompleteWithError error:) with error 1000

So seems that in my case ASAuthorizationPasswordProvider was the culprit but since ASAuthorizationError.Code.unknown is a generic error case, this solution may not work for you.

Also, In my case I need only ASAuthorizationAppleIDProvider for Apple ID sign in so dropped the support for ASAuthorizationPasswordProvider.




回答2:


I've resolved it by adding sign in with apple as key in entitlements plist .




回答3:


Simply Add + "Sign In with Apple" from Capability.




回答4:


From Apple's example,

performExistingAccountSetupFlows, only call this method once on viewDidAppear. If user info exists already then Apple will show it to login. If not then it will throw error.

handleAuthorizationAppleIDButtonPress, whenever user taps on Sign in with Apple button, note that if an account already had existed it would have shown it to the user already. I believe its still in progress and not all use cases are covered, for example if user sees the login info initially from ViewDidAppear call and cancels it then user have to create a new account when tapping on this method since its missing ASAuthorizationPasswordProvider request. If user had some login info then in that case this call (with ASAuthorizationPasswordProvider) will succeed but if no data is available then user will not see any action on tapping this button since it will throw error.

I am still figuring this out, if I have anything more to add then I will update the answer. So, for now we can only have this one use case to use this Sign in with Apple option.

Update: Once I created a new account, I was offered by this same flow to login with the already existing account. So, I can say that there is no need to include call to ASAuthorizationPasswordProvider request in handleAuthorizationAppleIDButtonPress method. I am doing all the testing on device.

You can always go to Settings -> AppleId -> Password & Security -> Apple ID Logins to check and delete account if you need to test various scenarios.

Update 2: Everything seems to work fine in other scenarios too if you already have a saved password or App Id account created, so even if I pass ASAuthorizationPasswordProvider in the handleAuthorizationAppleIDButtonPress call, it is working fine. I would suggest to not pass ASAuthorizationPasswordProvider in the next call and keep the flow as described above, this way if no saved password is present or Apple Id created then it will provide option to the user to create a new id, if there is already an id that exists then it will show that id.

 override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        performExistingAccountSetupFlows()
    }

    func performExistingAccountSetupFlows() {
        // Prepare requests for both Apple ID and password providers.
        let requests = [ASAuthorizationAppleIDProvider().createRequest(),
                        ASAuthorizationPasswordProvider().createRequest()]

        // Create an authorization controller with the given requests.
        let authorizationController = ASAuthorizationController(authorizationRequests: requests)
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
    }

    @objc
    func handleAuthorizationAppleIDButtonPress() {
        let appleIDProvider = ASAuthorizationAppleIDProvider()
        let request = appleIDProvider.createRequest()
        request.requestedScopes = [.fullName, .email]

        let authorizationController = ASAuthorizationController(authorizationRequests: [request])
        authorizationController.delegate = self
        authorizationController.presentationContextProvider = self
        authorizationController.performRequests()
    }



回答5:


In my case i needed to first check ASAuthorizationPasswordProvider, then, if there are no stored credential, use ASAuthorizationAppleIDProvider. For this case i had to make some crunches. Code below:

// Initial point   
public func fire(appleIDCompletion: @escaping AppleIDServiceCompletion) {
    self.completion = appleIDCompletion

    let requestPassword = ASAuthorizationPasswordProvider().createRequest()
    performRequest(requestPassword)
}

// help function
private func performRequest(_ request: ASAuthorizationRequest) {
    let controller = ASAuthorizationController(authorizationRequests: [request])
    controller.delegate = self
    controller.presentationContextProvider = self
    controller.performRequests()
} 

// delegate
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
    if let e = error as? ASAuthorizationError {
        switch e.code {
        case .canceled:
            trace("User did cancel authorization.")
            return
        case .failed:
            trace("Authorization failed.")
        case .invalidResponse:
            trace("Authorization returned invalid response.")
        case .notHandled:
            trace("Authorization not handled.")
        case .unknown:
            if controller.authorizationRequests.contains(where: { $0 is ASAuthorizationPasswordRequest }) {
                trace("Unknown error with password auth, trying to request for appleID auth..")

                let requestAppleID = ASAuthorizationAppleIDProvider().createRequest()
                requestAppleID.requestedScopes = [.email, .fullName]
                requestAppleID.requestedOperation = .operationImplicit
                performRequest(requestAppleID)
                return
            } else {
                trace("Unknown error for appleID auth.")
            }
        default:
            trace("Unsupported error code.")
        }
    }

    completion?(.rejected(error))
}

Works like a charm 🔥



来源:https://stackoverflow.com/questions/57802941/when-i-use-the-apple-to-log-in-the-selection-box-will-pop-up-i-choose-to-use-t

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!