Explore the Template Project

Learning Objectives

After completing this unit, you’ll be able to:

  • Navigate the project structure for Mobile SDK React Native apps.
  • Configure your project for debugging or production.
  • Find the Mobile SDK React Native sample app and open source libraries on GitHub.

Mobile SDK Templates for React Native

When you create an app with forcereact, the script customizes a template with the arguments that you provide. This customized template is the project for your new Mobile SDK app. For React Native, the template defines a native container app that provides direct access to the native operating system. This container provides the bridge between your JavaScript code and the Android or iOS runtime. In some cases, your development needs might require adjustments to this underlying container. Let’s take a quick look at what’s in that app.

iOS Native Container

The iOS native part of the template project is almost identical to that of a native iOS project. Its two classes take care of:

  • Configuring Mobile SDK for startup
  • Instantiating and displaying the root view
  • Initiating and handling login and authentication

Open <output_directory>/ios/FirstReact.xcworkspace in Xcode. If you skim through the workspace, it’s easy to think that you’re looking at a native iOS project. For example, the AppDelegate class includes most of the boilerplate code of a native iOS app. The React-specific code is in the setupRootViewController method of AppDelegate.

This method creates an instance of RCTRootView, a React Native class, and assigns that instance as the app’s root view. RCTRootView acts as the bridge between native UI components and your app’s React Native components. Notice that you initialize this class with the location (jsCodeLocation) of a bundle that contains your JavaScript code. 
- (void)setupRootViewController
{
    NSURL *jsCodeLocation;
    jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" 
                                                                    fallbackResource:nil];
    RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                        moduleName:@"SecondReact"
                                                 initialProperties:nil
                                                     launchOptions:self.launchOptions];
    rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f 
                                                      green:1.0f 
                                                       blue:1.0f 
                                                      alpha:1];
    UIViewController *rootViewController = [UIViewController new];
    rootViewController.view = rootView;
    self.window.rootViewController = rootViewController;
}

Android Native Container

Open your FirstReact/android project in Android Studio, then go to the Project view and look under FirstReact/app/app/src/main/java/com.mytrail.react. There, you can find two native Java classes––MainActivity and MainApplication. These classes are similar to their native-only Mobile SDK counterparts.

The MainApplication and MainActivity classes fulfill the same purposes as in Android native projects:

  • Configuring Mobile SDK for startup
  • Instantiating and displaying the startup activity
  • Initiating and handling login and authentication

The primary differences between native and React Native templates for these classes are their base classes. In React Native apps, MainApplication extends Application, as usual, but also implements ReactApplication. MainActivity extends SalesforceReactActivity, which, in turn, extends ReactActivity. ReactApplication and ReactActivity come from the Facebook React Native library. Looking closely at the implementations, you find that most code paths ultimately lead to a React Native object. These objects include React-centric specializations of many Mobile SDK classes, such as SalesforceReactSDKManager.

For example, the MainApplication code creates a ReactNativeHostobject and uses it to pass Mobile SDK React Native packages to the React Native framework.
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) {
   @Override
   public boolean getUseDeveloperSupport() {
      return BuildConfig.DEBUG;
   }
   @Override
   protected List<ReactPackage> getPackages() {
      @SuppressWarnings("UnnecessaryLocalVariable")
      List<ReactPackage> packages = new PackageList(this).getPackages();
      // Packages that cannot be autolinked yet can be added manually here, for example:
      // packages.add(new MyReactNativePackage());
      packages.add(SalesforceReactSDKManager.getInstance().getReactPackage());
      return packages;
   }
   @Override
   protected String getJSMainModuleName() {
      return "index";
   }
};
Digging deeper into the SalesforceReactSDKManager.getReactPackage() code, you find that it returns a new ReactPackage object. This object overrides the createNativeModules() base method to return exactly the list of packages you’d expect:
@Override public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
   List<NativeModule> modules = new ArrayList<>();  
   modules.add(new SalesforceOauthReactBridge(reactContext));
   modules.add(new SalesforceNetReactBridge(reactContext));
   modules.add(new SmartStoreReactBridge(reactContext));
   modules.add(new MobileSyncReactBridge(reactContext));
   return modules;
}

The React Native runtime calls this method and other overrides to weave the magic that executes JavaScript methods as native Mobile SDK code.

Configuring Your Build

Looking for where you configure your code to run in debug or release mode? That mechanism is a little different on Android than on iOS. During development and debugging, Android Studio expects to load the JS files directly from the development server. For release mode, it loads the JS files from a bundle on the device. You can override the default build configuration in the project’s android/app/build.gradle file. Follow the embedded instructions in the big comment at the top of the file. For example:

