Is React Native suitable for building an OpenGL-accelerated 2D-game? - react-native

Say I wanted to build something like a 2D side-scroller game. Would React Native be suitable performance-wise? E.g., can I use OpenGL-acceleration for it? Or would it probably be slower than just using WebGL and HTML5?
Researched some more and came up with this information:
Apparently there is a GLView which holds a WebGL context:
https://docs.expo.io/versions/latest/sdk/gl-view.html
On that page it says this:
Any WebGL-supporting library that expects a WebGLRenderingContext
could be used. Some times such libraries assume a web JavaScript
context (such as assuming document). Usually this is for resource
loading or event handling, with the main rendering logic still only
using pure WebGL. So these libraries can usually still be used with a
couple workarounds. The Expo-specific integrations above include
workarounds for some popular libraries.
Also a Twitter comment from Expo which mentions 'games' specifically:
Expo Graphics gives you the power of GL combined with Expo+React Native. It
is the foundation for image filters, games, and special effects.
And there should be a demo here:
https://github.com/gre/gl-react
Not much projects listed there which use React Native to build a game. Still, there being a WebGL context interface to a native OpenGL acceleration gives rise to hope.

I've used react-native-webgl to build a minesweeper game. This library has provided the performance gain I needed to render a 16x30 grid of cells with quick transitions from one state to another. In some circumstances the game needs to re-render dozens or even hundreds of cells at once. Default React Native renderer is not fast enough to do that without user noticing the delay.
Note that while react-native-webgl solves the performance problem, it requires you to write low level code such as creating shaders, manage the vertices etc. And I haven't found libraries built on top of react-native-webgl that would work for my task.
So if you really need or want to use React Native for your game, use react-native-webgl or GLView for Expo. Otherwise use a different technology like Unity.
You can find the source code of my game here.

Related

How to create a real life-like 3D avatar with react-native?

This question can sound a bit off-topic or more of tech capacity or capability. Let's say I am pretty new to this whole thing. I recently came across with https://avatarsdk.com and http://tada-time.com and really got curious how they are doing it. Let's say I want to use a real life-like 3D avatar in a react native app, any ideas where to start with? How do I create an avatar in React Native app?
I am well aware of there are API we can pay and use it.
Any help would be appreciated.
I guess what your requirement is to create 3D objects for Augmented reality, if I am correct. Currently Apple and Android provides their own framework for that. IOS's AR kit and android's AR Core is a bit different in terms of code structure(I mean how they approach problems, their functionality etc). I'll consider them a bit advance topic better done on native platforms. Answering your question, I haven't come across any such library in react native and I don't think we'll see any soon as react native is still maturing and still has a lot to do to become stable.
I've seen projects in react native having AR elements, but that was done entirely in native and bridged to react native (hybrid)

What is the difference between React Native and Flutter?

