This is what I shared at the mobile Developer Conference held by CSDN in the second half of this year. A few days ago, a friend asked me about it and remembered that I had not synchronized it on my blog. Take notes on sharing highlights.

 

At present, you can take a taxi in the United States by using didi App. Yes, there is no need to download a new App. The page of overseas taxi will be displayed automatically when the Current Didi App is opened in the United States.

Internationalization has certain particularity in technology, mainly including:

(1) map

Map is an important support and basis for Didi client. However, none of our friends have overseas road network data at present, so we need to access new foreign map providers for internationalization.

 

(2) Docking of different transport forces

Currently, Didi’s internationalization is to cooperate with partners with overseas investment, such as American Taxi hailing and Lyft.

 

(3) Roaming network

At present, the main user scenario of internationalization is still domestic users going abroad to take a taxi. At this time, users use domestic mobile phones and operators to access the network through overseas roaming. The above three particularities determine the technical differences we need. The following shares also focus on map module, roaming network and multi-service access project evolution.

 

Map of 1.

This section mainly includes two major problems :(1) map selection, (2) map switching

1.1 Map Selection

Didi is an App that relies heavily on maps, but at present our friends and most domestic map providers do not have overseas road network data. In our early stage, the scenario is that Domestic users take overseas taxis. Google Map relies on Google Play Service, which is almost unavailable in domestic mobile phones. Even if Google Play Service is installed, some mobile phones cannot run. Roaming networks also don’t have access to Google Maps, so the most reliable Google Maps are excluded at first.

 

In addition, some Domestic apps use Google Map overseas, but they are completed by transferring and distributing Map slices. We have high requirements on all aspects of the Map, so it is not appropriate.

 

All this requires us to find a suitable foreign map.

(1) Overseas map selection research sites



We were heavily dependent on maps and had some customization requirements, such as lots of markers that needed to be modified after being added, drawing circles and adjusting radius dynamically, etc

 

The main Map data sources available abroad are OpenStreetMap, Here and Tomtom. OpenStreetMap is an open source Map data source, similar to wikipedia, so the data is very new, even more than Google Map, but inevitably there will be some dirty data. In the early stage, we focused on big cities, and the data from OpenStreetMap can meet our needs.

 

Because it involves communicating across time zones, we want technical support to be strong.

 

Performance includes map startup time, rendering speed, front-end response speed, and back-end response speed.

 

Before we started internationalization, Didi’s installation package was already very large, which was basically the first of the mainstream apps in China (of course, Didi App is already quite small now), so we wanted the new map to be small enough.

 

(2) Comprehensive comparison of overseas maps



This time, we investigated five overseas maps including Mapbox, Nutiteq, Here, Tomtom and Bing. Among them

There is no Android version of Bing;

Tomtom has an ancient Android version that is too simple and has little documentation;

The Here SDK is as high as 40M. After communication with them, we can only reduce it to 25M, which is absolutely unacceptable to us.

So we focused on integrating and testing Mapbox and Nutiteq, two map providers.

 

The functions and performance of Mapbox and Nutiteq meet our requirements, and the map data sources are mainly OSM(OpenStreetMap). The API design of Mapbox is similar to that of Domestic maps, which is similar to Google Map, so it is easy to get started. The whole SDK is open source, and the Map style is more beautiful, while the underlying design of Nutiteq Map is unique, and the API usage is very unusual. This has also brought great trouble to our access.

 

Mapbox has many Web users, including Foursquare and Pinterest, but not many Android users. Nutiteq has a lot more Android users, but not a lot of users overall, but we don’t have a better option, and we don’t have a lot of users early on, so they’re all within the acceptable range.

 

Generally speaking, we prefer Mapbox, but Mapbox can only respond to GitHub Issues and emails, and the response is very slow. Nutiteq is efficient with Skype communication. To be on the safe side, Mapbox and Nutiteq did extensive access and testing, which proved useful.

 

Like most apps, to make the package smaller, our main project has abiFilter “Armeabi”, which only plays armabi’s SO, and Mapbox’s Armeabi So doesn’t run on armV7 machines. During the initial integration test, we passed the test by modifying the Gradle script and copying so during compilation. However, Mapbox was not willing to change and the Domestic market does not support Google Apk Splits, so we chose Nutiteq instead of Mapbox. Afterword: After the cooperation with Didi, Mapbox began to pay attention to the domestic market and set up a RESEARCH and development center in China to facilitate communication. In addition, it has recently solved the above arm SO problem.

 

1.2 Map Switching

Instead of using Google Maps, we had to choose a Map that supported multiple countries and was designed to switch between different maps. Yes, weak map and App dependency. To solve this problem, we designed a map isolation layer.

The overall designAs follows:



In the figure above, the second layer MapSDK is the standard API layer of the Map. App only deals with this layer. The API design of the standard layer is based on the Google Map API.

The third layer Adapter layer is the implementation layer that ADAPTS the concrete map to the standard API. Each map has an Adapter that converts the map API into a standard API.

 

The direct dependence of the original App and the three-party map is changed to the MapSDK layer that the App depends on to represent the standard API, and the MapSDK calls the three-party SDK through the specific Adapter. In this way, map switching only needs to replace the dependent Adapter, and there is no change in other places.

 

After the new designCompile dependenciesAs follows:



The App relies on the Map Adapter, which relies on our MapSDK and the MapSDK of the three parties.

When we need to replace the three-party Map SDK, we only need to replace the corresponding Map Adapter. For Android, the build.gradle dependency can be replaced.

 

1.3 Benefits of the new map module design

