跳转至正文

如何使用 Capacitor 通过 Google 登录(2026)

在 Capacitor 8 应用中接入 Google Sign-In:client ID、SHA-1、iOS URL scheme、Android Credential Manager、ID token 校验,以及错误 28444 的修复方法。

在 Capacitor 应用中使用 Capgo Social Login 插件的 Google 登录账户选择器

要在 Capacitor 应用中添加 Google 登录,请在 Google Cloud 中创建一个 Web、一个 iOS 以及一个或多个 Android OAuth 客户端 ID,然后安装 @capgo/capacitor-social-login,调用 SocialLogin.initialize({ google: { webClientId, iOSClientId } }),然后 SocialLogin.login({ provider: 'google' }). Android 使用 Google 的 Credential Manager,iOS 使用 Google Sign-In SDK,Web 端则使用 Google Identity Services。这三种方式都会返回一个 ID token,由你在服务器端验证。

本指南逐步讲解 2026 年 10 月 Capacitor 8 的每个步骤,包括最容易出错的部分:SHA-1 指纹、Play App Signing 密钥以及 iOS URL scheme。

Google Sign-In 在 Capacitor 应用中的工作原理

平台 插件使用的原生 API 传递给插件的 Client ID 其他控制台设置
Android 凭据管理器 (androidx.credentials) Web client ID 填为 webClientId 包含包名和 SHA-1 的 Android client
iOS 使用 SDK 实现 Google Sign-In iOS client ID 填为 iOSClientId 反向客户端 ID URL scheme 位于 Info.plist
Web 端 Google Identity Services Web client ID 填为 webClientId 已获授权的 JavaScript 来源

Google 会通过以下错误拦截嵌入式 WebView 中的 OAuth: disallowed_useragent 错误,所以在 Capacitor WebView 中加载 Google 登录页行不通。该插件改用原生账号选择器。

第 1 步:配置 Google Cloud

创建项目和 Google Auth Platform

  1. 打开 Google Cloud Console 并创建一个项目,或选择一个现有项目。所有客户端 ID 必须位于同一项目中。
  2. 打开 Google 身份验证平台 (即原“OAuth 同意屏幕”)。
  3. 在 品牌信息,设置用户可见的应用名称、支持邮箱,以及您的域名和隐私政策 URL。
  4. 在 受众,选择 外部 适用于面向消费者的应用。当应用处于 测试时,只有列在 测试用户 可以登录。
  5. 在 数据访问,保留默认 openid, email 以及 profile 权限,除非需要更多。

基本权限无需发布到生产环境或通过验证。敏感权限(日历、Drive、Gmail)在公开发布前需要通过验证。

创建 Client ID

前往 Google Auth Platform > 客户端 (或 API 和服务 > 凭据) 并创建:

客户端类型 填写内容 ID 填写位置
Web 应用 Web build 的已授权 JavaScript 来源(例如 https://app.example.com, http://localhost:5173) webClientId
iOS 您的 Bundle ID,以及获取后的 App Store ID 和 Team ID iOSClientId
Android(调试) 包名及调试 SHA-1 仅限控制台
Android(release) 包名加上传密钥 SHA-1 仅限控制台
Android (Play) 包名加 Play 应用签名 SHA-1 仅限控制台

获取 SHA-1 值:

# Debug key and any signing config in build.gradle
cd android && ./gradlew signingReport

# From a signed APK you actually install
keytool -printcert -jarfile android/app/build/outputs/apk/release/app-release.apk

对于 Play Store 构建,从以下位置复制 SHA-1: Play Console > 测试和发布 > 应用完整性 > 应用签名密钥证书。如果你先需要一个 release keystore, Android keystore 生成器 会在浏览器中生成一个。我们的 Google client ID 指南 会更深入地讲解控制台界面。

第 2 步:安装插件

bun add @capgo/capacitor-social-login
bunx cap sync

禁用你不使用的 provider,让它们的 SDK 不会被打进 binary:

// capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'Example',
  webDir: 'dist',
  plugins: {
    SocialLogin: {
      providers: {
        google: true,
        apple: true,
        facebook: false,
        twitter: false,
      },
    },
  },
};

export default config;

运行 bunx cap sync 更改 provider 后。

第 3 步:iOS 配置

添加反向 client ID 的 URL scheme

在 Google Cloud 中打开 iOS 客户端并复制 iOS URL scheme,格式类似 com.googleusercontent.apps.1234567890-abcdef。将其添加到 ios/App/App/Info.plist 在结束标签之前 </dict>:

