Translated from: https://juejin.cn/post/7000630849402044453
In this context, “cross app” refers to the ability to share code and software modules across different executables on different platforms. It’s an advanced version of cross-platform development.
** Author: Bytedance Front End Platform Team - 熊文源**
In our last post, we examined the various runtime environments between apps and games and how they led to the adoption of React Native. The official documentation provides guidance on how to set up a project for non-native developers to build apps for both iOS and Android. However, game development poses its own unique challenges, such as rendering interfaces with a custom graphic engine. To move forward, we first need to address how to properly render native UI. Specifically we need address the following technical question:
How to integrate CI/CD and the IDE for efficient React Native development and debugging.
How to properly integrate the UI with the container page, which is driven by React Native layout.
How to implement OTA updates and support fast, flexible release cycles.
Given that the mechanism is relatively straightforward, we will provide a brief explanation of the methodology and how it differs from other methods as follows.
In game development, native component libraries are integrated in the form of plugins. Thus, the initial step is to integrate React Native as a module. Specifically, on Android, React Native is encapsulated as a separate ARR module, which is then integrated as a plugin, making it accessible to the game’s logic.
The majority of the pages and the game itself are implemented using in-game logic, which necessitates engineering effort to invoke React Native logic, such as opening a React Native page via a button within the game. In Unity, this is achieved by implementing a C# to React Native bridge. This method is commonly used and can be found in other game development platforms.
Debugging is an essential aspect of development, thus, we need to implement a debug toggle feature, and disable it completely in the release version.
Custom game engines often use a single
Activity for all interactions, leading to game pausing and interruptions in immersion when navigating to new pages. In contrast, React Native pages are rendered in
ReactRootView. To implement a React Native page container, we consider the following key steps:
Incorporate a ReactRootView as a sub-view of the Activity or as a system Dialog window.
Utilize an open-source solution, such as a Router, to define inter-runtime communication.
Implement a view management API to organize multiple pages.
Utilize the Unity API to terminate a page by Id using the ‘pop’ protocol.”
The following is a general overview of React Native page container architecture.
Utilize OTA updates from the native side for consistency.
Implement support for diff updates, force updates, and optional updates. These are well-established practices, so they will not be discussed further.
In practice, the stock APIs provided by React Native are not sufficient for certain situations, such as when a game client involves a gateway, which standard APIs cannot handle. This requires the use of custom APIs and components:
Create native modules based on ReactBaseJavaModule.
Create native components based on ViewManager.
However, even this is not enough in the context of game development. Developers may need to inject additional APIs into React Native for specific business logic. The approach of working with React Native can also present a learning curve for game developers who are not familiar with the framework. To address this issue, we have introduced a
CommonModule architecture based on React Native. Here are the key design decisions:
To decouple the dependency on the React Native SDK, we implemented
CommonModule using standardized data structures and interfaces.
We provide standard dependency injection APIs, through which the capacities that pertain to the game are injected into the
ReactBaseJavaModule based on
CommonModule in an on-demand fashion when initializing React Package.
We have made the architecture composable by using the design discussed above. However, that is not sufficient. In the followup iterations, we enhance the components, optimize the view management, and implement degradation policies and disaster tolerance mechanisms. The following illustrates the full architecture.
Our architecture offers a comprehensive solution for custom game scenarios, featuring seamless integration of immersive experiences within game native UI, streamlined integration, development, and release processes, modular cross-platform page development, and the flexibility for dynamic releases at any time.