Using Native Modules to Keep Users Logged In

Let’s say you’re re-writing your iOS application in React Native and pushing the update live in a few days. In order to keep users logged in, each codebase checks for a session stored in their individual local storage system. iOS uses NSUserDefaults and React Native uses AsyncStorage. However, when a user downloads the update, nothing is going to be stored in AsyncStorage. Thus, they will be forced to log back in - not an ideal user experience.

Fortunately, React Native has a built-in way to communicate with iOS/Android native code. I will start with iOS. Though intimidating at first, it is a fairly simple process. Here is what we will need:

  • A bridge from the iOS codebase in Objective-C
  • A way to access that bridge in React Native

Objective-C

Read the Native Module Docs to skip this paragraph. In my example, my header file will be named UserToken, and it will import and extend the RCTBridgeModule to expose the class we need.

// UserToken.h
#import <React/RCTBridgeModule.h>

@interface UserToken : NSObject <RCTBridgeModule>

- (void) getToken;

@end

My implementation file will expose the class using RCT_EXPORT_MODULE() and the method I will be referencing using RCT_REMAP_METHOD(). This method will take the string supplied within React Native, and return a promise that will resolve with the value associated with that key from NSUserDefaults. RCT_REMAP_METHOD() will take four arguments:

  • the name of the method
  • the parameter supplied to that method, in our case the name of the token as stored in NSUserDefaults
  • the resolver that will resolve the promise and return the token from NSUserDefaults
  • and the rejecter of the promise.

The method takes a string as a parameter, in case there are other tokens stored in iOS that the React Native app needs. I’m presenting it this way because, in my case, I needed to be able to declare the name of the iOS token in the React Native code.

// UserToken.m
#import "UserToken.h"

@implementation UserTokens

    RCT_EXPORT_MODULE();

    RCT_REMAP_METHOD(getToken,
                    tokenRequest: (NSString *)tokenRequest
                    resolver: (RCTPromiseResolveBlock)resolve
                    rejecter: (RCTPromiseRejectBlock)reject)
    {
    
        if (tokenRequest) {
            NSString *tokenResponse = [[NSUserDefaults standardUserDefaults] objectForKey:tokenRequest];

            resolve(tokenResponse);
        } else {
            NSError *error = @"error";
            reject(@"no_events", @"There were no events", error);
        }
    }

@end

React Native

Now that the iOS code is exposed using the RCTBridgeModule, we can access it in the React Native codebase. It is as simple as importing the module.

import { NativeModules } from 'react-native'
const iosTokens = NativeModules.UserToken;

function appUpdateSession() {
    if ( Platform.OS === 'ios' ) {
        return iosTokens.getToken('session_token').then((sessionToken) => {
            console.log(sessionToken)
        }
    }
}

If your user is logged in on iOS, and downloads the app update to React Native, this code will log their session token that was stored in NSUserDefaults. You can use this value to prevent them from being logged out!