# RN Google FreeSignIn

A simple and lightweight Google Sign-In library for React Native that uses Google's latest Identity Services API. I built this because the existing solutions were either outdated or too complex for my needs.

**Note: This library currently supports Android only. If you're interested in creating an iOS version, feel free to contribute! I primarily work with Android and don't have plans to implement iOS support myself.**

## Why This Library?

- Uses Google's latest Identity Services API (not the deprecated SDK)
- Works with React Native 0.60+ autolinking
- Includes TypeScript definitions
- Provides both hooks and components for different use cases
- Minimal setup required
- Handles errors properly with clear error messages

## Installation

```bash
npm install react-native-google-freesignin
# or
yarn add react-native-google-freesignin
```

### Android Setup

1. **Add dependencies to your `android/app/build.gradle`:**

```gradle
dependencies {
    // ... your existing dependencies
    implementation 'androidx.credentials:credentials:1.2.2'
    implementation 'androidx.credentials:credentials-play-services-auth:1.2.2'
    implementation 'com.google.android.libraries.identity.googleid:googleid:1.1.0'
}
```

2. **Enable autolinking in your `android/app/build.gradle`:**

Make sure you have this in your `android/app/build.gradle` file:

```gradle
react {
    autolinkLibrariesWithApp()
}
```

*Note: If you're using React Native 0.60+, autolinking should handle the package registration automatically. You don't need to manually add the package to MainApplication.*

3. **Add Internet permission to your `android/app/src/main/AndroidManifest.xml`:**

```xml
<uses-permission android:name="android.permission.INTERNET" />
```

