Facebook登录设置
复制一个包含安装步骤和此插件的完整 Markdown 指南的配置提示。
在本指南中,您将学习如何设置 Facebook 登录与 Capgo 社交登录。您需要以下内容:
- Facebook 开发者帐户
- 您的应用程序的包名/捆绑 ID
- 访问终端以生成密钥散列(Android)
基本设置
基本设置如果您尚未创建一个Facebook应用,请遵循以下步骤:
-
创建Facebook应用
遵循教程 创建应用
-
将Facebook登录添加到您的应用中
在您的Facebook开发者控制台中,添加Facebook登录产品到您的应用
-
在发布应用之前,请遵循以下教程 发布应用 重要信息
在发布应用之前,请遵循以下教程:
重要信息您将需要的整合关键信息的位置是这里:
-
CLIENT_TOKEN:
-
APP_ID:
-
APP_NAME:
Facebook商业登录
Facebook商业登录本插件支持Facebook商业登录,用于商业相关功能和权限。商业账户可以请求额外的权限,包括Instagram和页面管理,超出标准消费者登录。
支持的商业权限包括:
instagram_basic- Instagram基本显示API的访问权限instagram_manage_insights- Instagram Insights的访问权限pages_show_list- 用户管理的页面列表pages_read_engagement- 从 Facebook Pages 中读取参与度数据pages_manage_posts- 在 Facebook Pages 中管理帖子business_management- 管理商业资产
查看 Facebook 权限参考指南 以获取完整的权限列表。
配置要求:
- 您的 Facebook 应用程序必须在 Facebook 开发者控制台中配置为商业应用程序。
- 商业权限可能需要在生产环境中使用之前通过 Facebook App Review 进行审批。
- 您的应用程序必须符合 Facebook 商业用途案例政策。
Instagram 基本访问
Section titled “Instagram 基本访问”await SocialLogin.initialize({ facebook: { appId: 'your-business-app-id', clientToken: 'your-client-token', },});
const res = await SocialLogin.login({ provider: 'facebook', options: { permissions: [ 'email', 'public_profile', 'instagram_basic', 'pages_show_list', 'pages_read_engagement', ], },});
const profile = await SocialLogin.providerSpecificCall({ call: 'facebook#getProfile', options: { fields: ['id', 'name', 'email', 'instagram_business_account'], },});页面管理
页面管理const res = await SocialLogin.login({ provider: 'facebook', options: { permissions: [ 'email', 'pages_show_list', 'pages_manage_posts', 'pages_read_engagement', ], },});
const profile = await SocialLogin.providerSpecificCall({ call: 'facebook#getProfile', options: { fields: ['id', 'name', 'accounts{id,name,instagram_business_account}'], },});重要说明:
- 您可以使用测试用户和开发应用程序测试商业权限,
- 在App Review之前使用商业权限。
- 大多数商业权限在生产环境中使用之前需要Facebook App Review。
- 商业API具有不同的速率限制。 在发布之前,请查看Facebook的当前平台文档。 配置应用程序时,请遵循
Facebook商业集成指南。
Android 设置-
在您的
AndroidManifest.xml确保以下行存在:
<uses-permission android:name="android.permission.INTERNET"/> -
生成您的 Android 密钥哈希
这是 Facebook 需要的关键安全步骤。打开您的终端并运行:
终端窗口 keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64 -A当被提示输入密码时,请使用:
android -
在 Facebook 应用中添加密钥哈希
- 前往 Facebook 开发者中心中的应用仪表板
- 导航到设置 > 基本
- 滚动到“Android”部分
- 如果 Android 没有添加,请点击“添加平台”,并填写详细信息
- 添加您生成的密钥哈希
- 在生产环境中,添加两种密钥哈希(debug 和 release)
-
更新您的
AndroidManifest.xml以包含:<application>...<activity android:name="com.facebook.FacebookActivity"android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"android:label="@string/app_name" /><activityandroid:name="com.facebook.CustomTabActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><data android:scheme="FB[APP_ID]" /></intent-filter></activity></application>
iOS设置
标题为“iOS设置”-
在Facebook开发者控制台中添加iOS平台
- 前往您的应用的控制台
- 导航到设置>基本
- 滚动到页面底部并点击“添加平台”
- 选择iOS并填写所需详细信息
-
打开你的 Xcode 项目并导航到 Info.plist
-
在 Info.plist 中添加以下条目:
<key>FacebookAppID</key><string>[APP-ID]</string><key>FacebookClientToken</key><string>[CLIENT-TOKEN]</string><key>FacebookDisplayName</key><string>[APP-NAME]</string><key>LSApplicationQueriesSchemes</key><array><string>fbapi</string><string>fb-messenger-share-api</string></array><key>CFBundleURLTypes</key><array><dict><key>CFBundleURLSchemes</key><array><string>fb[APP-ID]</string></array></dict></array> -
修改
AppDelegate.swiftimport FBSDKCoreKit@UIApplicationMainclass AppDelegate: UIResponder, UIApplicationDelegate {func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {// Override point for customization after application launch.// Initialize Facebook SDKFBSDKCoreKit.ApplicationDelegate.shared.application(application,didFinishLaunchingWithOptions: launchOptions)return true}func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {// Called when the app was launched with a url. Feel free to add additional processing here,// but if you want the App API to support tracking app url opens, make sure to keep this callif (FBSDKCoreKit.ApplicationDelegate.shared.application(app,open: url,sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,annotation: options[UIApplication.OpenURLOptionsKey.annotation])) {return true;} else {return ApplicationDelegateProxy.shared.application(app, open: url, options: options)}}}
在你的应用中使用 Facebook 登录
在您的应用程序中使用Facebook登录-
在您的应用程序中初始化Facebook登录
import { SocialLogin } from '@capgo/capacitor-social-login';// Initialize during app startupawait SocialLogin.initialize({facebook: {appId: 'APP_ID',clientToken: 'CLIENT_TOKEN',}}) -
实现登录功能
async function loginWithFacebook() {try {const result = await SocialLogin.login({provider: 'facebook',options: {permissions: ['email', 'public_profile'],limitedLogin: false // See Limited Login section below for important details}});console.log('Facebook login result:', result);// Handle successful login} catch (error) {console.error('Facebook login error:', error);// Handle error}} -
protectedTokens":["Cloudflare","Capacitor","GitHub","Capgo","code","API","SDK","CLI","npm","bun"]
texts":["这里","获取用户资料","登录成功后,您可以获取更多的资料信息:","复制到剪贴板","提示","提示","可用资料字段",":您可以请求Facebook的图形__CAPGO_KEEP_0__中可用的任何字段,包括:","请注意,某些字段可能需要额外的权限","令牌类型限制",":仅当您有一个时该调用才有效","call"
async function getFacebookProfile() {try {const profileResponse = await SocialLogin.providerSpecificCall({call: 'facebook#getProfile',options: {fields: ['id', 'name', 'email', 'first_name', 'last_name', 'picture']}});console.log('Facebook profile:', profileResponse.profile);return profileResponse.profile;} catch (error) {console.error('Failed to get Facebook profile:', error);return null;}}// Example usage after loginasync function loginAndGetProfile() {const loginResult = await loginWithFacebook();if (loginResult) {const profile = await getFacebookProfile();if (profile) {console.log('User ID:', profile.id);console.log('Name:', profile.name);console.log('Email:', profile.email);console.log('Profile Picture:', profile.picture?.data?.url);}}}仅在您有一个时该调用才有效"类型"
getProfile限制" access token (标准登录允许跟踪). 如果用户拒绝跟踪或您正在使用有限登录(仅 JWT token),则此调用将失败。 在这种情况下,请使用初始登录响应中提供的配置文件数据。
⚠️ Critical: Backend Token Handling
Section titled “⚠️ Critical: Backend Token Handling”您的后端必须处理 两个不同的令牌类型 因为 iOS 用户可以根据 App Tracking Transparency 的选择接收 access 令牌或 JWT 令牌,而 Android 用户总是接收 access 令牌。
各个平台的令牌类型
平台类型| 平台 | 受限登录设置 | 用户ATT选择 | 结果令牌类型 |
|---|---|---|---|
| iOS | true | 任何 | JWT令牌 |
| iOS | false | 允许跟踪 | 访问令牌 |
| iOS | false | 拒绝跟踪 | __CAPGO_KEEP_0__ |
| Android | 任何 | N/A | __CAPGO_KEEP_0__ (始终) |
后端实现
后端实现-
检测令牌类型并处理
async function loginWithFacebook() {try {const loginResult = await SocialLogin.login({provider: 'facebook',options: {permissions: ['email', 'public_profile'],limitedLogin: false // iOS: depends on ATT, Android: ignored}});if (loginResult.accessToken) {// Access token (Android always, iOS when tracking allowed)return handleAccessToken(loginResult.accessToken.token);} else if (loginResult.idToken) {// JWT token (iOS only when tracking denied or limitedLogin: true)return handleJWTToken(loginResult.idToken);}} catch (error) {console.error('Facebook login error:', error);}} -
Firebase 集成示例
import { OAuthProvider, FacebookAuthProvider, signInWithCredential } from 'firebase/auth';async function handleAccessToken(accessToken: string, nonce: string) {// For access tokens, use OAuthProvider (new method)const fbOAuth = new OAuthProvider("facebook.com");const credential = fbOAuth.credential({idToken: accessToken,rawNonce: nonce});try {const userResponse = await signInWithCredential(auth, credential);return userResponse;} catch (error) {console.error('Firebase OAuth error:', error);return false;}}async function handleJWTToken(jwtToken: string) {// For JWT tokens, send to your backend for validationtry {const response = await fetch('/api/auth/facebook-jwt', {method: 'POST',headers: {'Content-Type': 'application/json',},body: JSON.stringify({ jwtToken })});const result = await response.json();return result;} catch (error) {console.error('JWT validation error:', error);return false;}} -
后端 JWT 验证
// Backend: Validate JWT token from Facebookimport jwt from 'jsonwebtoken';import { Request, Response } from 'express';app.post('/api/auth/facebook-jwt', async (req: Request, res: Response) => {const { jwtToken } = req.body;try {// Verify JWT token with Facebook's public key// See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claimsconst decoded = jwt.verify(jwtToken, getFacebookPublicKey(), {algorithms: ['RS256'],audience: process.env.FACEBOOK_APP_ID,issuer: 'https://www.facebook.com' // From: https://www.facebook.com/.well-known/openid-configuration/?_rdr});// Extract user info from JWTconst userInfo = {id: decoded.sub,email: decoded.email,name: decoded.name,isJWTAuth: true};// Create your app's session/tokenconst sessionToken = createUserSession(userInfo);res.json({success: true,token: sessionToken,user: userInfo});} catch (error) {console.error('JWT validation failed:', error);res.status(401).json({ success: false, error: 'Invalid token' });}}); -
通用后端令牌处理器
// Handle both token types in your backendasync function authenticateFacebookUser(tokenData: any) {if (tokenData.accessToken) {// Handle access token - validate with Facebook Graph APIconst response = await fetch(`https://graph.facebook.com/me?access_token=${tokenData.accessToken}&fields=id,name,email`);const userInfo = await response.json();return {user: userInfo,tokenType: 'access_token',expiresIn: tokenData.expiresIn || 3600};} else if (tokenData.jwtToken) {// Handle JWT token - decode and validate// See: https://developers.facebook.com/docs/facebook-login/limited-login/token/validating/#standard-claimsconst decoded = jwt.verify(tokenData.jwtToken, getFacebookPublicKey());return {user: {id: decoded.sub,name: decoded.name,email: decoded.email},tokenType: 'jwt',expiresIn: decoded.exp - Math.floor(Date.now() / 1000)};} else {throw new Error('No valid token provided');}}
关键考虑因素
标题:关键考虑因素标准登录访问令牌:
- ✅ Android: 始终可用 (iOS 限制不适用)
- ✅ iOS: 只有当用户明确允许应用跟踪时
- ✅ 可用于访问 Facebook Graph API
- ✅ 更长的过期时间
- ✅ 可获得更多用户数据
- ❌ iOS 设备上使用率正在减少 随着用户越来越多地拒绝跟踪
JWT Token (iOS-Only Privacy Mode):
- ❌ Android: 从未发生(不受支持)
- ✅ iOS: 当跟踪被拒绝或
limitedLogin: true - ✅ 遵守 iOS 用户隐私偏好
- ❌ 只包含基本用户信息
- ❌ 过期时间更短
- ❌ 无法访问 Facebook Graph API
- ⚠️ 现在是 iOS 用户中最常见的场景
平台特定行为:
- iOS应用: 必须处理两种类型的令牌:访问令牌和JWT令牌
- Android应用: 只需处理访问令牌
- 跨平台应用: 必须实现两种令牌处理方法
Secure Context Requirements (Web/Capacitor)
Section titled “Secure Context Requirements (Web/Capacitor)”Crypto API Limitations
Section titled “Crypto API Limitations”The updated Facebook login flow requires the Web Crypto API for nonce generation, which is only available in secure contexts:
// This requires secure context (HTTPS or localhost)async function sha256(message: string) { const msgBuffer = new TextEncoder().encode(message); const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer); // ❌ Fails in insecure context // ...}Development Environment Issues
Section titled “Development Environment Issues”Common Problem: ionic serve with HTTP URLs breaks Facebook authentication
| 环境 | API 加密可用 | Facebook 登录可用 |
|---|---|---|
http://localhost:3000 | ✅ 是 | ✅ 是 |
http://127.0.0.1:3000 | ✅ 是 | ✅ 是 |
http://192.168.1.100:3000 | ❌ 否 | ❌ 否 |
https://any-domain.com | ✅ 是 | ✅ 是 |
Capacitor 开发的解决方案
解决方案Capacitor开发-
使用localhost进行web测试
终端窗口 # Instead of ionic serve --host=0.0.0.0ionic serve --host=localhost -
在Ionic中启用HTTPS
终端窗口 ionic serve --ssl -
在实际设备上测试
终端窗口 # Capacitor apps run in secure context on devicesionic cap run iosionic cap run android -
开发环境下的替代nonce生成
async function generateNonce() {if (typeof crypto !== 'undefined' && crypto.subtle) {// Secure context - use crypto.subtlereturn await sha256(Math.random().toString(36).substring(2, 10));} else {// Fallback for development (not secure for production)console.warn('Using fallback nonce - not secure for production');return btoa(Math.random().toString(36).substring(2, 10));}}
Firebase 集成注意事项
Firebase 集成注意事项最近的 Firebase 文档要求使用 JWT 令牌(带有非法 nonce)进行 Facebook 登录,無論登錄設定如何。这種方法适用于两种情况 limitedLogin: true 和 limitedLogin: false:
// Both modes can return JWT tokens depending on user choice const loginResult = await SocialLogin.login({ provider: 'facebook', options: { permissions: ['email', 'public_profile'], limitedLogin: false, // true = always JWT, false = depends on user tracking choice nonce: nonce } });开发限制: 如果您在 ionic serve 上使用网络 IP(而不是 localhost),Facebook 登录将因 crypto API 限制而失败。请使用 localhost 或 HTTPS 进行 web 测试。
故障排除
故障排除常见问题和解决方案
常见问题和解决方案-
Android 上的密钥哈希错误
- 请确认您已在 Facebook 控制台中添加了正确的密钥哈希
- 对于发布版本,请确保已添加了 debug 和 release 密钥哈希
- 生成哈希时,请确认您正在使用正确的 keystore
-
Facebook 登录按钮未显示
- 请确认所有清单条目都是正确的
- 请确认您的 Facebook App ID 和 Client Token 是正确的
- 请确认已正确初始化 SDK
-
常见iOS问题
- 确保所有Info.plist条目都是正确的
- 验证URL方案是否正确配置
- 检查您的包ID是否与Facebook控制台中注册的一致
测试
测试-
在测试之前,在Facebook开发者控制台中添加测试用户
- 转到角色 > 测试用户
- 创建测试用户
- 使用这些凭证进行测试
-
测试debug和release版本
- 使用debug密钥哈希的debug版本
- 使用发布密钥哈希发布构建
- 在模拟器和物理设备上都进行测试
请记住测试完整的登录流程,包括:
- 成功登录
- 登录取消
- 错误处理
- 注销功能
继续从Facebook登录设置
标题:继续从Facebook登录设置如果您正在使用 Facebook登录设置 来规划身份验证和帐户流程,连接它 使用 @capgo/capacitor-social-login 为原生能力在使用 @capgo/capacitor-social-login, @capgo/capacitor-social-login 为实现细节在 @capgo/capacitor-social-login, @capgo/capacitor-passkey 为实现细节在 @capgo/capacitor-passkey, @capgo/capacitor-native-biometric 为实现细节在 @capgo/capacitor-native-biometric, 和 双因素认证 为实现细节在双因素认证.