I am trying to create a google login for a react native app I intend to release to the app store. I am aware there are npm libraries for this, however I don't want to run into the issue of creators not updating their libraries. Also in the future I will probably make a custom native login UI for both ios and android. For that reason I followed this google guide to make a google sign-in button in Swift. I am proficient with React and know enough to work with React Native comfortably. However I am not familiar with Swift or branching code from Swift to React Native. Also since that google guide gives the example in swift I decided to convert the native files from Objective C to Swift (deleted AppDelegate.h, AppDelegate.m, main.m. Created AppDelegate.swift).
Problem: Can't get swift google sign in button to be visible in React Native
Steps:
- build google sign in button in swift
- export it to react native
- make a button to call sign in code from swift
I prefer to just make the button in swift then import it in react, but just making a button in react native to call swift functions is fine too. Also if I need to I can revert back to original Objective C code.
By following this guide I assume the solution would look something like this:
GoogleSignInManager.swift
import UIKit
import GoogleSignIn
@objc(GoogleSignInManager)
class GoogleSignInManager : NSObject {
override func viewDidLoad() {
super.viewDidLoad()
GIDSignIn.sharedInstance()?.presentingViewController = self
// Automatically sign in the user.
GIDSignIn.sharedInstance()?.restorePreviousSignIn()
}
}
GoogleSignInManger.m
#import "React/RCTViewManager.h"
@interface RCT_EXTERN_MODULE(GoogleSignInManager, RCTViewManager)
@end
MyApp-Bridging-Header.h
#import "React/RCTBridgeModule.h"
#import "React/RCTViewManager.h"
#import <React/RCTBridgeModule.h>
#import <React/RCTBridge.h>
#import <React/RCTEventDispatcher.h>
#import <React/RCTRootView.h>
#import <React/RCTUtils.h>
#import <React/RCTConvert.h>
#import <React/RCTBundleURLProvider.h>
AppDelegate.swift
import GoogleSignIn
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, GIDSignInDelegate {
var window: UIWindow?
var bridge: RCTBridge!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let jsCodeLocation: URL
jsCodeLocation = RCTBundleURLProvider.sharedSettings().jsBundleURL(forBundleRoot: "index", fallbackResource:nil)
let rootView = RCTRootView(bundleURL: jsCodeLocation, moduleName: "BbookMobile", initialProperties: nil, launchOptions: launchOptions)
let rootViewController = UIViewController()
rootViewController.view = rootView
self.window = UIWindow(frame: UIScreen.main.bounds)
self.window?.rootViewController = rootViewController
self.window?.makeKeyAndVisible()
/* Google API stuff I got from the guide */
Initialize sign-in
GIDSignIn.sharedInstance().clientID = "123fakeClientID456.apps.googleusercontent.com"
GIDSignIn.sharedInstance().delegate = self
@available(iOS 9.0, *)
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
func sign(_ signIn: GIDSignIn!, didSignInFor user: GIDGoogleUser!,
withError error: Error!) {
if let error = error {
if (error as NSError).code == GIDSignInErrorCode.hasNoAuthInKeychain.rawValue {
print("The user has not signed in before or they have since signed out.")
} else {
print("\(error.localizedDescription)")
}
return
}
// Perform any operations on signed in user here.
let userId = user.userID // For client-side use only!
let idToken = user.authentication.idToken // Safe to send to the server
let fullName = user.profile.name
let givenName = user.profile.givenName
let familyName = user.profile.familyName
let email = user.profile.email
print(fullName)
}
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!,
withError error: Error!) {
// Perform any operations when the user disconnects from app here.
print("User has disconnected")
}
/* End of google stuff */
return true
}
}
App.tsx
import React from 'react'
import { View, requireNativeComponent } from 'react-native'
import { ActionBtn } from './component-lib/Button'
import TextField from './component-lib/TextField'
const GoogleSignIn = requireNativeComponent("GoogleSignInManager")
const App = () => {
return (
<>
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<TextField label={"Username"} placeholder={"johndoe_"} contentType={"username"} />
<TextField label={"Password"} contentType={"password"} secure={true} />
<ActionBtn text={"hello"} />
<GoogleSignIn />
</View>
</>
)
}
I have been reading and looking for examples for about three hours to close the gap on this one and plan to write my own guide if I figure it out but hopefully someone can fill in the holes for me.