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

Expo+Firebase JS SDK下RN GoogleSignin模块链接错误及跨平台问题排查

跨平台谷歌登录问题排查(Expo托管工作流 + @react-native-google-signin/google-signin + Firebase)

问题描述

  • Web端点击GoogleSigninButton时抛出错误:Uncaught Error: RN GoogleSignin native module is not correctly linked...
  • Android模拟器卡在启动页,提示打包完成但无后续页面加载

已执行操作

  • 构建开发版
  • 安装所有依赖
  • 运行expo doctor无异常提示
  • 清理预构建文件
  • 启动开发客户端
  • 确认配置符合官方文档要求

相关代码配置

SignUpScreen.tsx

import {GoogleSignin,GoogleSigninButton} from '@react-native-google-signin/google-signin';

//...
<GoogleSigninButton
            size={GoogleSigninButton.Size.Wide}
            color={GoogleSigninButton.Color.Light}
           // onPress={}
            //disabled={}
            style={{ width:'100%', height:SIZES.xxSmall}}
          />

app.json

"ios": {
      "config": {
        "usesNonExemptEncryption": false
      },
      "supportsTablet": true,
      "bundleIdentifier": "bundleIdentifier",
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./src/assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "my package"
    },
    "web": {
      "bundler": "metro",
      "favicon": "./src/assets/favicon.png"
    },
    "experiments": {
      "tsconfigPaths": true
    },
    "extra": {
      "eas": {
        "projectId": "projectId"
      }
    },
    "plugins": [
      "expo-font",
      "@react-native-google-signin/google-signin"
    ],
    "owner": "owner"

metro.config.ts

const { getDefaultConfig } = require("expo/metro-config");

module.exports = (() => {
  const config = getDefaultConfig(__dirname);
  const { transformer, resolver } = config;
  config.transformer = {
    ...transformer,
    babelTransformerPath: require.resolve("react-native-svg-transformer")
  };
  config.resolver = {
    ...resolver,
    assetExts: resolver.assetExts.filter((ext:any) => ext !== "svg"),
    sourceExts: [...resolver.sourceExts, "svg",'cjs','mjs','d.ts',
  ]
  };
  
  return config;
})();

package.json

dependencies:{
    "firebase": "^10.7.0",
    "@react-native-google-signin/google-signin": "^11.0.0",
    "@reduxjs/toolkit": "^1.9.7",
     "expo": "^50.0.0",
    "expo-auth-session": "~5.4.0",
    "expo-crypto": "~12.8.0",
    "expo-dev-client": "~3.3.5",
    "expo-system-ui": "~2.9.3",
    "expo-web-browser": "~12.8.1",
    "react": "^18.2.0",
    "react-dom": "18.2.0",
    "react-hook-form": "^7.49.2",
    "react-native": "^0.73.2",}

GoogleLogin.tsx

import React,{useEffect ,useState} from 'react'
import * as WebBrowser from 'expo-web-browser';
import { makeRedirectUri } from 'expo-auth-session';
import app,{ auth,provider } from '../../../firebaseConfig';
import { 
  GoogleSignin,
  statusCodes,
  GoogleSigninButton,} from '@react-native-google-signin/google-signin';
 import {Web_Client_ID  } from "../../utils/clientKeys";


