Huang Lili, Android engineer of Wedoctor Cloud service team, loves traveling and food.

Before RN came out, many companies already had a complete set of APPS, which may have complex businesses and various dependencies. In this case, it is obviously impractical to overturn and rewrite the original App, with high costs and risks. So how to do hybrid development is critical.

Currently, the officially recommended routing framework of RN is React-Navigation. Most of the logic of this framework is written in javascript. The stack management of RN pages is controlled by THE JS side. In the rN-native – native – RN jump scenario, if it is managed by a single RN container, it is necessary to determine whether the last page is RN or native when returning, and embed base class modification. If you manage multiple RN containers, you also need to distinguish between jump native and RN when jumping.

Another widely used framework on the Internet is the React-native Navigation framework, which uses basic apis native to iOS and Android. However, the problem of mixed development is the same as that of react navigation. JS’s own stack management and native stack management are not unified, resulting in complex stack management and extra processing for jump. Therefore, by analyzing some routes in the market and reforming the React-native navigation framework, we abandoned the stack management of JS side and put one RN page corresponding to one container, so that the stack management of RN can be integrated into the original stack management.

WYNavigation

The main concept

We use a single-engine multi-container model. In the early stage, we have unpacked the existing RN code into a common package and N Business packages. And every page in the native project jumps to a RouteUrl (like a browser address). These two points provide technical support for our scheme. Sharing a common package allows our code to share an RN engine, and the pattern of RouteUrl allows us to jump to pages without worrying about whether to jump to native or RN pages. The following is the procedure for opening an RN page: Just like react-native navigation, we will register all RN pages in navigation, and Test is the external name of this RN page.

Navigation.registerComponent("Test", () => TestScreen)
Copy the code

When the native main project is started, the common package will be preloaded first. When an RN page needs to be opened, the native will first open an RN container, find the corresponding Business package to load according to the PageName passed, and then upload PageName to the RN end. The RN side finds the corresponding RN page according to PageName, and the container initializes the native navigation bar based on static variables in the found RN page, so since this RN container is equal to a native page, there is only one RN page in this container, so an RN page is equal to a native container, This RN page is embedded in the native navigation stack. In this way RN and the native navigation stack are unified.

Understanding of components, pages, containers

There are three concepts: Component: a unit of RN that has independent functions. A page consists of multiple components. Screen: A page in the sense of UI, including navigation bar and content display. RNContainer: A container that is used natively to hold RN and display RN pages. Our solution is multiple components = one page = one container = one native page, and all pushes and pops on RN pages actually end up going through the native jump of the container, which is equivalent to RN pages jumping and returning exactly the same as native pages.

Hop of route

Combined with our existing App routing mode, we unified the protocols of containers on both sides of iOS and Android, and passed RN page names in the form of parameters.

Native jump to RN

To jump from a native page to an RN page, you need to specify an input parameter pageName, which is the name of the RN page to jump to. If you need to pass parameters, define a dictionary with the key as param and the value as the parameter to pass. As follows, MyPost is the name of an RN page.

// native jump RN
NSDictionary *params = @{@"pageName": @"MyPost"The @"param": param};
[WYMediator routeURL:WYURL(@"xxx/rncontainer") withParams:par];
Copy the code
// Native jump
ExtParams param = new ExtParams();
param.putStringExtra("PageName"."MyPost");
param.putStringExtra("PageParam", pageParams);
Router.startRoute(activity, "xxx/rncontainer", param);
Copy the code

RN jumps to native

Jumping from RN pages to native pages also follows our routing protocol. This procedure is implemented natively and calls the native routing component to jump from the RN container to the specified native page. In the following command, name refers to the protocol corresponding to the native page, and passProps is the parameter required by the native page to be jumped to. If no parameter is displayed, the parameter is left blank. The last parameter is the callback function. When the push method is executed, the route stores the callback function on the JS side based on the incoming componentId. When the native page is closed and returned to the current RN page, the route fetches the callback function based on the current page’s Component and executes it.

Navigation.push(this.props.componentId, {
    name:"xxxx".    passProps: {patientId:'11111'.patientName:'Joe'}
}, (componentId, params) => {
    // Returns the current page callback function
}); Copy the code

RN jumps to RN

A jump between RNS is the same as a jump from RN to a native, passing name, passProps, and callback callbacks via push, except that the name is no longer the native protocol, but the registered name below.

Navigation.registerComponent("Test", () => TestScreen);
Copy the code

RN page return

To close the current RN page is as simple as calling the POP method.

Navigation.pop(this.props.componentId, passProps: {})Copy the code

PassProps is an argument that needs to be passed back to the previous page for the callback method in the previous push, or not.

Container life cycle

RN’s components have their own life cycle:

  • Constructor () //

  • ComponentWillMount () // about to load

  • ComponentDidMount () // Load complete

  • ComponentWillUnmount () // The component is unmounted

However, sometimes this is not enough for our business needs. For an RN page to use a container, the container lifecycle is also critical. We need to do something else during the hidden display of the container, so we added the container lifecycle to our new routing framework:

  • ContainerWillAppear () // The container is about to display

  • ContainerDidAppear () // The container is displayed

  • ContainerWillDisappear () // the containerWillDisappear

  • ContainerDidDisappear () // The container is hiding

The lifecycle of the container and the lifecycle of the component are not necessarily in order, but are mostly used when some data needs to be updated when the container is displayed again, so it may be called multiple times.

Navigation Bar Configuration

The current configuration of the navigation bar is the same as that of the React-native navigation framework, which adopts the style of Tree to pass in navigation parameters and set them natively. The basic usage is as follows:

class MyScreen extends Component {
  static options(passProps) {
    return {
      topBar: {
        title: {
 text: 'My page'  },  leftButtons: [  {  id: 'buttonOne'. icon: require('icon.png')  } ]. rightButtons: [],  }  };  } } Copy the code

When an RN page is loaded, it will fetch the Component of the current page based on the registered PageName. In this example, MyScreen will fetch the corresponding static variable options and pass it to the current RN container. The RN container generates the navigation bar for display based on the configuration in it, so using the native navigation bar ensures that the page is highly identical to the native navigation bar, and you don’t need to add bridge classes to modify the native navigation bar.

Summary and questions

At present, WYNavigation has been put into use in the micro Doctor project, and no obvious bugs have been found in the process of use. This solution solves the problem of navigation stack confusion in complex mixed scenes in a simple way. But because of the current related business involves the page form is single, so for the other TAB, modal involve more than one RN page peers do not make too much deep, but in the future we hope to be able to supplement the missing as soon as possible, use it as a generic solution, for more RN and native mixed development projects, Hope interested partners to share with us.