Mobile Development 28 min read

How WeChat Re‑engineered Its Android Architecture for Scalability

This article chronicles the evolution of WeChat's Android architecture from a simple layered design through multi‑process and modular restructurings, explains why a major refactor was needed, and details the new communication, module, and code‑boundary strategies that enable faster development, better isolation, and a lightweight WeChat nano demo.

WeChat Client Technology Team
WeChat Client Technology Team
WeChat Client Technology Team
How WeChat Re‑engineered Its Android Architecture for Scalability

WeChat Android Architecture History

When WeChat Android was first created, it used a common layered architecture. This simple and clear design has been retained to this day, representing the v1.x era of WeChat architecture.

Architecture evolution diagram
Architecture evolution diagram

Figure 1 – Architecture evolution

In the v2.x era, rapid business growth exposed delayed message notifications and a memory‑leak problem in WebView on Android versions prior to 2.3. The growing code base, memory usage, and APK size increased resource consumption, causing the WeChat process to be reclaimed by the system. Consequently, WeChat switched to a multi‑process architecture: a dedicated communication process kept long‑living connections stable, and a separate WebView process isolated the memory‑leak issue.

Modular architecture diagram
Modular architecture diagram

Figure 2 – Architecture diagram

Why Refactor Again

After more than two years of the previous architecture, the number of Gradle modules kept increasing, supporting large features such as Moments, Shake, and Nearby People. The original architecture worked well, but code continued to bloat. Core libraries libnetscene and libplugin grew without limit, and many business‑related classes were forced into a centralized base class, making it unreadable. Lack of compile‑time isolation caused module boundaries to degrade, and tools to limit erroneous dependencies could not fully prevent the damage.

Architecture changes diagram
Architecture changes diagram

Figure 3 – Gradual architecture changes

When hardware teams requested a lightweight version of WeChat for a photo‑album product, the existing monolithic codebase could not be easily trimmed, prompting a full refactor.

Reshaping Modularity

Changing Communication Method

The original Event‑bus was suitable for one‑to‑many broadcasts but became painful for complex data exchange, leading developers to bypass it and place shared code into the base library, causing its bloat.

We replaced the Event‑bus with an SDK‑style interface approach. Each module now provides an SDK containing interfaces and data structures, which other modules consume at compile time.

Register interface diagram
Register interface diagram

Figure 4 – Register interface

Access interface diagram
Access interface diagram

Figure 5 – Access interface

To make SDK exposure even easier, we introduced the “.api” convention: rename any file that should be exposed from .java to .api. The Gradle build scripts are adjusted accordingly.

.api conversion diagram
.api conversion diagram

Figure 6 – “.api” conversion

Gradle settings files are updated to recognize the new file type (see Figure 7).

settings.gradle
settings.gradle
build.gradle
build.gradle

Figure 7 – settings.gradle & build.gradle

Redesigning Modules

We eliminated the “code sink” of the base library by moving previously sunk code back into its owning module. The new mmkernel layer is split into three core parts: CoreAccount, CoreNetwork, and CoreStorage, each handling account state, network callbacks, and storage lifecycle respectively.

mmkernel structure
mmkernel structure

Figure 10 – mmkernel structure

The original module lifecycle only had “Account init” and “Account logout”. We extended it to cover the whole application start‑up and shutdown, allowing each module to define a Plugin class with three phases: dependency() – declare other plugins this one depends on. configure() – initialize data, register services, insert BootTask s. execute() – run the actual startup logic.

Plugin phases
Plugin phases

Figure 12 – Plugin initialization phases

During dependency() a full dependency tree is generated, distinguishing compile‑time type dependencies from runtime logical dependencies.

Dependency tree
Dependency tree

Figure 14 – Dependency tree

The configure() phase traverses the tree to set up data, register IService implementations, and insert BootTask s.

Configure phase
Configure phase

Figure 15 – Configure phase

In the execute() phase each Plugin (also a BootTask) runs its logic according to the ordered tree, ensuring a deterministic start‑up sequence.

BootTask execution
BootTask execution

Figure 16 – BootTask execution

Constraining Code Boundaries

Compile‑time isolation is the only reliable way to keep code boundaries intact. Beyond separating projects, we introduced a fine‑grained “pins” project structure that allows sub‑projects inside a module, each defined by a project.properties file that lists its compile‑time dependencies.

Pins project example
Pins project example

Figure 17 – Pins project example

A custom code‑check tool runs during compilation to forbid illegal references outside the declared dependencies.

Code‑check tool
Code‑check tool

Figure 18 – Code‑check

The pins approach reduces the number of tiny modules, improves incremental Gradle compilation speed, and enforces strict module boundaries.

Trade‑offs and Choices

We evaluated plugin/sandbox solutions (Atlas, Small, DroidPlugin, DynamicApk) that provide dynamic loading and strong isolation. While dynamic plugins are useful for hot‑patches and rapid feature rollout, WeChat’s workflow does not require frequent independent releases, and the added complexity would outweigh the benefits. Therefore we kept the pure modular approach and rely on Tinker for hot‑patching when needed.

Beyond Code, Inside Architecture

To maintain code quality we introduced a “module owner” system. Each module has a designated owner responsible for its code, design, and public APIs, and who reviews any changes made by others. This improves ownership, encourages proactive refactoring, and raises overall code‑review rates.

Final

Refactoring the whole architecture cannot be done in a single sprint; it proceeds incrementally through “split → gray release → merge back” cycles. The result is a lightweight WeChat nano demo (≈3.5 MB, ~10 % of the full app, 25 % of memory usage) that proves the modular design works.

WeChat nano demo
WeChat nano demo

We hope the shared experience helps other teams improve modularity, enforce boundaries, and keep their Android codebases healthy.

mobile developmentarchitecturemodularizationAndroidpluginGradleWeChat
WeChat Client Technology Team
Written by

WeChat Client Technology Team

Official account of the WeChat mobile client development team, sharing development experience, cutting‑edge tech, and little‑known stories across Android, iOS, macOS, Windows Phone, and Windows.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.