What is the difference between React-native and Flutter technically?
Both technologies seem to do relatively the same thing, and Flutter even admits that it takes inspiration from React: faq
This is even more obvious when they list the same features and have almost the same syntax (StatefulWidget vs Component class).
Similarly to AngularDart being a Dart implementation of Angular; is it right to assume that Flutter is a Dart implementation of React?
Architecturally, React Native (RN) and Flutter are very similar.
What Flutter calls a "Widget" is the strict equivalent to React's "Component". That's what Flutter means when it says its inspired from React.
The difference between them lies in the other aspects of the frameworks:
Interpreted Javascript VS Compiled Dart
Flutter uses Dart, a typed language that offers both "Just in time" (JIT) and "Ahead of time" (AOT) compilation (with tree-shaking included)
In development, Flutter uses JIT compilation to empower hot-reload. And for production builds, it uses AOT compilation for better performances.
React-Native uses Javascript enhanced by some syntax sugar called JSX.
JSX being a different language, it compiles to JS, then evaluated at runtime.
Bridge to native VS Complete rewrite
React native is built on the top of native.
When using a button or a text in React Native, you are manipulating the official object used for native Android/iOS apps.
We can consider React as a common language between Android/iOS to declare layouts – but fundamentally the applications are different with potential inconsistencies.
It's is not true cross-platform. But at the same time, it allows better interoperability with native elements.
Flutter is the opposite. The goal of Flutter is to use as few native elements as possible.
Flutter requests to the OS a window, and then entirely manage its content using Dart and Skia (it's c++ graphics engine).
It has a few implications:
All the UI logic had to be reimplemented by Flutter. Be it scroll, touch events, animations, ...
The application is written entirely in Dart, even deep into the lower layers. It means that whatever the platform is, it's always the same code that is executed.
Potentially anything that can run Dart code and create a window can run Flutter and apps should work with little to no change. As such, web is in progress ( Hummingbird) and basic support of desktops is available.
To some extent, we can compare Flutter to a webview/game engine, but optimized for casual applications.
Remi already has a couple good points. I have one more.
Interpreted with bridges - vs. native and no bridges
Despite what the name might imply, React Native apps are not compiled to native code. React Native apps interpret Javascript code during runtime, and component updates in a React Native app go through a bridge to the native view counterpart. This might slow things down a little bit and be a bottleneck.
On the contrary, Flutter apps (on release mode) are compiled to native code and don't require a bridge for manipulating the UI. This in turn, at least in theory, will be more performant - there's no need to do roundtrips to the native land to make simple UI changes. Not to mention that release Flutter code is natively compiled and there are no interpreters involved.
Dance monkey, dance
Now that we know that release mode Flutter apps don't have an interpreter or the need for bridges for UI manipulations, let's see what those two things actually are in the first place.
We'll do this with a highly hypothetical example app. Our React Native app has a button that makes a monkey dance on the screen. In React Native, our button and the dancing monkey components are written in Javascript and React.
Interpreters
Since Javascript is not a first class language on Android or iOS, your React Native app includes a Javascript interpreter that interprets your Javascript code in runtime. Without the interpreter, you wouldn't be able to write apps with Javascript at all - even a simple console.log('Hello World!') wouldn't work.
According to the React Native docs, in "most cases", the Javascript code will be interpreted with JavascriptCore.
Bridges
Under the hood, React Native uses the native Android Views and iOS UIViews for displaying UI components (such as dancing monkeys) on the screen. But since the UI parts of the Android and iOS SDKs don't use Javascript, you can't make the monkey dance by using Javascript alone.
This is where a bridge comes into play. On the other side of the bridge are your React Native components and logic, written in Javascript. On the opposite side, we have the host Android/iOS app that renders native views into the screen.
From now on, let's call the two sides of the bridge as the Javascript land and the native land.
So, what happens when the user clicks on our "dance, monkey, dance!" button?
The native Android/iOS view dispatches an onclick event, which goes over the bridge to the Javascript land.
Our onclick listener written in Javascript gets invoked. It is a simple call that toggles a boolean inside the component. Something along the lines of setState(() {isMonkeyDancing = true}) or similar.
React sees that something has changed. It comes up with an updated representation of UI elements that has a dancing monkey. The representation is just a tree of plain Javascript objects that describes the updated state of the UI.
The Javascript object tree gets serialized and sent over the bridge to the native land.
The host app receives the serialized object tree and deserializes it. Now it can update the native Android/iOS view to match the deserialized UI representation. Our monkey is now dancing and our user is eternally happy.
So in this example, one button click required going over the bridge two times.
Actually, it's three - just simply rendering a button initially is a call across the bridge itself.
In an app that is more than just one button and a dancing monkey, you're likely to go over the bridge a lot more. And every time you do, it requires serializing data and sending it over from one side to the another.
This is slower than just coming up with the UI representation and updating the UI with that directly. Additionally, there's a cost of interpreting Javascript in runtime compared to having the code compiled ahead of time.
The bottom line
Since Flutter is essentially a portable rendering engine, Flutter doesn't need a bridge to do an UI update. And because of that, UI updates, at least in theory, are faster. That's one reason why building apps with complex animations or things like Flare, SpriteWidget, or even games would be more lucrative with Flutter compared to React Native.
And because Flutter on release mode is AOT compiled, Flutter doesn't need an interpreter either. That's the difference between Flutter and React Native.
Flutter vs React Native: A Developer’s Perspective
React Native by Facebook and Flutter by Google – two hot cross-platform app development technologies creating a buzz. In this post, we will compare both of them in detail from a developer’s perspective.
What’s Flutter and React Native?
React Native is a project started by Facebook internally that they open-sourced in 2015. On the other side is Flutter, a project started by Google which they have been heavily promoting since I/O 2017. Both of these technologies help app developers build cross-platform apps faster by using a single programming language. React Native is already a mature tool and has a huge community, but Flutter also started seeing huge adoption rates since 2017. In this post, we will compare each of them using ten criteria:
Programming language
Technical architecture
Installation
Setup and project configuration
UI components and development API
Developer productivity
Community support
Testing support
Build & release automation support
DevOps and CI/CD support
Programming Language
The key benefit of using a cross-platform mobile app development technology is the ability to use a single programming language to develop apps for both iOS and Android.
React Native — JavaScript
Flutter — Dart
Installation
The installation method should be straightforward without having too many complicated steps so that it could be easily learned by developers that are just starting with it.
React Native - NPM
Flutter - Binary Download from Source
UI Components and Development API
React Native - Less Components
Flutter - Rich in Components
Conclusion
React Native and Flutter both have their pros and cons. Some of the industry experts have predicted that Flutter is the future of mobile app development. Considering the comparison above, it’s clear that Flutter has entered the cross-platform mobile development race very strongly. Let’s not predict the future but wait and watch!
If you learn both technology in deep. So, you will find big differences:
Programming language- Java Script and Dart
Technical architecture- Flex and Skia.
UI components and development API: Widget in flutter but views in React native.
Developer productivity: Debugging is very easy in Flutter.
Community: Big Community support in React Native.
Documentation & Toolkit: Flutter team have created simple duc for all widgets.
Testing support: Flutter providing testing libs.
DevOps and CI/CD: Flutter Providing CI/CD supports.
There are more difference between React Native and Flutter that you can read her.

React Native vs Swift/Objective-C/Java Native

I'm working on a new project for a Fintech company and I have been tasked with looking into whether we should go with React Native or native Swift/Objective-C/Java for our mobile app development technology and strategy going forward.
I have done loads of research into this and have read many of the case studies relating to React Native, but I still don't feel I have enough to make an informed decision at this point.
The broad app functionality will include things like:
Data related functions such as Account Balances and Statements (pretty simple)
Image capture of identity documents and selfies of the users
Capture of biometric data
Push notifications
Some of this is pretty standard and simple, but some of it will require the app to use low level device functions and/or use 3rd party Android and iOS SDKs.
So, in terms of working towards the decision of a mobile development strategy, can I ask you for your input, based on your recent experience, on reasons to consider React Native over native Swift/Objective-C/Java development in the light of the planned functionality listed above (including reasons why it may be far better to stick with the native languages/platforms).
From own experience I can tell that React Native is a good choice for most of the apps when you need to develop and iterate fast. It usually means it would be cheaper to develop for a customer.
Looking at the list of features I can not see anything that can not be done in RN. Sooner or later you'll have to dive into native code, usually to bridge native modules with JS. I've done this multiple times, it's not that hard and documentation on RN website helps a lot.
Be aware that you'll most certainly run into stupid bugs and you'll have to find workaround. At least this happened to me multiple times when I was building RN app half a year ago, maybe now it's more stable.
Also I believe it really depends on what are the devices of potential app users. I've never developed for Android, but heard from fellow developers, that on mid-level Android devices RN runs much slower, this should be tested from the very beginning.
React Native has a really nice and tempting idea behind sounds like "unified and almost fully shareable codebase for different platforms including Web". But from my experience (not so extensive but still) the reality is a little bit different – at some point you will face some issues with native code for sure, and it would be really good if you have experienced Swift/Objective-C/Java developers in your team to deal with it. Don't trust the promises "all you need is just a React Front-End Developer". The React Native platform itself seemed to me more like a magical blackbox which I ran with a single command having no any idea what's inside and how it actually works. You have to know at least something about Xcode and Android Emulator even if Facebook is trying to hide this aspect it from you as much as they can.
TL;DR In my opinion if you really want to try React Native for something more complex than TodoMVC then you need to have at least 3 developers: Web (JavaScript/React), iOS (Swift/Objective-C) and Android (Java). Or just one Superhero.

Appcelerator Hyperloop vs. Plain Titanium Modules

I've started playing around with Appcelerator Hyperloop. While it seems great to access native APIs from JS from day zero, it does raise a few questions about architecture of the platform and the performance.
Currently (AFAIK) a Titanium app has a main UI thread (that runs the native UI controllers) and a JS thread (that runs the JS logic). Each call from JS to Native is passed though the "Bridge" (which is the expansive operation in an app).
Also, Titanium API doesn't cover all the native API and abstracts as much as it can. But if new APIs are introduced it could take time for Appcelerator to implement those into the platform.
One of my favorite things about Titanium is the ability to extend it (using objective-c for iOS and java for Android) - allowing to use native APIs that are not covered by Titanium, and also developing a really native performance controls in case we need to do anything that's too "heavy" for JS. And, as mentioned it's developed 100% native for each platform.
Now that Appcelerator introduced Hyperloop I've done a simple test app and saw that Hyperloop is not translated into native code but just to normal JS code:
var UILabel = require('hyperloop/uikit/uilabel');
var label = new UILabel();
label.text = "HELLO WORLD!";
$.index.add(label);
And another thing about it is that you have to run on the main thread.
So we basically have a few things come to mind here as far as Hyperloop architecture goes:
We still have a bridge? if Hyperloop is JS that calls "special" Hyperloop require then we still have a bridge, that now not only acts as a bridge but also needs to do some sort of reflection (which is also an expansive operation)?
Until now JS ran in it's own thread - so now running in a single main thread seems to be a potential source to more UI blocking operation.
The old-fashioned modules were truly native (not including the bridge call) - so how do Hyperloop-enabled apps compare with those?
There isn't much documentation or articles about Hyperloop that explain the inner working yet - so if anyone has any answers have been trying apps with it could be very helpful.
Answering your questions straight-forward:
There are no Kroll-Proxies involved anymore, since actual classes are being generated on runtime. This is done by using the hyperloop-metabase that does reflection (as you already said) to build an AST that grabs the actual signatures, types, classes, methods, properties, etc.
We did not see any performance-issues with running on the main-thread for now. If you do so, please file a JIRA-ticket so we can investigate the use-case.
The old-modules were "less native" then now, simply because they were all wrapped by the Kroll-proxy (by extending every view from TiUIView and every proxy from TiProxy / TiViewProxy. Hyperloop does not work with those, making the module-development much more faster by also allowing the developer to test his/her process live in their app without the need of packaging and referencing the module manually. Hyperloop modules are nothing else then CommonJS modules that are already used frequently across Alloy and other Ti-components.
I hope that gives you a quick overview on how Hyperloop works. If you have further questions, let us know!
Hans
(As a detailed answer to the above comment)
So let's say you have a tableview in iOS. The native class is UITableView and the Titanium-API is Ti.UI.TableView / Ti.UI.ListView.
While the ListView already provides a huge performance-boost compared to the TableView by abstracting the Child-API usage to templates, those child-API's (Ti.UI.Label, Ti.UI.ImageView, ...) are still custom classes that are wrapped and provide custom logic (!) e.g. keeping track of it's parent-references, internal data-structures and locks to jump between the threads.
If you now check the Hyperloop example of a native UITableView, you access the native API's directly, so no proxy behind it needs to manage sections, templates, items etc. Of course we deliver that API through a kroll proxy in order to display it in Titanium, but you don't "jump between the bridge" with every call you make from the SDK.
The easiest way to see that is to actually run some bigger example like the tableview, collectionview and view-animation. If you do a fast scroll through these, you already feel the performance boost compared to "classic" Titanium API's, simply because the only communication between your proxy and (like a Ti.UI.Window you want to add it to) is the .add() to receive the native API of the type HyperloopClass.
Finally, of course it still makes sense to use Ti.UI.ListView for example, because it comes with the builtin utilities that Titanium devs love (events, easy configuration and layout-handling). But thats also where the benefit of Hyperloop comes along, by allowing the developer to access those API's him-/herself.
I hope that helps a bit more to understand it.

What's the correct way to develop components for Android and iOS?

At our company we have several React Native components built for iOS. They are all JavaScript based components, so they should work under React Native for Android also. Also, most of the components we have should only differ in the design style, so we need to code those differences between both platforms.
What's the right way to enable this components to support Android? Do we have to use if's checking the app Platform and change the style accordingly? If we want to separate the components in two files, Component.android.js and Component.ios.js, is React Native going to automatically detect which one it needs to use depending on the platform it's running?
There is a very simple solution which I prefer. Just use the file extension: .ios. vs .android.
E.g. look at my nav. I use the android toolbar in the android nav and then I can use navigatorIos for ios if I wish. The application platform will correctly load the corresponding platform file just based on the extension. Which means I just load it normally:
var Nav = require('./jsx/Nav');
I like to follow a declarative approach that React talks about, thus:
1) organizing your files would be by function/behaviour and not by platform as the same file with different extensions will be next to each other.
2) Whether platform to be explicit or implicit isn't relevant as you will only split the file into extensions when it's different platform specific components (so this is inherent)
3) Never any need to handle different platform(s) behaviour in your code ever.
4) This is a composition solution as I've already mentioned: files that are cross-platform do not need the platform extension (and might not need an abstract class for extension in some cases even).
This is a simple solution and I do not know how well it would scale for large projects; but I'm all for the declarative simplicity about it.
1. Organize them
Some components will be IOS-only, some will be Android-only, and some will be cross-platform.
I place my components into 3 directories:
/common/components/
/android/components/
/ios/components/
2. Decide whether you want platform to be explicit or implicit
For every component, there are two basic approaches:
Have the parent manage the platform via composition (i.e. parent selects which component to render and/or passes the platform into the children)
Delegate the platform rendering to the child (i.e. child figures out what platform it's on and renders itself accordingly).
The right approach depends on how different your IOS vs Android layout, style, and functionality are. If the two platforms have different layouts and features, you will likely favor the composition approach. If your code is really isomorphic across platforms then you will likely favor delegation.
3. For trivial differences, use if or switch
If the differences between IOS and Android flavors are purely stylistic (e.g. different style sheet), then you can use a simple if to retrieve the right style.
4. For more significant differences, use inheritance and composition for better modularity
If you have a component which has significant differences between IOS and Android (e.g. <MyCameraWidget>), then you might use a base <BaseCameraWidget> and then have <CameraWidgetIOS> and <CameraWidgetAndroid> variants which extend the base component. This properly separates the cross-platform from the platform-specific logic for better component maintainability later on.
The variants may live in different files, or in the same file, depending on whether you want to expose them or not.
If you are using delegated platform rendering, you will likely want to create a <CameraWidget> facade which has the simple task of figuring out what plaform its on and rendering the correct <CameraWidgetIOS> or <CameraWidgetAndroid> component.
Finally, read this Facebook article on adjustments you may want to make with the React Native packager. There is a blacklist feature which allows you to block out android or IOS files for different builds, but as of today that feature is undocumented and potentially not yet released.