<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array>
      <string>com.googleusercontent.apps.1234567890-abcdef</string>
    </array>
  </dict>
</array>

如果你已经有 CFBundleURLTypes 用于 deep links 的数组,请添加一个新 <dict> 条目,而不是创建第二个键。

让 Google SDK 处理回调 URL

在 ios/App/App/AppDelegate.swift,导入 SDK,并在 Capacitor 之前将 URL 路由给它:

import GoogleSignIn // add at the top of the file

// Replace the generated application(_:open:options:) method
func application(_ app: UIApplication, open url: URL,
                 options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
    if GIDSignIn.sharedInstance.handle(url) {
        return true
    }
    return ApplicationDelegateProxy.shared.application(app, open: url, options: options)
}

保留这种 ApplicationDelegateProxy 调用,因此 @capacitor/app 仍会接收其他深度链接。

步骤 4:Android 配置

使用默认作用域的基础登录无需原生代码修改。如果你请求 额外权限范围 或使用 离线模式,插件需要接收 activity 结果,因此 MainActivity 必须实现该插件的标记接口:

package com.example.app;

import android.content.Intent;
import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;
import com.getcapacitor.PluginHandle;
import ee.forgr.capacitor.social.login.GoogleProvider;
import ee.forgr.capacitor.social.login.ModifiedMainActivityForSocialLoginPlugin;
import ee.forgr.capacitor.social.login.SocialLoginPlugin;

public class MainActivity extends BridgeActivity implements ModifiedMainActivityForSocialLoginPlugin {

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode >= GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MIN
                && requestCode < GoogleProvider.REQUEST_AUTHORIZE_GOOGLE_MAX) {
            PluginHandle handle = getBridge().getPlugin("SocialLogin");
            if (handle == null) return;
            Plugin plugin = handle.getInstance();
            if (plugin instanceof SocialLoginPlugin) {
                ((SocialLoginPlugin) plugin).handleGoogleLoginIntent(requestCode, data);
            }
        }
    }

    @Override
    public void IHaveModifiedTheMainActivityForTheUseWithSocialLoginPlugin() {}
}

如果没有它,带有 scopes 的调用将被拒绝,并提示“您无法在未修改主 activity 的情况下使用权限范围”。

对于模拟器,请使用包含 Google Play 标签的系统镜像,并在设备设置中登录 Google 账户。不包含 Play 服务的镜像将返回 NoCredentialException.

步骤 5:Web 配置

将提供 Web 构建的所有源添加到 Web 客户端的 已获授权的 JavaScript 来源,包括端口(http://localhost:5173)。调用 initialize 要尽早执行:该插件会注入 Google 的 script 标签,如果在脚本就绪前运行,登录将会失败。

步骤 6:初始化并登录

import { SocialLogin } from '@capgo/capacitor-social-login';

const WEB_CLIENT_ID = '1234567890-web.apps.googleusercontent.com';
const IOS_CLIENT_ID = '1234567890-ios.apps.googleusercontent.com';

export async function initAuth() {
  await SocialLogin.initialize({
    google: {
      webClientId: WEB_CLIENT_ID, // Android + web
      iOSClientId: IOS_CLIENT_ID, // iOS
      iOSServerClientId: WEB_CLIENT_ID, // same as webClientId, required for offline mode on iOS
      mode: 'online',
    },
  });
}

export async function signInWithGoogle() {
  try {
    const { result } = await SocialLogin.login({
      provider: 'google',
      options: {},
    });

    if (result.responseType !== 'online' || !result.idToken) {
      throw new Error('Expected an ID token from Google');
    }

    const res = await fetch('https://api.example.com/auth/google', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ idToken: result.idToken }),
    });
    return res.json();
  } catch (error: any) {
    if (error?.code === 'USER_CANCELLED') return null;
    throw error;
  }
}

在线响应包含:

字段 备注
idToken OpenID Connect JWT。把它发送到你的服务器
accessToken 用于从客户端调用 Google APIs。可以是 null 在 Android 上,当仅请求默认作用域时
profile email, name, givenName, familyName, imageUrl, id
responseType 'online'

仅限 Android 的显示选项

本指南中介绍的 options 对象接受 style: 'bottom' 用于 bottom sheet UI,以及 filterByAuthorizedAccounts 以及 autoSelectEnabled 用于回访用户。请 filterByAuthorizedAccounts 在支持 Family Link 账号时保持关闭。 forceRefreshToken: true 向 Android 请求新的 access token,而不是缓存的 token。

请求额外的 scopes

