I was recently contracted out by a Fortune 500 company to research the feasibility of implementing either React Native or NativeScript as a future mobile solution for a specific software product within the company. I spent over two months building a prototype application in each framework and documented every highlight, pain point and milestone along the way.
This is not an expansive, all-encompassing review of every strength/weakness of one framework versus the other, but it does touch on some key findings. Although I do cover a lot, I’m sure there are many more topics worth covering and would love to hear from you if you have some in mind.
I was told to focus on these eight topics while conducting my research:
- Testing and Debugging
- Continuous Integration
- Running an Application –Emulators and Device Management
- Platform Tools
- Access to Native APIs
- Completeness of Platform
I reviewed these topics for each framework and documented exactly how each process is achieved. After further ado, here are my findings!
Note: The company is an Angular shop, and some of my conclusions are based on that presupposition.
Testing & Debugging
NativeScript’s debugging capabilities are good, not great. There are a few existing timeout bugs related to accessing iOS ports which hampered development for a small amount of time, but overall, I could connect to the devices and access the console to debug my functions.
There was one issue I had with the debugging process: inability to inspect an element by tapping on it. That is beneficial to my styling capabilities as a web developer. Updating styling without it delivers nothing more than an adequate experience.
React Native supplied a very similar experience from a debugging standpoint. I could log functions and test certain functionality adequately, but the device to element interface is lacking. However, since React Native allows a smoother transition to percentages (see responsiveness section) this didn’t create a significant problem.
Documentation regarding continuous integration and automated build processes with NativeScript are very few. The NativeScript community uses a single blog post as a reference point for learning about how to troubleshoot build and release processes with NativeScript. In this specific example, the author utilizes TeamCity and automates the Android-only build and packaging.
Upon speaking with the mobile team lead, all of the company’s mobile build processes are automated but hosted and maintained in-house at another office. NativeScript is compatible with this approach, and all processes can be automated if the Android/iOS runtime versions are compatible with the installed development kit versions.
React Native’s build processes parallel NativeScript’s approach but is much better documented. Utilizing either the React Native or Expo CLI, the build pipeline can also be automated using the build:ios and build:android commands for iOS and Android, respectively.
Running yYour App – Emulators and Device Management
Due to Apple’s privacy and OS-specific technologies like XCode, the only options for debugging and building an actual iOS application is if you are running on a Mac. XCode has an extensive emulator that has every iOS device form factor.
There are three ways to run a Nativescript application that has been developed:
- Via a connected device
- Via an android emulator – Android Studio has a built-in emulator
- Via a third-party emulator
Local Device Testing
Local device management and testing can be completed either via the CLI or with NativeScript Sidekick. iOS and Android devices are connected via USB and have LiveSync capabilities so any code change within a NativeScript project triggers a local build that updates the application within seconds.
Lists all recognized connected physical or virtual devices.
tns device run
Runs the selected application on a connected device
By default, any React Native app that is built with the Expo CLI is not initially packaged as a standalone app, contrary to NativeScript. First, developers are required to eject the application to ExpoKit (native iOS/Android library that allows developers to use Expo). Next step is to run expo build:ios or expo build:android for iOS and Android builds, respectively, and with a successful build the CLI will generate the corresponding packaged file for each platform.
From there it is broken down into platform-specific instructions, as each platform needs a specific configuration for running on a device. The documentation for that is here.
NativeScript has its own platform tools, while React Native has deprecated its own CLI and tools in favor of a partnership with Expo. Below is a checklist and review of the features that each framework toolset provides.
|Cloud Builds for iOS and Android packaging||✓*|
|Browser-based code editor||✓|
*First 100 cloud builds are free, any after that require a monthly subscription. See rates here
NativeScript Sidekick (Desktop GUI) – This is NativeScript’s hub for application management. In this GUI developers manage connected devices, build packaging processes, plug-ins and more.
NativeScript CLI – Command line alternative to Sidekick.
NativeScript Playground –NativeScript’s browser-based code editor and client application for iOS/Android.
|Cloud Builds for iOS and Android packaging|
|Browser-based code editor||✓|
React Native building, packaging, release and debugging all rely on a technology called Expo. Expo maintains a suite of products – Client, CLI, Snack, ExpoKit, and SDK. React-native’s partnership with Expo has given developers an entire framework to assist with device management, testing and debugging.
Expo CLI – React Native used to have its own native CLI to create and manage project and connected devices. As of their recent partnership with Expo, React Native has shifted its CLI processes to Expo and deprecated both create-react-native and react-native commands in favor of Expo’s CLI. My experience with the CLI has been very mixed. Configuration was one of the most drawn-out processes in any framework set up that I have ever implemented. Due to the fact that Expo recently deprecated its desktop application XDE in its 30.0.0 release, the GUI for React Native device management and debugging has transferred over to an in-browser debugging tool, hosted locally on a server. This is helpful, but also significantly more difficult to configure because each developer needs to configure his/her proxy to tunnel through Localhost:8888 which is a liability with corporate firewall and proxy policy.
Expo Client – React Native’s alternative to NativeScript’s playground application. As a free app in the App and Google Play stores, it allows any iOS/Android device to wirelessly run the application via QR Code (Android only) or via a link to a hosted server.
Snack – Browser-based code editor where you can run your application wirelessly.
ExpoKit – ExpoKit is an Objective-C and Java library that allows you to use the Expo platform with a native iOS/Android project, preferably with React Native. See the React Native section of Local Device Testing for a little bit more context on this.
The companion tools that accompany both React Native and NativeScript are similar, but this is an area that is very dependent on what operating system you are using. For Windows development, one important question that needs to be asked is:
“Can you truly develop for RN/N on any operating system?”
And my answer to that is: “Not realistically”.
As noted above, NativeScript possesses the ability to build to the cloud when packaging your .ipa and .apk files that will run on the device. This functionality was very helpful when building a simple prototype application. However, that seems to be the extent of its helpfulness, as NativeScript charges developers a monthly rate if they surpass 100 cloud builds a month. Due to that subscription model, this would end up being a costly approach compared to React Native when implemented at an enterprise level. I also foresee potential iOS-specific device and build issues that can only be solved by accessing the build files on a macOS device.
The alternative to cloud build packaging is to build locally. Both incorporate well with Xcode and Android Studio and can achieve that functionality equally. However, this is only achievable when developing on macOS (sorry Windows/Linux users).
Access to Native APIs
NativeScript supports Mapbox, Google Maps, and even native app map applications very efficiently. For the prototype application, I used Mapbox to ensure that the map technology on the existing application is supported in NativeScript. I utilized the well-documented nativescript-mapbox plugin and it was very simple to use.
React Native also utilizes an easy-to-use plugin for Mapbox but requires an import to local build files to get it to work.
NativeScript utilizes an open-source plugin to access the camera application and take photos. Displayed on the prototype application. Very easy to implement and use. Functionality requests camera and photo permissions and then opens the camera application.
React Native also supports a multi-functional plug-in for camera functionality. This plug-in also needs to be imported into the build files so that it can work.
*push notifications via cloud messaging requires a third-party
For the prototype, I implemented push notifications by using a local notifications plugin. This was a very simple process, all that it required was installing the plugin in the project package.json, importing it, and utilizing a function.
React Native also utilizes a plugin to send local and cloud push notifications, but it accomplishes this with a bit more time-consuming approach than NativeScript. The actual implementation of the notification is similar, but React Native developers need to register with Apple first in order to send a push notification.
This extra step can either be accomplished by editing the iOS App’s AppDelegate.m file and importing the notification plug-in or manually registering for notifications in XCode, both of which require a macOS device to complete. The plug-in also requires edits to Android’s build.gradle file in order for it to work on the Android side.
NativeScript’s plug-in uses a third-party plugin created by a well-known NativeScript contributor for its local storage capabilities. The plug-in possesses six functions to read, write and access local storage for your NativeScript application.
Responsiveness has a few obstacles in NativeScript. The built-in functionality is to create different XML or CSS files for each form factor (mobile/tablet) and style it from there. However, that screen size qualifier approach is not compatible with Angular and Webpack builds due to Angular’s AOT compilation.
As of September, NativeScript doesn’t have built-in CSS media queries. A few different plug-ins have been implemented to try and fix this and there are some hacks available, but it is an additional challenge.
However, there is an available plugin that mocks the CSS media query functionality. The plugin allows you to define platform-specific styling using .ios or .android prefixes on any class and also manages to (a bit clumsily) prefix device size in terms of dpi (.ios1024 .android680)
From there, I ran into a few issues implementing the plugin. I felt that it created too much rework to implement it when I had already established a project file structure. EddyVerbruggen, who is one of the top minds in the NativeScript community, suggested this workaround and I implemented a similar solution. The premise of his solution utilizes the NativeScript device interface which has os, deviceType and model properties which assist in building cross-platform or form-factor.
React Native seems to have a much more comfortable implementation of device and platform responsiveness. Although React Native doesn’t fully support applying percentages to CSS properties, there is a package named react-native-response-screen that allows developers to convert percentages to dependent pixels.
A second React Native library named react-native-responsive give developers the full capability to implement Media Queries throughout platform and device form factor, rounding out the responsiveness capabilities of React Native as a whole.
Completeness of Platform
One of the most important factors in a quality framework is its community. Usage, issue management, and consistent updates are imperative for a framework to be a successful and sustainable investment. Here is a break down of the statistics surrounding the NativeScript and React Native communities, respectively:
Over the course of the project, I submitted issues to both NativeScript and React Native repositories, and I received a quick response from contributors in each situation. However, the most glaring difference in the communities is in the volume of issues submitted. Due to React Native’s maturity and larger adaptation, when I encountered an issue and I searched StackOverflow, Github, internet forums, etc. for an answer there would be three or four different people who had the exact issue or a similar one. Due to this, I saw multiple potential solutions and determined which one was the best remedy for my problem.
When I encountered an issue with NativeScript, I would find a similar question asked only once on either Stack Overflow or the NativeScript forums and at times a speculative answer would be given instead of a verified contributor answer which led to further investigating on my end. This could potentially be a point of concern, but not definite. Although the smaller developer community required me to research further, I developed a deeper grasp of the framework in doing so.
Learning Curve and Skillset reuse
Project and folder structure, development language and testing framework are all the exact same as an Angular web application, nothing on that end of the application changes when utilizing NativeScript.
On the React Native side, there would be no existing code reuse because the development team would be implementing an entirely new framework. Feature implementation would take on a different approach due to the way that React Native focuses on separation of concerns.