INTEGRATING
react native

IN YOUR NATIVE APPS

About me

Alexandre Moureaux

Lead Dev  @

@almouro

github.com/almouro

Check out our open-source (github.com/bamlab) and our blog (blog.bam.tech)

REACT NATIVE

IN A NUTSHELL

REACT NATIVE

Native

React Native

JS VM

It's JS running in a VM controlling Native UI

<Image />

ImageView

BRIDGE

View inspectors

REACT NATIVE IS ESSENTIALLY NATIVE

ENJOY REACT NATIVE DEVELOPMENT

LIVE RELOAD / HOT RELOAD

COMPONENT-DRIVEN ARCHITECTURE

ONE CODE / TWO PLATFORMS (OR MORE...)

HANDLING

NAVIGATION

KEEP A CONSISTENT STACK

HANDLING NAVIGATION

Recommended solution in RN is react-navigation

BUT IT'S A FULL JS SOLUTION

NATIVE SCREEN

NATIVE SCREEN

REACT SCREEN

REACT SCREEN

NATIVE SCREEN

THE SOLUTION

native-navigation by

INSTALLING NATIVE NAVIGATION

REgister screens IN JAVASCRIPT

import Navigator from "native-navigation";
import ArticleDetailScreen from "./screens/ArticleDetail";

Navigator.registerScreen("ArticleDetail", () => ArticleDetailScreen);
let screen = ReactViewController(
  moduleName: "ArticleDetail", 
  props: ["articleId": articleRef.identifier as AnyObject],
)
navigationController?.pushReactViewController(screen, 
                  animated: true)
final Bundle props = new Bundle();
props.putString("articleId", article.getId());
screenCoordinator.pushScreen("ArticleDetail", props);

PUSH VIEW FROM NATIVE

OR FROM JS

Navigator.push("ArticleDetail", { articleId: article.id });

CONFIGURE YOUR NAVBAR

import Navigator from "native-navigation";
import ArticleDetailScreen from "./screens/ArticleDetail";

Navigator.registerScreen("ArticleDetail", () => (
  <Navigator.Config
    statusBarHidden={false}
    title="HISTORY"
    titleFontSize={14}
    titleFontName={`${themes.fonts.competitionFont}-Bold`}
    titleColor="white"
    backButtonTitle=""
    displayHomeAsUp
    showTitle
    contentInsetStartWithNavigation={0}
    statusBarTranslucent={false}
  >
    ....
  </Navigator.Config>
);

COMMUNICATE

BETWEEN

REACT

AND NATIVE

exchanging over the bridge

Native app

JS engine

thread

Bridge

Asynchronous messages or events (sent on a queue)

Main thread

Native module thread

WRITE NATIVE MODULES

EXPOSE NATIVE FEATURES

- Video Player

- Photo Gallery

- Membership

- Translations

#import <React/RCTBridgeModule.h>

@interface RCT_EXTERN_MODULE(VideoPlayer, NSObject)

RCT_EXTERN_METHOD(
startVideos:(nonnull NSArray<NSString *>)videoIds 
at:(nonnull NSInteger)index 
loadRelatedContent:(BOOL)loadRelatedContent)

@end
@objc(VideoPlayer)
class VideoPlayer: NSObject {
  @objc(startVideos:at:loadRelatedContent:)
  func startVideos(videoIds: [String], 
     at index: Int, loadRelatedContent: Bool) {
  ..        
    // Native modules are in a separate native thread
    DispatchQueue.main.async(execute: {() -> Void in
      presentVC.startVideos(
        videos: videoRefs)
      })
}

iOS

class VideoPlayerModule extends ReactContextBaseJavaModule {    
  @ReactMethod
  public void startVideos(List<String> videoIds) {
    VideoPlayerActivity.startVideos(
      getCurrentActivity(), 
      videoIds);
  }
}
public class VideoPlayerPackage implements ReactPackage {
  public List<NativeModule> createNativeModules(
        ReactApplicationContext reactContext) {

    List<NativeModule> modules = new ArrayList<>();
    modules.add(new VideoPlayerModule(reactContext));

    return modules;
  }
}

IMPLEMENT THE MODULE

IMPLEMENT THE PACKAGE

ANDROID

public class MainApplication extends BaseApplication 
      implements ReactApplication {

  private final ReactNativeHost reactNativeHost = 
      new ReactNativeHost(this) {
    @Override
    protected List<ReactPackage> getPackages() {
      return Arrays.asList(
        new MainReactPackage(),
        new VideoPlayerPackage(),
    }
  };
}

REGISTER THE PACKAGE IN THE APPLICATION

import { NativeModules } from "react-native";

const VideoPlayer = NativeModules.VideoPlayer;

VideoPlayer.startVideos(videoIds, at, loadRelatedContent)

USE THE MODULE IN JAVASCRIPT

BUT YOU CAN ALSO EXPOSE CONSTANTS

THOSE METHODS ARE ASYNCHRONOUS

@objc func constantsToExport() -> NSObject {
let dict: [String: [String: String?]] = [
    "api": [
        "gotw_base_url": ApiBaseURL.goalOfTheWeek.urlString,
        "digital_base_url": ApiBaseURL.mobileBackend.urlString,
    ],
    "competition": UefaConfiguration.getCurrentCompetition()
]

return dict as NSObject
}

EXPOSING CONSTANTS

import { NativeModules } from "react-native";

const Configuration = NativeModules.UefaConfiguration;

const apiUrl = Configuration.api.digital_base_url;

bootstrapping a module

https://github.com/bamlab/generator-module-react-native

WRAP NATIVE COMPONENTS

- AdMobBanner

- TwitterKit

- Match Card

REUSE COMMUNITY MODULES

- react-native-linear-gradient

- react-native-admob-banner

FROM NATIVE TO REACT NATIVE

class func didAppearBecauseScroll() {
  let args: [AnyObject] = ["onAppearBecauseScroll" as AnyObject]
  ReactNavigationCoordinator.sharedInstance.bridge?
    .enqueueJSCall("RCTDeviceEventEmitter.emit", args: args)
}

SEND EVENT FROM NATIVE

LISTEN TO EVENT IN REACT

import DeviceEventEmitter from "RCTDeviceEventEmitter";

DeviceEventEmitter.addListener(
  "onAppearBecauseScroll",
  this.onAppearBecauseScroll
);

STRUCTURING YOUR     

TEAM

STRUCTURING YOUR TEAM

YOU NEED NATIVE DEVS

- Android App in android folder

KEEP YOUR APPs IN ONE REPO

- iOS App in iOS folder

- RN screens and components in js folder

POINTS

PAIN

PAIN POINTS

- no Multiflavors build support out of the box on Android

- lots of Bridges to write

- knowledge of Native code is necessary

- Cannot use react-native cli tools easily

NEXT STEPS

- More documentation on the Github repo to come

- Series of blog articles to come

thank you!

:   

)   

@almouro

github.com/almouro

Integrating React Native in your Native Apps

By Alexandre Moureaux

Integrating React Native in your Native Apps

Lightning talk

  • 889