Angular集成Sign In With Apple JS时,点击Continue按钮后弹窗不关闭、登录事件未触发
Angular集成Sign In With Apple JS时,点击Continue按钮后弹窗不关闭、登录事件未触发
我之前也遇到过几乎一模一样的问题,折腾了好一阵才找到几个核心排查方向和解决办法,你可以逐一试试:
1. 核心问题:回调URI不能是API接口,必须用静态前端页面
这大概率是你当前问题的根源!当开启usePopup: true时,Apple的授权流程会通过web_message模式传递结果,你的redirectURI必须指向一个能接收并转发Apple消息的静态HTML页面,而不是后端API接口(你现在填的是https://mtmdevelopmentapi.azurewebsites.net/api/Account/AppleCallback/300,这是API接口,无法处理前端的postMessage通信)。
解决方案:
- 新建一个静态HTML页面(比如
apple-callback.html),放在你的前端域名下(和Angular应用同域),内容如下:<!DOCTYPE html> <html> <body> <script type="text/javascript"> // 接收Apple的授权结果消息,转发给父窗口后关闭弹窗 window.addEventListener('message', function(event) { if (event.origin === 'https://appleid.apple.com') { window.opener.postMessage(event.data, event.origin); window.close(); } }); </script> </body> </html> - 到Apple开发者后台,把你的Redirect URI更新为这个静态页面的完整URL(比如
https://your-frontend-domain.com/apple-callback.html) - 同时修改Angular代码里的
AppleID.auth.init配置,把redirectURI替换成这个新地址
2. 确认事件绑定的时机与组件生命周期清理
Angular组件的事件绑定容易出现时机问题,要确保在Apple JS SDK完全加载完成后再绑定事件,同时组件销毁时要解绑避免内存泄漏。
优化后的代码示例:
import { Component, OnInit, OnDestroy } from '@angular/core'; @Component({ selector: 'app-apple-signin', templateUrl: './apple-signin.component.html' }) export class AppleSigninComponent implements OnInit, OnDestroy { private boundAppleSuccessHandler: any; private boundAppleErrorHandler: any; ngOnInit(): void { this.loadAppleSDK(); } ngOnDestroy(): void { // 组件销毁时解绑事件 if (this.boundAppleSuccessHandler) { document.removeEventListener('AppleIDSignInOnSuccess', this.boundAppleSuccessHandler); } if (this.boundAppleErrorHandler) { document.removeEventListener('AppleIDSignInOnFailure', this.boundAppleErrorHandler); } } private loadAppleSDK(): void { // 动态加载Apple JS SDK,确保加载完成后再初始化和绑定事件 const script = document.createElement('script'); script.src = 'https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js'; script.onload = () => { // 初始化Apple SDK AppleID.auth.init({ clientId: 'net.membertomember.customer', scope: 'name email', redirectURI: 'https://your-frontend-domain.com/apple-callback.html', // 替换为新的静态回调页地址 usePopup: true, }); // 绑定事件 this.boundAppleSuccessHandler = this.handleAppleSuccessResponse.bind(this); this.boundAppleErrorHandler = this.handleAppleErrorResponse.bind(this); document.addEventListener('AppleIDSignInOnSuccess', this.boundAppleSuccessHandler); document.addEventListener('AppleIDSignInOnFailure', this.boundAppleErrorHandler); }; document.body.appendChild(script); } private handleAppleSuccessResponse(event: any) { console.log('授权成功:', event.detail.data); this.authService.AuthFromLocalStorage = event.detail.data; this.authService.getCustomerDetails(event.detail.data.email); } private handleAppleErrorResponse(event: any) { console.log('授权失败:', event.detail.error); if (event.detail.error === 'popup_closed_by_user') return; this.toast.error(event.detail.error_description, event.detail.error); } }
3. 浏览器环境排查
部分浏览器(尤其是Safari)对跨域弹窗、第三方Cookie的限制很严格,可能会阻止消息传递:
- 确保用户浏览器允许你的网站弹出窗口
- Safari用户需要在设置中开启"允许跨域跟踪"(关闭"防止跨站跟踪"选项)
- 检查浏览器控制台是否有跨域相关的报错
4. 检查授权请求参数
从你提供的网络请求来看,请求体里的scopes是空数组,但你初始化时设置了scope: 'name email',可以尝试把scope改成数组格式:scope: ['name', 'email'],确保权限参数正确传递。
我当时就是因为把回调URI设成了API接口,折腾了好久,换成静态回调页后马上就正常了,你先试试这个核心修改!
内容来源于stack exchange




