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

如何在Kotlin/JS中集成Google GSI?遇属性未定义错误求解决

Kotlin/JS React Google一键登录:错误修复与资源参考

先解决当前的Cannot read properties of undefined (reading 'accounts')错误

这个问题的核心是你用了async defer加载Google GSI脚本,导致React组件的useEffect执行时,window.google还没被初始化。这里有几种靠谱的解决方式:

方式1:轮询检查Google对象是否加载完成

在useEffect里写一个递归检查的函数,直到google对象存在再执行初始化:

val SignIn = FC<Props> {    
    useEffect {      
        fun initGoogleSignIn() {
            val google = window.asDynamic().google
            if (google != undefined) {
                google.accounts.id.initialize(
                    js("{ client_id: '你的客户端ID', callback: (response) => { /* 处理登录回调逻辑 */ } }")
                )
            } else {
                setTimeout({ initGoogleSignIn() }, 100)
            }
        }
        initGoogleSignIn()
    }
}

方式2:监听脚本加载完成事件

在index.html里给脚本添加onload回调,触发自定义事件后再在React组件里执行初始化:

  1. 修改index.html:
<script>
  function onGoogleGSILoaded() {
    window.dispatchEvent(new Event('googleGSILoaded'));
  }
</script>
<script src="https://accounts.google.com/gsi/client" async defer onload="onGoogleGSILoaded()"></script>
  1. 在Kotlin组件里监听事件:
val SignIn = FC<Props> {    
    useEffect {
        val handleLoad = {
            val google = window.asDynamic().google
            google.accounts.id.initialize(/* 你的配置参数 */)
        }

        // 检查是否已经加载完成
        if (window.asDynamic().google?.accounts != undefined) {
            handleLoad()
        } else {
            window.addEventListener("googleGSILoaded", handleLoad)
        }

        // 组件卸载时清理事件监听
        return@useEffect {
            window.removeEventListener("googleGSILoaded", handleLoad)
        }
    }
}

Kotlin封装库与实现参考

目前没有官方专门针对Google GSI的Kotlin/JS封装库,但可以自己封装类型安全的交互层,避免全用dynamic:

// 定义类型安全的外部接口
external interface GoogleSignInConfig {
    val client_id: String
    val callback: (GoogleSignInResponse) -> Unit
}

external interface GoogleSignInResponse {
    val credential: String
    val select_by: String
}

external interface GoogleAccountsId {
    fun initialize(config: GoogleSignInConfig)
    fun renderButton(element: Element, config: dynamic)
}

external interface GoogleAccounts {
    val id: GoogleAccountsId
}

external interface Google {
    val accounts: GoogleAccounts
}

// 全局获取Google对象
val google: Google? get() = window.asDynamic().google?.unsafeCast<Google?>()

之后就可以用类型安全的方式调用API,不用再依赖dynamic。

参考方向:

  • 遵循Google Identity Services官方的Web端实现规范,明确需要调用的API参数和回调逻辑
  • 参考Kotlin/JS官方的JS互操作文档,学习如何正确定义外部接口和处理JS对象

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:17:34