嵌入LoginView的SignInWithAppleButton点击无弹窗问题
问题分析与解决方案
我正在为应用实现Sign in with AppleID功能,完成后跳转至MongoDB Atlas。已实现可正常运行的SignInWithAppleButton,但该按钮仅能单独在ContentView中运行;集成到LoginView后,点击按钮时登录弹窗无法弹出。LoginView代码如下:
@Environment(\.colorScheme) var colorScheme enum Field: Hashable { case username case password } @Binding var username: String? @Binding var userEmail: String? @Binding var firstLogin: Bool? @Binding var prename: String @Binding var surname: String @State var email: String = "" @State var wds: WatchlistDataService? @StateObject var vm: LoginViewModel = LoginViewModel() @State private var resetEmail = "" @State private var password = "" @State private var errorMessage = "" @State private var inProgress = false @State var showDialog = false @State var showPWReset = false @State var showPWResetConfirmation = false @State var showOverlay = true @FocusState private var focussedField: Field? var body: some View { NavigationView { ZStack { LinearGradient(gradient: Gradient(colors: [Color.theme.backGroundGreen, Color.theme.backGroundPurple]), startPoint: .topTrailing, endPoint: .bottomLeading) .ignoresSafeArea() VStack(spacing: 16) { Image("Logo") .resizable() .frame(width: 300, height: 61) .padding(.top, 75) .padding(.bottom, 40) Text(errorMessage) .foregroundColor(.red) .padding(.horizontal) TextField("E-Mail Adresse", text: $email) .padding(10) .overlay { RoundedRectangle(cornerRadius: 5) .stroke(Color.theme.accent.opacity(0.1), lineWidth: 2) } .padding(.horizontal, 10) .focused($focussedField, equals: .username) .submitLabel(.next) .onSubmit { focussedField = .password } SecureField("Passwort", text: $password) .padding(10) .overlay { RoundedRectangle(cornerRadius: 5) .stroke(Color.theme.accent.opacity(0.1), lineWidth: 2) } .padding(.horizontal, 10) .focused($focussedField, equals: .password) .onSubmit{userAction() endTextEditing()} .submitLabel(.go) HStack { loginButton .disabled(email == "" || password == "") NavigationLink { RegistrationView(prename: $prename, surname: $surname, email: $email) } label: { registerButton } } signInWithApple HStack{ Spacer() NavigationLink { PasswordResetView() } label: { Text("Ich habe mein Passwort vergessen") .font(.caption) .underline() .foregroundColor(colorScheme == .light ? .blue : Color.theme.accent) } .padding() .ignoresSafeArea(.keyboard, edges: .bottom) Spacer() } if inProgress { ProgressView() } } .onTapGesture { self.endTextEditing() } .onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { focussedField = .username } Analytics.logEvent(AnalyticsEventScreenView, parameters: [AnalyticsParameterScreenName: "Login"]) } .confirmationDialog("Bitte gültige Email Adresse eingeben.", isPresented: $showDialog, titleVisibility: .visible, actions: { Button("Ok") { showDialog = false } }) } } .navigationBarTitle("") .navigationBarBackButtonHidden(true) .navigationBarHidden(true) } extension LoginView { var loginButton: some View { Button { userAction() } label: { ZStack{ RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 1) .foregroundColor(Color.theme.accent) RoundedRectangle(cornerRadius: 10) .foregroundColor(Color.theme.accent.opacity(0.2)) Text("Mit E-Mail anmelden") .foregroundStyle(Color.theme.primaryFont) } .frame(width: 180, height: 40) } } var registerButton: some View { ZStack{ RoundedRectangle(cornerRadius: 10) .stroke(lineWidth: 1) .foregroundColor(Color.theme.accent) RoundedRectangle(cornerRadius: 10) .foregroundColor(Color.theme.accent.opacity(0.2)) Text("Mit E-Mail registrieren") .foregroundStyle(Color.theme.primaryFont) } .frame(width: 180, height: 40) } func loginWithApple(idToken: String){ print("loginWithApple()") // Fetch IDToken via the Apple SDK let credentials = Credentials.apple(idToken: idToken) myRealmApp.login(credentials: credentials) { (result) in switch result { case .failure(let error): print("Login failed: \(error.localizedDescription)") case .success(let user): vm.updateLoginStatetoLoggedIn() print("Successfully logged in as user \(user)") // Now logged in, do something with user // Remember to dispatch to main if you are doing anything on the UI thread } } } var signInWithApple: some View { SignInWithAppleButton(.signIn) { request in print("request started...") request.requestedScopes = [.email, .fullName] } onCompletion: { result in print("request completed...") print ("result: \(result)") switch result { case .success(let authResults): print("Authorisation successful") switch authResults.credential { case let credential as ASAuthorizationAppleIDCredential: if let idToken = credential.identityToken { guard let idTokenString = String(data: idToken, encoding: .utf8) else { print("Unable to serialize token string from data: \(idToken.debugDescription)") return } loginWithApple(idToken: idTokenString) self.username = credential.email self.prename = credential.fullName?.givenName ?? "" self.surname = credential.fullName?.familyName ?? "" self.email = credential.email ?? "" } default: print("default") break } case .failure(let error): print("Authorisation failed: \(error.localizedDescription)") } } .frame(height: 50) .padding() } }
核心问题排查与修复方案
1. 解决NavigationView层级遮挡问题
SignInWithAppleButton的弹窗需要正确的UIWindow层级,嵌套在NavigationView中可能导致弹窗被覆盖。添加导航视图样式确保层级正确:
var body: some View { NavigationView { // 原有ZStack内容 } .navigationViewStyle(.stack) // 添加此行 .navigationBarTitle("") .navigationBarBackButtonHidden(true) .navigationBarHidden(true) }
2. 避免点击事件被拦截
VStack上的onTapGesture会拦截所有区域的点击,包括Apple登录按钮。修改为仅在非按钮区域触发失焦:
// 替换原有VStack的.onTapGesture VStack(spacing: 16) { // 原有内容 } .gesture( TapGesture() .onEnded { endTextEditing() } )
或者给Apple登录按钮添加高优先级手势,确保点击优先响应:
var signInWithApple: some View { SignInWithAppleButton(.signIn) { request in print("request started...") request.requestedScopes = [.email, .fullName] } onCompletion: { result in // 原有逻辑 } .frame(height: 50) .padding() .highPriorityGesture(TapGesture()) // 添加此行 }
3. 清除输入框焦点再触发登录
当前输入框处于FocusState时,可能干扰Apple登录弹窗的触发。点击按钮时先取消焦点:
var signInWithApple: some View { Button(action: { focussedField = nil endTextEditing() }) { SignInWithAppleButton(.signIn) { request in request.requestedScopes = [.email, .fullName] } onCompletion: { result in // 原有逻辑 } .frame(height: 50) .padding() } }
4. 验证控制台日志
点击按钮后查看Xcode控制台,检查是否有以下错误:
- Apple登录权限配置错误
- 身份请求上下文异常
- Token解析失败
内容的提问来源于stack exchange,提问作者Marvin Meinhard
相关产品推荐
相关产品推荐