(1) Decoupling, low switching cost, which has been introduced above, will not be affected by changing the map. (2) Low learning cost business developers only need to be familiar with the standard MapSDK API, do not need to understand the specific use of other maps, time cost is reduced. (3) Universal applicable to all APPS, new APPS in the future, you can directly use the Adapter formed before.

 

1.4 Notes for map switching implementation

(1) All API adaptation In theory, MapSDK should be the maximum set of all API of map. In practice, the required functions can be defined and adapted first according to the situation.

 

(2) The ruler needs to be unified, such as scaling scale and the same coordinate system.

 

(3) API processing is not supported because MapSDK of the standard layer is the largest set of map functions, so it is inevitable that some three-party maps do not support the functions defined by MapSDK. For example, scaling based on a set of points will be implemented by the corresponding Adapter in Debug mode and null in Release mode.

 

There are also API specifications like the MapSDK that we’ve already talked about using the Google Map API as a standard. The Adapter has specific development specification requirements.

 

2. Roaming the Internet

As mentioned above, we initially targeted at the overseas taxi taking scenario of domestic users. At this time, users access the network through overseas roaming of domestic mobile phones and operators, so network access needs to be optimized.

The general roaming network flow is as follows:



Users connect to domestic carriers from overseas carriers and access the Web through a public network (with a wall). Our server is deployed on AWS, and the flow of users’ overseas roaming taxi hailing network is shown as follows:



Since it is very slow to access AWS from the public network, we added overseas special lines, and the optimized process of users’ overseas roaming taxi hailing network is shown as follows:



Users access the domestic transfer server, and the transfer server accesses THE AWS through the overseas dedicated line.

 

The client does the following: (1) pull the transit server domain name list in the list (2) use a transit server domain name access, error with the original domain name relegation retry (3) timing and push to update the domain name list Domain name order here by the server load balancing, returns transit server domain name list is transfer or direct overseas server domain name is also decided by the server.

 

3. Android project evolution

3.1 Original Mode

The previous project to internationalize the business was a simple way to put all the business, components, and tools together, grouped according to the specific package name:



This was not a problem in the early days and was quickly and easily developed, but as more services were connected, such as the new national capacity connectivity we talked about earlier, the problems became more obvious, including:

(1) Coupling between components

Although the package name has been divided, but can still call each other, the dependencies between components are not clear, and there are even cyclic dependencies.

(2) It is inconvenient to add new business

(3) Development issues

The larger the size of the submission, the greater the likelihood of conflict.

 

3.2 SDK engineering extraction

The original project is divided into business project and SDK project. Single business project directly depends on SDK and can be independently developed, run and packaged. As follows:



In this way, after new services are added, the overall project structure is shown as follows:



Each service, as a separate project, shares components, tools, and services in the SDK layer.

The integration engineering is responsible for the integration of Lyft, Ola and GrabTaxi projects. All business projects are provided with AAR, which is packaged and released by the integration engineering.

 

3.3 COMPONentized separation of SDK project

In order to solve the coupling between components, prevent the aggravation of subsequent problems, and facilitate the collaborative development and better reuse, the SDK project components are divided as follows:



SDK is divided into two parts, Business Library and Util Library, mainly depending on whether they can be independent of our Business. Reverse dependence between them is not allowed. Each section contains several components, each in the form of a Module.

 

The Business Library is a common Business layer that contains common Business components such as smooth movement, pickup points, location, geographic information, dotting, and network encapsulation. CommonBusiness stores CommonBusiness that is temporarily common but not enough to be a separate component. It may be separated in the future. Note the package name specification to facilitate future independence.

 

Util Library is a set of tools — View and Util — and DidiSDK is the mass of generic components for the Didi App. It has universal image caching, network requests, basic login components, and so on.

 

3.4 SDK componentized dependency diagram after separation



As you can see from the figure above, even at the Business Library layer, components are divided into distinct upper and lower layers based on dependencies.

 

3.5 SDK componentization classification items

(1) Single and open and closed principle Each module only represents a functional module or a public business, and is open to the public in the form of interfaces for personalized or customized functions. PS: At present, CommonBusiness Module is temporarily used as the integrated package Module of the internationalization SDK, namely the SDK Module in the internationalization SDK project. Later, when one of the common businesses is enough to become a Module, it can be further divided.

 

(2) The evolution of the project is continuous, there is no need to split out every small component, which not only increases the complexity of the project, but also affects the compilation time. Components that are too small to be independent can be split as required in future reconstruction. The CommonBusiness module above, of course, needs to maintain a certain level of specification to facilitate later separation.

 

(3) The dependency relationship through the dependency graph to sort out the dependency relationship, prevent repeated dependence, and see the precipitation relationship. 1. Util Library cannot reversely rely on Business Library; 2. Except for the basic parts of Business Library, such as Net, Geo, EventTrack, other parts should not rely on each other. 3. Net, Geo, EventTrack in Business Library do not allow reverse dependency on other modules.

 

(4) In order to ensure expansibility and convenience, the development specification will continue to split: 1. All business package names start with com.dide. {xx}.sdk.{businessName}; 2. All toolkit names in CommonUtil module start with com.didi.{xx}.sdk.util.{utilName}; 3. All View package names in CommonView module start with com.didi.{xx}.sdK.view.{viewName};

 

(5) The communication between components abandons EventBus, which causes serious coupling, and uses native communication methods, including startActivityForResult, internal broadcast, callback, etc.

 

3.6 Overall design drawing of SDK component project



The dashed line is the SDK layer.

 

3.7 Benefits after componentization

(1) decoupling between components; (2) parallel development and testing of services; (3) separate testing of components

 

If you have any questions, please leave a comment and give us a thumbs up.