4. **Configure your Google Cloud Console:**
   - Go to [Google Cloud Console](https://console.cloud.google.com/)
   - Create or select your project
   - Enable the Google Sign-In API
   - Create credentials (OAuth 2.0 Client ID) for Android
   - Add your app's SHA-1 fingerprint (see troubleshooting section below)

### iOS Setup

**iOS is not currently supported.** This library focuses on Android implementation using Google Identity Services. If you're interested in creating an iOS version, feel free to contribute! I primarily work with Android and don't have plans to implement iOS support myself.

## Usage

### Basic Setup

First, you need to configure the library with your Google OAuth client ID:

```javascript
import GoogleSignIn from 'react-native-google-freesignin';

// Configure with your web client ID
GoogleSignIn.configure({
  webClientId: 'your-web-client-id.apps.googleusercontent.com',
});
```

### Using the Hook (Recommended)

```javascript
import React from 'react';
import { View, Button, Text } from 'react-native';
import { useGoogleSignIn } from 'react-native-google-freesignin';

export default function App() {
  const { signIn, signOut, isLoading, error, user } = useGoogleSignIn();

  const handleSignIn = async () => {
    const result = await signIn();
    if (result) {
      console.log('Signed in successfully:', result.user);
    }
  };

  const handleSignOut = async () => {
    await signOut();
    console.log('Signed out successfully');
  };

  if (isLoading) {
    return <Text>Loading...</Text>;
  }

  if (error) {
    return <Text>Error: {error.message}</Text>;
  }

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      {user ? (
        <View>
          <Text>Welcome, {user.user.name}!</Text>
          <Text>Email: {user.user.email}</Text>
          <Button title="Sign Out" onPress={handleSignOut} />
        </View>
      ) : (
        <Button title="Sign In with Google" onPress={handleSignIn} />
      )}
    </View>
  );
}
```

### Using the Pre-built Button

```javascript
import React from 'react';
import { View, Alert } from 'react-native';
import { GoogleSignInButton } from 'react-native-google-freesignin';

export default function App() {
  const handleSignInSuccess = (user) => {
    Alert.alert('Success', `Welcome ${user.user.name}!`);
  };

  const handleSignInError = (error) => {
    Alert.alert('Error', error.message);
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      <GoogleSignInButton
        onPress={handleSignInSuccess}
        onError={handleSignInError}
        size="large"
        color="light"
        title="Sign in with Google"
      />
    </View>
  );
}
```

### Using the Service Directly

```javascript
import React, { useState } from 'react';
import { View, Button, Text } from 'react-native';
import GoogleSignIn from 'react-native-google-freesignin';

export default function App() {
  const [user, setUser] = useState(null);
  const [isLoading, setIsLoading] = useState(false);

  const signIn = async () => {
    setIsLoading(true);
    try {
      const result = await GoogleSignIn.signIn();
      setUser(result);
      console.log('User signed in:', result);
    } catch (error) {
      console.error('Sign in error:', error);
    } finally {
      setIsLoading(false);
    }
  };

  const signOut = async () => {
    try {
      await GoogleSignIn.signOut();
      setUser(null);
      console.log('User signed out');
    } catch (error) {
      console.error('Sign out error:', error);
    }
  };

  return (
    <View style={{ flex: 1, justifyContent: 'center', padding: 20 }}>
      {user ? (
        <View>
          <Text>Welcome, {user.user.name}!</Text>
          <Button title="Sign Out" onPress={signOut} />
        </View>
      ) : (
        <Button 
          title={isLoading ? "Signing in..." : "Sign In with Google"} 
          onPress={signIn}
          disabled={isLoading}
        />
      )}
    </View>
  );
}
```

## API Reference

### GoogleSignIn Service

#### Methods

- **`configure(config: GoogleSignInConfig): Promise<void>`**
  Configure the Google Sign-In service with your OAuth client IDs.

- **`signIn(): Promise<GoogleSignInResult>`**
  Start the Google Sign-In flow.

- **`signOut(): Promise<void>`**
  Sign out the current user.

- **`revokeAccess(): Promise<void>`**
  Revoke access token and sign out.

- **`getCurrentUser(): Promise<GoogleSignInResult | null>`**
  Get the currently signed-in user.

- **`isSignedIn(): Promise<boolean>`**
  Check if a user is currently signed in.

#### Types

```typescript
interface GoogleSignInConfig {
  webClientId: string;
  androidClientId?: string;
  iosClientId?: string;
}

interface GoogleSignInUser {
  id: string;
  name: string;
  email: string;
  photo?: string;
}

interface GoogleSignInResult {
  idToken: string;
  user: GoogleSignInUser;
  data?: {
    idToken: string;
  };
}

interface GoogleSignInError {
  code: string | number;
  message: string;
}
```

### useGoogleSignIn Hook

```typescript
interface UseGoogleSignInReturn {
  signIn: () => Promise<GoogleSignInResult | null>;
  signOut: () => Promise<void>;
  isLoading: boolean;
  error: GoogleSignInError | null;
  user: GoogleSignInResult | null;
}
```

### GoogleSignInButton Component

```typescript
interface GoogleSignInButtonProps {
  onPress?: (user: GoogleSignInResult) => void;
  onError?: (error: GoogleSignInError) => void;
  style?: ViewStyle;
  textStyle?: TextStyle;
  disabled?: boolean;
  title?: string;
  loadingTitle?: string;
  showIcon?: boolean;
  size?: 'small' | 'medium' | 'large';
  color?: 'light' | 'dark';
}
```

## Error Handling

The library provides comprehensive error handling with typed error objects:

```javascript
const { signIn, error } = useGoogleSignIn();

const handleSignIn = async () => {
  const result = await signIn();
  if (!result && error) {
    switch (error.code) {
      case 12501:
        console.log('User cancelled the sign-in');
        break;
      case 7:
        console.log('Network error');
        break;
      default:
        console.log('Other error:', error.message);
    }
  }
};
```

## Common Error Codes

- `12501`: User cancelled the sign-in
- `12500`: Sign-in failed
- `7`: Network error
- `NOT_CONFIGURED`: Google Sign-In not configured
- `NO_ACTIVITY`: Current activity is null

## Examples

### Complete Authentication Flow

```javascript
import React, { useEffect } from 'react';
import { View, StyleSheet } from 'react-native';
import GoogleSignIn, { GoogleSignInButton } from 'react-native-google-freesignin';

export default function AuthScreen() {
  useEffect(() => {
    // Configure Google Sign-In
    GoogleSignIn.configure({
      webClientId: 'your-web-client-id.apps.googleusercontent.com',
    });
  }, []);

  const handleSignIn = async (user) => {
    // Send the idToken to your backend for verification
    try {
      const response = await fetch('https://your-api.com/auth/google', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          idToken: user.idToken,
        }),
      });
      
      const data = await response.json();
      // Handle successful authentication
      console.log('Backend response:', data);
    } catch (error) {
      console.error('Backend error:', error);
    }
  };

  const handleError = (error) => {
    console.error('Google Sign-In error:', error);
  };

  return (
    <View style={styles.container}>
      <GoogleSignInButton
        onPress={handleSignIn}
        onError={handleError}
        size="large"
        color="light"
        style={styles.signInButton}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 20,
  },
  signInButton: {
    width: '100%',
    marginBottom: 20,
  },
});
```

### Custom Button Implementation

```javascript
import React from 'react';
import { TouchableOpacity, Text, StyleSheet } from 'react-native';
import { useGoogleSignIn } from 'react-native-google-freesignin';

export function CustomGoogleButton() {
  const { signIn, isLoading } = useGoogleSignIn();

  return (
    <TouchableOpacity
      style={styles.button}
      onPress={signIn}
      disabled={isLoading}
    >
      <Text style={styles.buttonText}>
        {isLoading ? 'Signing in...' : 'Custom Google Sign-In'}
      </Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  button: {
    backgroundColor: '#4285f4',
    padding: 15,
    borderRadius: 8,
    alignItems: 'center',
  },
  buttonText: {
    color: 'white',
    fontSize: 16,
    fontWeight: 'bold',
  },
});
```

## Troubleshooting

### Common Issues

**"Google Sign In not configured" error**
- Make sure you call `GoogleSignIn.configure()` before trying to sign in.

**"Current activity is null" error**
- This usually happens when the React Native bridge isn't ready yet. Make sure your component is fully mounted before calling sign-in methods.

**Network errors**
- Check your internet connection and make sure your Google Cloud Console project is set up correctly.

**SHA-1 fingerprint issues**
- This is the most common issue. Make sure you've added the correct SHA-1 fingerprint to your Google Cloud Console project.
- For debug builds, use the debug keystore SHA-1.
- For release builds, use your release keystore SHA-1.

### Getting SHA-1 Fingerprint

For debug builds:
```bash
cd android && ./gradlew signingReport
```

Or using keytool directly:
```bash
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android
```

For release builds:
```bash
keytool -list -v -keystore your-release-key.keystore
```

**Important:** Make sure to add both debug and release SHA-1 fingerprints to your Google Cloud Console project for the library to work in both debug and release builds.

## Contributing

Contributions are welcome! If you find bugs or want to add features, feel free to open issues or submit pull requests.

## License

MIT License - see the LICENSE file for details.

## Support

If you run into issues, please check the troubleshooting section first. If that doesn't help, feel free to open an issue on GitHub.

## Changelog

### v1.0.0
- Initial release
- Android support with Google Identity Services
- TypeScript support
- React Hooks integration
- Pre-built button component
- Comprehensive error handling