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