Expo 實作 Google 登入功能

a blurry photo of a colorful object

版本

  • expo 52
  • react-native 0.76.1
  • @react-native-google-signin/google-signin 13.1.0

設定 OAuth 同意畫面

1.到 Google Cloud Console 建立專案
2.進入憑證頁面
3.建立憑證 > 新增 OAuth 用戶端 ID,此時會提示你需要先設定同意畫面

image 9
image 10

4.User Type 選擇外部

image 11

5.接著填寫 APP 的資訊,後面步驟全部跳過即可。

image 12

創建 OAuth 用戶端 ID

回到憑證,建立 OAuth 用戶端 ID

image 13

Web

  • 應用程式類型選擇 Web
  • 已授權的JavaScript來源和已授權的重新導向URI都設為 http://localhost:8081,這是 expo 預設的 web uri
image 15

Android

  • 應用程式類型選擇 Android
  • 套件名稱為 app.json 中 android.package 設置的名稱
  • SHA-1憑證指紋需要使用指令生成,請看下一節
image 14

獲取 APP 的 SHA-1 憑證指紋

1. eas login 先登入 expo 帳號

2. eas build:configure 生成 eas.json,並且配置好 profile

3.接著 eas credentials 開始生成 APP 憑證

先為 development 建立 Android 憑證,選擇 Set up a new keystore 即可。

image 16

建立完之後就能得到 SHA-1

image 17

建立 iOS 憑證也是一樣的操作方式,只不過生成 iOS 憑證需要登入Apple付費開發帳號才可以,我沒有付費,所以這邊就不演示雙平台了。

安裝 react-native-google-signin

安裝 @react-native-google-signin/google-signin

npx expo install @react-native-google-signin/google-signin

若要在 iOS 使用的話記得在 app.json 的 plugins 中加入以下內容,不然可以跳過。

{
  "expo": {
    "plugins": [
      [
        "@react-native-google-signin/google-signin",
        {
          "iosUrlScheme": "com.googleusercontent.apps._some_id_here_"
        }
      ]
    ]
  }
}

實作Google登入按鈕及路由權限驗證

修改 app.json 中的 scheme

{
  "expo": {
    "scheme": "your app name"
  }
}

新增一個 GoogleSigninButton.tsx

import { StyleSheet, Pressable, View } from 'react-native'
import { Image, Text } from 'tamagui'
import { useTranslation } from 'react-i18next'

import { useAuth } from '@/hooks'

export const GoogleSigninButton = () => {
  const { signIn } = useAuth()
  //...
  return (
    <Pressable style={[styles.container, { backgroundColor: color.primary }]} onPress={signIn}>
      <View style={styles.iconContainer}>
        <Image source={require('../../assets/images/google.png')} style={styles.icon} />
      </View>
      <Text style={styles.text} color={color.text} fontSize={18}>{t('SignInWithGoogle')}</Text>
    </Pressable>
  )
}

useAuth.ts

import { useContext } from 'react'
import { GoogleSignin } from '@react-native-google-signin/google-signin'
import { AuthContext } from '@/context'

GoogleSignin.configure({
  webClientId: process.env.EXPO_PUBLIC_WEB_CLIENT_ID,
})

export const useAuth = () => {
  const { setToken } = useAuthStore()

  const signIn = async () => {
    try {
      await GoogleSignin.hasPlayServices({ showPlayServicesUpdateDialog: true })
      const userInfo = await GoogleSignin.signIn()
      console.log('userInfo', userInfo)

      // send idToken to server for verification
      const token = ....
      setToken(token)
    } catch (error) {
      console.error(error)
    }
  }

  const signOut = async () => {
    try {
      await GoogleSignin.signOut()
      setToken(null)
    } catch (error) {
      console.error(error)
    }
  }

  return { signIn, signOut }
}

app/_layout.tsx

<AuthProvider>
  <Stack>
    <Stack.Screen name="login" options={{ headerShown: false }} />
    <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
  </Stack>
</AuthProvider>

AuthProvider.tsx

import { PropsWithChildren } from 'react'
import { AuthContext } from '@/context'
import { useAuthStore } from '@/hooks'

export const AuthProvider = ({ children }: PropsWithChildren) => {
  const { token, setToken } = useAuthStore()
  return (
    <AuthContext.Provider value={{ token, setToken }}>
      {children}
    </AuthContext.Provider>
  )
}

需要登入才能訪問的路由記得加上權限驗證,比如:

// (tabs)/_layout.tsx
import React from 'react'
import { Tabs, Redirect } from 'expo-router'
import { useTranslation } from 'react-i18next'

import { TabBar } from '@/components'
import { useAuthStore } from '@/hooks'

export default function TabLayout() {
  const { t } = useTranslation()
  const { token } = useAuthStore()

  if (!token) {
    return <Redirect href="/login" />
  }

  return (
    <Tabs
      backBehavior="history"
      screenOptions={{ headerShown: false }}
      tabBar={(props) => <TabBar {...props} />}
    >
      <Tabs.Screen name="index" options={{ title: t('Home') }} />
    </Tabs>
  )
}

guest

0 評論
最舊
最新 最多投票
內聯回饋
查看全部評論