You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

KMM+Compose Multiplatform实现Apple SignIn卡在密码输入页求助

KMM + Compose Multiplatform 实现Apple Sign In时输入密码后流程卡住的问题排查与解决

问题核心

在KMM与Compose Multiplatform项目中实现Apple Sign In,输入密码后流程卡住,无任何日志或回调反馈,已完成开发者后台配置、依赖集成与登录逻辑编写。

可能原因与解决步骤

1. iOS窗口获取方式错误(iOS 13+多场景架构适配问题)

你的AuthorizationDelegate中使用UIApplication.sharedApplication.keyWindow!!获取窗口,但iOS 13之后引入了多场景(Scene)架构,keyWindow已被废弃,直接使用可能导致授权界面无法正确关闭,流程卡住。

修改方案:
替换presentationAnchorForAuthorizationController方法,从活跃场景中获取当前窗口:

override fun presentationAnchorForAuthorizationController(controller: ASAuthorizationController): UIWindow {
    val activeScene = UIApplication.sharedApplication.connectedScenes
        .firstOrNull { it.activationState == UISceneActivationStateForegroundActive } as? UIWindowScene
    return activeScene?.windows?.firstOrNull { it.isKeyWindow } ?: UIWindow()
}

2. Delegate被意外回收(生命周期问题)

你在signIn方法中创建的AuthorizationDelegate是局部变量,Kotlin/Native的内存管理可能在方法执行完毕后回收该对象,导致授权完成后无法触发回调。

修改方案:
将AuthorizationDelegate作为AppleSignInManager的成员变量持有,避免被回收:

actual class AppleSignInManager actual constructor() {
    private var authDelegate: AuthorizationDelegate? = null

    actual fun signIn(listener: AppleSignInListener) {
        val logger = Logger.withTag("AppleSignInManager")
        val provider = ASAuthorizationAppleIDProvider()
        val request = provider.createRequest()
        request.requestedScopes = listOf(ASAuthorizationScopeFullName, ASAuthorizationScopeEmail)

        logger.i { "requestedScopes : ${ASAuthorizationScopeFullName.toString()} : ${ASAuthorizationScopeEmail.toString()} " }

        val controller = ASAuthorizationController(authorizationRequests = listOf(request))
        authDelegate = AuthorizationDelegate(listener, logger)
        controller.delegate = authDelegate
        controller.presentationContextProvider = authDelegate

        controller.performRequests()
    }
}

3. 日志输出失效

自定义Logger可能存在配置问题,导致即使回调触发也看不到日志。可以先使用iOS原生日志工具验证回调是否执行:
在AuthorizationDelegate的回调方法中添加:

import platform.Foundation.NSLog

// 在didCompleteWithAuthorization方法中
NSLog("Apple Sign In 授权完成回调触发")

// 在didCompleteWithError方法中
NSLog("Apple Sign In 错误回调触发: ${didCompleteWithError.localizedDescription}")

4. 环境与配置验证

  • 必须使用真机测试:Apple Sign In在模拟器上可能存在兼容性问题
  • 确认设备网络正常:Apple授权流程需要网络连接
  • 检查开发者后台配置:确保App ID已启用Sign In with Apple,Bundle ID与项目一致,Provisioning Profile是最新生成并包含该权限

修改后的完整示例(关键部分)

actual class AppleSignInManager actual constructor() {
    private var authDelegate: AuthorizationDelegate? = null

    actual fun signIn(listener: AppleSignInListener) {
        val logger = Logger.withTag("AppleSignInManager")
        val provider = ASAuthorizationAppleIDProvider()
        val request = provider.createRequest()
        request.requestedScopes = listOf(ASAuthorizationScopeFullName, ASAuthorizationScopeEmail)

        logger.i { "requestedScopes : ${ASAuthorizationScopeFullName.toString()} : ${ASAuthorizationScopeEmail.toString()} " }

        val controller = ASAuthorizationController(authorizationRequests = listOf(request))
        authDelegate = AuthorizationDelegate(listener, logger)
        controller.delegate = authDelegate
        controller.presentationContextProvider = authDelegate

        controller.performRequests()
    }
}

class AuthorizationDelegate(private val listener: AppleSignInListener, val logger: Logger) : NSObject(),
    ASAuthorizationControllerDelegateProtocol,
    ASAuthorizationControllerPresentationContextProvidingProtocol {

    override fun authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization: ASAuthorization) {
        NSLog("Apple Sign In 授权完成回调触发")
        logger.i {"didCompleteWithAuthorization"}
        val credential = (didCompleteWithAuthorization.credential as? ASAuthorizationAppleIDCredential)
        val idTokenData = credential?.identityToken
        val idToken = idTokenData?.toUtf8String()
        if (idToken != null) {
            logger.i {didCompleteWithAuthorization.toString()}
            listener.onSignInSuccess(idToken)
        } else {
            logger.i {didCompleteWithAuthorization.toString()}
            listener.onSignInFailure(Throwable())
        }
    }

    override fun authorizationController(controller: ASAuthorizationController, didCompleteWithError: NSError) {
        NSLog("Apple Sign In 错误回调触发: ${didCompleteWithError.localizedDescription}")
        logger.i {didCompleteWithError.localizedDescription}
        listener.onSignInFailure(Throwable())
    }

    override fun presentationAnchorForAuthorizationController(controller: ASAuthorizationController): UIWindow {
        val activeScene = UIApplication.sharedApplication.connectedScenes
            .firstOrNull { it.activationState == UISceneActivationStateForegroundActive } as? UIWindowScene
        return activeScene?.windows?.firstOrNull { it.isKeyWindow } ?: UIWindow()
    }
}

fun NSData.toUtf8String(): String? {
    return NSString.create(data = this, encoding = NSUTF8StringEncoding) as String?
}

内容的提问来源于stack exchange,提问作者Dan Luciano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 02:15:00