

In a few words: It’s been amazing. We think they are great developers and we learned a lot from them. They communicate efficiently with the stakeholders and provide helpful feedback and suggestions. Even though they are external contributors, we consider them as colleagues and part of the team.
In brief
The kiwi.com app helps organize your air travel in a simple and safe way. It offers the best prices for your airline tickets and guarantees to cover missed connections. The client had a mobile app for both platforms - iOS and Android - with totally separated codebases.
React Native integration
We identified several problems; the major ones were as follows:
Loading React Native screens was slow
The user opened the app and when it was time to click a button to navigate to a React Native screen, the user had to wait for the JS to load. If the user navigated back and clicked again, they had to wait one more time.
Navigation
The app had problems integrating the native side of things with react-navigation. On Android the major problem was the back button interaction. On iOS, the swipe back gesture.
Packaging and distribution
- Kiwi had a repository with the JS code that was being released to npmjs
- A different repository was creating a library for Android consuming the npm package
- A different repository was creating an iOS framework consuming the npm package
- The problems with this approach were that the responsibilities were spread among 3 repositories and 3 owners.
The main problem here was keeping the React Native version in sync as we needed to update it in the 3 different repositories at the same time.
The client was also interested in having CodePush.
Reusing Native code
The client wanted to be able to reuse some existing Native code in React Native without having to re-implement it.

Techniques to adopt
We decided to go for a brownfield approach and apply the following techniques for the following issues:
- Loading React Native was slow
Init the bridge in advance and only one time (share/reuse it)
- Navigation
Init the bridge in advance and only one time (share/reuse it)
- Packaging and distribution
Move everything to a single repo, automate releases (maven on Android) and generate a .framework on iOS. Add Codepush
- Reusing Native code
Write native modules that can use the dependency injection pattern

Solution: the singleton pattern for Android and iOS

Loading React Native screens
The solution for both platforms is written in a different way but the idea is the same: Using the singleton pattern.
iOS
We initialize the RCTBridge when the app starts (not when the user navigates to a React Native screen) and we create a singleton to share it whenever it is needed.
Android
We override the ReactNativeHost class and we configure anything related to our ReactInstanceManager there. In the Application level, that is, a class extending android.app.Application, we store there our reactNativeHost instance to be reused and shared. This way, it does not rely on a Context that can be destroyed (like if we were initiating the ReactInstanceManager in some Activity). We also make use of createReactContextInBackground().
.gif)
Navigation
iOS
On iOS, we needed to disable the native swipe back gesture if we were in a nested react-navigation screen (so it could be handled in the JavaScript side). On the other hand, if we were in the first React Native screen (not nested), the gesture needed to be enabled. Therefore, we created a native module so we could enable/disable native gesture from React Native. For such, we used the interactivePopGestureRecognizer.
Moreover, in order to go back from a React Native screen to a native one, we expose a method in our native module to close the current view controller (which is basically calling popViewControllerAnimated.
Android
The Android Activity that hosts the React Native View needs to implement DefaultHardwareBackBtnHandler from the react package. This is explained in detail in Integration with Existing Apps documentation.
However, we should also be able to navigate back from a React Native screen to a native one using any kind of button (like the back arrow on the Toolbar). For that, we wrote a Native Module for React Native to be able to go back to native whenever is necessary. This is as simple as calling the .finish() method of an Activity.
Packaging and distribution
The following would be triggered by GitlabCI in every merge to master so it was fully automatic.
iOS
Here, we had a script that would package everything into a .framework. These were the requirements from the iOS Native team, so they didn’t have to use CocoaPods and build React. We uploaded that .framework into Github Releases and the native team just had to copy and paste it into their project.
Moreover, in order to go back from a React Native screen to a native one, we expose a method in our native module to close the current view controller (which is basically calling popViewControllerAnimated.

Android
On Android there were more steps:
For every native dependency, build the library and deploy it into a private maven repository For every new version of React Native, build it and deploy it to a private maven repository We wrote generic classes and the code responsible for the bridge, navigation, etc. and we made a library out of it, that was published to maven too. Here we were also building the JS code and attach it as an asset The native app was just consuming the library without having a direct dependency to react-native.
We also implemented CodePush so GitlabCI was able to release a new version whenever conditions matched.

Faster for the users and more developer friendly
- React Native screens load without delay
- Navigation works as expected
- Native code can be reused in React Native
- Everything in one repository and React Native version in sync.
- CodePush is working which means not waiting for the App Store anymore when there are JavaScript changes
In short: Delivering a brownfield solution for both platforms which keeps a natural native feeling without having to rely on a WebView. Plus it can work offline!


The challenges we’ve solved so far
get in touch
Fill in the form and tell us a little bit about your enquiry. We’ll get back to you promptly to discuss your requirements.