/*** The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
* and bundleReleaseJsAndAssets).
* These basically call `react-native bundle` with the correct arguments during the Android build
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
* bundle directly from the development server. Below you can see all the possible configurations
* and their defaults. If you decide to add a configuration block, make sure to add it before the
* `apply from: "../../node_modules/react-native/react.gradle"` line.
*
* project.ext.react = [
*   // the name of the generated asset file containing your JS bundle
*   bundleAssetName: "index.bundle",
*
*   // the entry file for bundle generation
*   entryFile: "index.js",
*
*   // whether to bundle JS and assets in debug mode
*   bundleInDebug: false,
*
*   // whether to bundle JS and assets in release mode
*   bundleInRelease: true,
*
*   // whether to bundle JS and assets in another build variant (if configured).
*   // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
*   // The configuration property can be in the following formats
*   //         'bundleIn${productFlavor}${buildType}'
*   //         'bundleIn${buildType}'
*   // bundleInFreeDebug: true,
*   // bundleInPaidRelease: true,
*   // bundleInBeta: true,
*
*   // the root of your project, i.e. where "package.json" lives
*   root: "../../",
*
*   // where to put the JS bundle asset in debug mode
*   jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
*
*   // where to put the JS bundle asset in release mode
*   jsBundleDirRelease: "$buildDir/intermediates/assets/release",
*
*   // where to put drawable resources / React Native assets, e.g. the ones you use via
*   // require('./image.png')), in debug mode
*   resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
*
*   // where to put drawable resources / React Native assets, e.g. the ones you use via
*   // require('./image.png')), in release mode*   resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
*
*   // by default the gradle tasks are skipped if none of the JS files or assets change; this means
*   // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
*   // date; if you have any other folders that you want to ignore for performance reasons (gradle
*   // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
*   // for example, you might want to remove it from here.
*   inputExcludes: ["android/**", "ios/**"],
*
*   // override which node gets called and with what additional arguments
*   nodeExecutableAndArgs: ["node"]
*
*   // supply additional arguments to the packager
*   extraPackagerArgs: []
* ]
*/

In iOS, the switch between debug and release modes is handled for you automatically.

Mobile SDK Sample App for React Native

If you’re itching to do some further explorations on your own, check out the MobileSyncExplorerReactNative sample app in the SalesforceMobileSDK-Templates repo on GitHub. This sample demonstrates all the React Native language features you’ve just learned about, as well as some Mobile SDK offline features you may not yet know about:
  • SmartStore––An offline caching mechanism for storing data securely on the device.
  • Mobile Sync––An offline synchronization mechanism for easily merging offline data changes with the source Salesforce records when a device regains its connectivity.
To build the MobileSyncExplorerReactNative sample app on your development machine, use the forcereact createwithtemplate command. Here's an example. 
% forcereact createwithtemplate
Enter the target platform(s) separated by commas (ios, android): ios,android
Enter URI of repo containing template application or a Mobile SDK template name: MobileSyncExplorerReactNative
Enter your application name: MyMobileSyncExplorer
Enter your package name: com.mytrail.react
Enter your organization name (Acme, Inc.): MyTrail
Enter output directory for your app (leave empty for the current directory): MyMobileSyncExplorer

To run the app, start up the React Native development server.

  1. In a Terminal window in macOS or the command prompt in Windows, change to your app’s root directory. In our case, that’s MyMobileSyncExplorer/.
  2. Run one of the following commands:
    • In macOS: yarn start or npm start 
    • In Windows: yarn run-script start-windows or npm run-script start-windows

When the command line reports “To open developer menu press 'd'”, you can run the app from within your development environment.

  1. For iOS:
    1. In Xcode, open MyMobileSyncExplorer/ios/MyMobileSyncExplorer.xcworkspace.
    2. Click Run.
  2. For Android:
    1. From the Android Studio Welcome screen, or from the File | Open menu item, navigate to MyMobileSyncExplorer/android/.
    2. Click OK.
    3. Click Run.

Dig Deeper!

To examine how the native library project defines bridges between Mobile SDK and React Native, see:

Keep learning for
free!
Sign up for an account to continue.
What’s in it for you?
  • Get personalized recommendations for your career goals
  • Practice your skills with hands-on challenges and quizzes
  • Track and share your progress with employers
  • Connect to mentorship and career opportunities