const GoogleLogin =() => {
  const googleSigninConfig = ():void =>{
    GoogleSignin.configure({
      webClientId:Web_Client_ID , 
      scopes: ["profile", "email"],
      offlineAccess: true, 
      forceCodeForRefreshToken: true, 
      profileImageSize: 120, 
    });
  }
  const onAuthStateChanged = (user:any)=> {
    if(user){
     console.log(user)
    }else{
      //set user info to null
    }
  }

  useEffect(() => {
    googleSigninConfig()
    getCurrentUserInfo()
    const subscriber = auth().onAuthStateChanged(onAuthStateChanged) 
      //triggered once user either log in or out 
    return subscriber;
  },[])


  const signinWithGoogle = async () => {//ongoogle btn press
    try {
        await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true });
       
        const userInfo = await GoogleSignin.signIn();
        const {idToken, accessToken} = await GoogleSignin.getTokens()
        console.log(idToken,accessToken)
     
        const credential = 
        firebase.auth.GoogleAuthProvider.credential(idToken, accessToken,);
        await auth().signInWithCredential(credential); 
        
    }  catch ( error :any) {
        if (error.code === statusCodes.SIGN_IN_CANCELLED) {
          console.log('SIGN_IN_CANCELLED')
        } else if (error.code === statusCodes.IN_PROGRESS) {
          console.log('IN_PROGRESS')
        } else if (error.code === statusCodes.PLAY_SERVICES_NOT_AVAILABLE) {
          console.log('PLAY_SERVICES_NOT_AVAILABLE')
        } else {
          // some other error happened
        }
    }
  }

   
  //return null if user didnt signin previously
  const getCurrentUserInfo = async () => {
    try {
      const userInfo = await GoogleSignin.signInSilently()
      console.log(userInfo)
    } catch ( error :any) {
        if (error.code === statusCodes.SIGN_IN_REQUIRED) {
          console.log('SIGN_IN_REQUIRED')
        } else {
          console.log('error')
        }
    }
  }
    
  const GoogleSignout = async ()=>{
    try {
      await GoogleSignin.revokeAccess()
      await GoogleSignin.signOut()
      //.then(() => alert('Your are signed out!'));
      // setloggedIn(false);
    } catch ( error :any) {
           // Alert.alert('Something else went wrong... ', error.toString())
          }
  }
     
}

问题原因与解决方案

1. Web端错误:RN GoogleSignin native module is not correctly linked

@react-native-google-signin/google-signin仅支持React Native原生端(iOS/Android),完全不兼容Web平台。Web端需要单独使用Firebase JS SDK的谷歌登录方案,或结合expo-auth-session实现OAuth登录。

修复步骤:

  • 替换Web端登录逻辑,改用Firebase的signInWithPopup:
    // Web端专用登录函数
    import { getAuth, signInWithPopup, GoogleAuthProvider } from "firebase/auth";
    
    const signInWithGoogleWeb = async () => {
      const auth = getAuth();
      const provider = new GoogleAuthProvider();
      try {
        const result = await signInWithPopup(auth, provider);
        console.log(result.user);
      } catch (error) {
        console.error(error);
      }
    };
    
  • 通过平台判断渲染对应按钮:
    import { Platform } from 'react-native';
    
    // 组件内渲染逻辑
    {Platform.OS === 'web' ? (
      <button onClick={signInWithGoogleWeb} style={{width:'100%', padding:10}}>Google登录</button>
    ) : (
      <GoogleSigninButton
        size={GoogleSigninButton.Size.Wide}
        color={GoogleSigninButton.Color.Light}
        onPress={signinWithGoogle}
        style={{ width:'100%', height:SIZES.xxSmall}}
      />
    )}
    

2. Android模拟器卡在启动页

可能原因及修复:

  • 缺少Android客户端ID:GoogleSignin.configure中仅配置了webClientId,Android端必须添加androidClientId(从Google Cloud控制台获取):
    import { Android_Client_ID } from "../../utils/clientKeys";
    
    GoogleSignin.configure({
      webClientId: Web_Client_ID,
      androidClientId: Android_Client_ID, // 添加该行
      scopes: ["profile", "email"],
      offlineAccess: true,
      forceCodeForRefreshToken: true,
      profileImageSize: 120,
    });
    
  • metro配置冗余:sourceExts中添加的cjs、mjs可能导致依赖解析异常,精简配置:
    sourceExts: [...resolver.sourceExts, "svg"]
    
  • 开发客户端缓存残留:完全卸载模拟器中的开发客户端,重新构建安装:
    eas build --profile development --platform android
    # 将构建后的APK拖入模拟器安装
    
  • Google Play Services版本不兼容:更新模拟器的Google Play Services,或调整最低版本要求:
    await GoogleSignin.hasPlayServices({ 
      showPlayServicesUpdateDialog: true,
      minPlayServicesVersion: 12000000 // 根据实际情况调整
    });
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:54:58