const { result } = await SocialLogin.login({
  provider: 'google',
  options: {
    scopes: ['https://www.googleapis.com/auth/calendar.readonly'],
  },
});

记住 MainActivity 在 Android 上的更改,并在 数据访问 Google Cloud 中添加该 scope。

在线与离线模式

在线(默认) 离线
返回 ID token、access token、profile serverAuthCode 仅
需要后端 仅用于验证 token 是,用于交换 code
Google 刷新令牌 保留在 Google SDK 的设备上 存储在你的服务器上
适用场景 你只需要知道用户是谁 用户离开时,你的服务器调用 Google API
logout, isLoggedIn, refresh 支持 暂不支持

iOS 上的离线模式需要 iOSServerClientId,而在 Android 上则需要 MainActivity 更改。

注销与会话检查

await SocialLogin.isLoggedIn({ provider: 'google' }); // { isLoggedIn: boolean }
await SocialLogin.logout({ provider: 'google' });

在 Android 上, logout 还会清除 Credential Manager 状态,因此下次会再次弹出账号选择器。

第 7 步:在您的服务器上验证 ID token

import { OAuth2Client } from 'google-auth-library';

const client = new OAuth2Client();

export async function verifyGoogleToken(idToken: string) {
  const ticket = await client.verifyIdToken({
    idToken,
    audience: [
      '1234567890-web.apps.googleusercontent.com',
      '1234567890-ios.apps.googleusercontent.com',
    ],
  });
  const payload = ticket.getPayload();
  if (!payload) throw new Error('Empty token payload');

  return {
    googleUserId: payload.sub,
    email: payload.email,
    emailVerified: payload.email_verified === true,
    name: payload.name,
  };
}

使用 sub 作为稳定的用户标识。仅当满足以下条件时,才通过电子邮件关联现有账号: email_verified 为 true。同时接受两个 client ID 作为 audience 可以确保来自所有平台的 token 均有效。然后签发您自己的 session。如果您使用托管后端,请遵循 使用 Capacitor Social Login 的 Supabase 或 Firebase Google 指南. Neon Auth 通过 OAuth 重定向处理 Google 登录, @capgo/capacitor-neon 原生运行。

故障排除

错误 原因 修复
[28444] Developer console is not set up correctly 包名、SHA-1 或 webClientId 不匹配 使用 Web 客户端 ID,注册已安装 build 的 SHA-1,所有客户端保留在同一项目中
debug 下正常,从 Play Store 安装后失败 Play 会重新签名应用 添加使用 Play App Signing SHA-1 的 Android 客户端
[16] Account reauth failed 缓存的账号状态已过期、账号不是测试用户,或用户已停用应用 插件会自动重试一次。请检查测试用户、外部受众和 Play signing SHA-1
NoCredentialException 设备上没有 Google 账号,或模拟器没有 Play services 使用 Google Play 系统镜像并登录
USER_CANCELLED 选择账号后立即执行 通常还是 SHA-1 或 client ID 不匹配 在把它当成真正的取消之前,先修复控制台配置
iOS 崩溃:“缺少对以下 URL scheme 的支持” 缺少反转后的 client ID Info.plist 添加 com.googleusercontent.apps... scheme
Web:“指定的 origin 不允许用于指定的 client ID” Web 客户端缺少 Origin 添加准确的 origin,包括端口号
access_denied 提示“应用尚未完成 Google 验证流程” 处于 Testing 模式时,账号不是测试用户 在 Audience > Test users 下添加
iOS 上的 Google 登录界面被中断 @capacitor/privacy-screen 覆盖了 SDK 视图 调用 PrivacyScreen.disable() 在……之前 login

在 Android 上,通过 Logcat 过滤 GoogleProvider。该插件会记录包名、签名 SHA-1 以及脱敏后的 webClientId,稍后你可以拿它和控制台对比。

发布与维护

控制台更改可能需要几个小时才能生效,因此请勿在发布当天轮换客户端 ID。一旦原生配置已包含在商店构建中,诸如 scopes、错误处理或后端 URL 等客户端更改即可通过 Capgo 实时更新。如果你的团队没有用于 iOS 发布的 Mac, Capgo 构建 在云端构建并签名 iOS 二进制文件。

为 Capacitor 应用提供 Live Updates

当 Web 层出现线上 Bug 时,通过 Capgo 发布修复,而不用等 App Store 审核好几天。用户会在后台收到更新,原生变更则仍走正常审核流程。

博客最新动态

Capgo 为你提供打造真正专业的移动应用所需的最有价值的洞察。