利用 React Native 打造视频点播应用

602 阅读4分钟
A deliberate mixture of metals and other elements makes stronger and/or more versatile metals…

When your company provides video streaming technology to global entertainment brands like Festival De Cannes and SXSW it’s crucial for software developers to operate with unified source code and workflows, and to do so in the most platform-agnostic way possible.

This is the challenge faced by the R&D team at SHIFT72, as we develop video streaming apps for a growing list of global entertainment brands like the ones mentioned above. We started exploring React Native as one of the obvious solutions but were initially unsure how effective it would be, since hybrid apps, which rely on a heavy WebView layer, rarely present with good UX. On the other hand, we soon found that the React based framework can achieve native-level performance, for those JavaScript powered components have not shown noticeable performance degradation in comparison to those programmed in Objective-C.

We have been using React Native for almost a year now and things have been going well. We released our first React Native powered app on Apple TV and are very close to releasing our new mobile apps. It seems like a fitting time to review our development journey and provide some insight for those considering React Native as we approach the one year mark. Whether the way is rugged or easy? Here is the report.

The fundamental difference between React and React Native

Whether using React or React Native, developers rely on JSX for UI and JavaScript for logic. This is done through virtual DOMs that represents JSX nodes and a reconciliation algorithm that dictates the UI update in an on-demand manner.

More native than web

Although React Native and React share this commonality, there is a fundamental difference: React Native doesn’t use HTML to render elements; instead, it relies on Cocoa Touch and Android UI to draw actual pixels on the user’s screen. This differs from React where final modifications are passed onto real DOMs in HTML. To illustrate this difference, think about an <Image/> tag defined in JSX file. In order to display the designated image on iOS, the tag is actually backed by a native class RCTImageView, which renders a UIImageView with the properties contained in props passed through. It is this encapsulation of underlying UI frameworks, that makes React Native more consistent across various platforms. If React Native were to expose platform specific APIs directly, we would end up with ad-hoc (JavaScript) code for different platforms, which fundamentally contradicts our primary intention — to create a concise and converged code base.

With this difference understood, we progressed forward onto some real work.

Implementing the Web API Layer

Luckily for us JavaScript is the official language of React Native. This means the battle-hardened source code of our existing web system can largely be re-used and the development of new API requests and model layers can easily be achieved by copy-and-pasting the /api sub-directory. This opens up more time for valuable and meaningful work.

We also found that a wider range of JavaScript projects on GitHub could be used. However, since React Native doesn’t use HTML, anything that manipulates on document object can not work. For these situations we can only keep the pure logic of the destined project, such as a protocol parser for example. Because of this, it’s very helpful if the project draws a clear line between the logic and UI layer.

Implementing the UI Layer

This is where we encountered our first real obstacle: implementing the UI layer for the Apple TV app. At the moment, React Native (0.46.x) appears to not include a full fledged focus engine, nor parallax animation. Due to this, we had to tinker until we found a way to fully support TVOS remote controls. Luckily for us, again, React Native’s intuitive logic flow and modularized source code made adding this feature a lot easier than expected. We’ll leave the modification of React Native for another article, but to showcase the end result, see below.

Next, we added more effects, per the requirement for mobile platforms, and rarely noticed lagging animation or sluggish transition in production; however, we did see slow animation in development build, which was likely caused by the debugger.

Following the same design pattern of React, we encapsulated repeatedly used UI elements into Components, as this ensures those elements only need to be developed once, and then can be used again anywhere.

Implementing multi-tenancy mechanisms

The tension we are facing differs from a lot of other R&D teams who normally work on builds across the development stages (development, staging, product, etc.), in which case react-native-config can be used to define parameters for these different builds.

At SHIFT72 we are required to deploy executable for various clients, and in some cases the executable needs to enlist meta data from multiple clients. Our clients also generally demand different tints, layouts and even UX flows, which can hardly be reflected by static configuration entries. So we don’t rely on react-native-config, but rather on a combination of native multi-tenancy mechanisms (i.e., Xcode targets and build variant) and JavaScript module dependency. This has worked well for us so far.

To do so, we indicate the xxx.index.js for different targets or variants. Then these entry index files decide which components it relies on. Each entry also contains a context object that mandates minor presentation tweaks on general purpose components, like tint and layout, if applicable.

Component Trees

Conclusion

With SHIFT72 now using React Native for app development, we can go shopping for the best parts from the world of React and the world of Native. This is great whenever we are looking for a solution. An interesting discovery we also made along the way is that developers with strong backgrounds in web can help the app team by fixing components, optimizing JavaScript code and revising some obscured implementations, such as nested Promise. Conversely, the know-how also helps our app developers establishing their web development capabilities. This highlights a key point: React Native has not only made our apps cross-platform, but also our team. After all, if a deliberate mixture of metals and other elements can make stronger and/or more versatile metals, then maybe somehow the same principle works on apps and the people who make them.

References

How I set up my React Native Projects
TLDR => Having set up a number of React Native projects, learnt the quirks and pitfalls, I’ve started to settle on a…medium.com
Image Caching in React Native
Update. It’s been almost a year since I wrote this story. You can read my latest finding on this topic in the story…hackernoon.com
React Native ListView with Section Headers - Modus Create
React Native is an exciting framework that enables the developer to easily build native apps using a common web…moduscreate.com
Adding multiple target pipelines for React Native Apps (and Fastlane CircleCI deployment) pt. 1
Why should we add multiple targets to our apps?medium.com
Animate text color change in React-Native
This problem has been bugging me for a while now and I am stuck. I want to animate the color property of my text when a…stackoverflow.com
Optimizing Performance - React
Internally, React uses several clever techniques to minimize the number of costly DOM operations required to update the…reactjs.org
Reconciliation - React
React provides a declarative API so that you don't have to worry about exactly what changes on every update. This makes…reactjs.org
Understanding React — Component life-cycle
React provides developers with many methods or “hooks” that are called during the life-cycle of an component, which…medium.com
Understanding ReactJS — setState
Component state is a way of holding, processing and using information that is internal to a given Component and allows…medium.com