Skip to content

About

Proxy client for Android with rootful capabilities and Material Design style. Powered by Xray-core.

Topics

Resources

Stars

23 stars

Watchers

1 watching

Forks

Repository files navigation

Material Xray logo

Material Xray

An Android proxy client powered by Xray-core, with a Material Design 3 interface.

Download APK · Release notes · Report an issue

Get started

You'll need Android 7.0 or newer on an arm64, armv7 or x86_64 device, and a proxy server or subscription of your own. Material Xray is a client, not a service that provides servers.

  1. Download the APK from the latest release and install it. Android may ask you to allow installation from your browser or file manager.
  2. Open the app and choose Add new server or subscription. Paste a link, scan a QR code, or enter it manually.
  3. Select a server and tap Start.

What you can do

  • Keep servers grouped by subscription and test their latency before connecting.
  • Import VLESS, VMess, Trojan, Shadowsocks, and Hysteria2 links. HTTP, SOCKS, WireGuard, and raw Xray JSON configurations are also supported.
  • Choose which apps use the proxy, bypass it, or connect through a specific server.
  • Add custom routing rules or apply routing supplied by your subscription provider.
  • See live upload, download, session traffic, and ping on the home screen.
  • Configure DNS, IPv6, and local-network bypass.

Advanced options expose live app and Xray logs, a configuration viewer and editor, and additional connection settings.

Root or rootless?

Category Rootless Rootful
Detection points ❗️ Establishes an Android VpnService, which apps can detect through the system's network APIs. ✅ Configures routing tables to make the tunnel hidden from the apps that bypass it.
Ease of setup ✅ Approve Android's VPN permission, just like any other VPN app. ⚠️ Requires superuser access through su.
Android VPN state ❗️ Occupies Android's VPN slot, easily detected by other apps. ✅ Uses root-managed routing instead, allowing it to hide itself and even coexist with other VPNs like Tailscale.
Per-app control ✅ Choose which apps use the proxy and which bypass it. ✅ Choose which apps use the proxy and which bypass it assign different proxy servers to individual apps.
Hotspot and tethering ⚠️ Does not tunnel tethered clients. ✅ Can tunnel tethered clients through the proxy.
Always-on VPN ✅ Supports Android's always-on VPN. ⚠️ Enabling Android's always-on VPN switches the app to rootless mode.
Auto-connect after reboot ✅ Supported ✅ Supported
If Android kills the app process ℹ️ The proxy process stops too. Always-on VPN can restart the service. ✅ The proxy process can keep running independently of the app.
Stability ✅ Traffic is routed by Android, standard and battle-tested. ℹ️ Rigorously tested but may have rough edges.

TL;DR: Use rootful mode when avoiding VPN detection by other apps is the priority. Use rootless when root is unavailable or you prefer Android's standard VPN integration.

Rootful does not mean undetectable. Apps may use other signals, such as root detection, bad routing policies and weird networking edge-cases. It does not hide another VPN you run alongside it, and coexistence still depends on routing compatibility. If the app falls back to rootless mode, or Android's always-on VPN forces rootless mode, the connection becomes an Android VPN again.

The app is still under active development. Device-specific behavior is possible, especially with root routing and network changes. If something goes wrong, open an issue with your Android version, device model, service mode, and steps to reproduce it. Remove credentials, subscription URLs, and other private information from any logs or configurations you share.

Development

This project is AI-assisted.

Material Xray is a multi-module Kotlin Android app using Jetpack Compose, Navigation 3, Koin, Room, DataStore, and WorkManager. Platform-free code lives in plain JVM modules so a future Compose Multiplatform desktop build can reuse it. Xray-core handles proxy connections; the app manages subscriptions, configuration, routing, and the service lifecycle.

Build and install

Use JDK 21, the Android SDK, Go 1.21 or newer, and Git. The current build uses Android platform 37.0 and CMake 3.31.6, matching CI. Set your SDK path through ANDROID_HOME or sdk.dir in local.properties.

Run from the repository root:

./gradlew :app:assembleDebug

The APK is written to app/build/outputs/apk/debug/app-debug.apk. To install it on a connected device or emulator:

./gradlew :app:installDebug

Checks

Install the Git hook with prek:

prek install

Run tests and assemble the app, then lint and static analysis:

./gradlew test :app:assembleDebug
./gradlew :app:lintDebug
prek run --all-files

Formatting is checked by the hook, not applied by a build. Use ./gradlew ktlintFormat to fix Kotlin formatting. The instrumentation test requires a connected device or emulator and runs with ./gradlew :core:android:connectedDebugAndroidTest.

Signed releases

To build a signed release locally, provide your own keystore:

RELEASE_KEYSTORE_PATH=/path/to/release.keystore \
RELEASE_KEY_ALIAS=your_alias \
RELEASE_KEY_PASSWORD=your_key_password \
RELEASE_STORE_PASSWORD=your_store_password \
./gradlew :app:assembleRelease

CI builds a debug APK on pushes and pull requests. The manually triggered release workflow signs and publishes a release APK, an Xray corresponding-source archive, and build-provenance attestations.

To verify a release artifact with the GitHub CLI:

gh attestation verify <filename.apk> --repo AetherMagee/MaterialXray

Releases before v0.5.0 do not have attestations.

Runtime and native assets

The APK packages arm64-v8a, x86_64 and armeabi-v7a. Both modes run an Android Xray build, packaged as libxray.so. For arm64-v8a and x86_64 the Gradle build downloads the official one. Upstream publishes no Android armeabi-v7a build, so the Gradle build compiles it from the pinned Xray commit with upstream's Android flags and Go toolchain; building an APK therefore needs Go 1.21 or newer. Rootless mode launches it through the JNI shim in core/runtime/src/main/cpp/xray_launcher.c; root mode launches it through core/runtime/src/main/cpp/xray_root_exec.c, which creates the TUN interface in TUN mode, hands Xray its descriptor and starts Xray as its own unprivileged uid with only the network capabilities it needs.

Each APK build downloads the latest geoip.dat and geosite.dat from v2fly/geoip and v2fly/domain-list-community and bundles them as assets. On first use, the app copies the bundled files into Xray's data directory, so a new installation can connect without downloading geodata. The app also queues a one-time background sync on first launch; its download does not delay tunnel startup. Later updates and custom download URLs remain available in Settings. APK builds require access to those release assets.

In rootful TUN mode, the service manages the tunnel interface and routing. Every per-app proxy group shares that one interface: each group's routing table gives its traffic a distinct source address, and Xray routes on that address. Rootful mode binds outbound connections to the physical network interface to avoid routing loops, watches Wi-Fi and cellular changes, and retargets the connection when needed. Rootless mode passes Android's VPN TUN file descriptor to Xray and excludes Material Xray itself from the VPN to prevent routing loops, relying on Android's network routing rather than the rootful retargeting logic.

No Xray binary is committed. APK builds download the release recorded in third_party/xray/VERSION, refusing any archive or executable that does not match third_party/xray/CHECKSUMS.sha256, and compile armeabi-v7a from third_party/xray/COMMIT. Switch Xray versions with:

./scripts/change-xray-ver.sh v26.9.30

The script verifies the published SHA-256 digests of the Android builds, preserves Xray's license, and records the version, source commit, upstream's Go toolchain and hashes under third_party/xray/.

Project layout

Kotlin packages follow the modules (:core:xray is com.material.xray.core.xray), except the service, tile, boot receiver and workers, which stay in com.material.xray.service because Android and WorkManager persist their class names.

build-logic/        Gradle convention plugins shared by every module
core/model          Server, routing and connection state models (JVM)
core/common         Logging, formatting, log buffer, connection state coordinator (JVM)
core/root           Root shell and process execution (JVM)
core/xray           Xray configuration, TUN and routing plans, gRPC stubs (JVM)
core/network        Link probing, DNS and bundled CA handling (JVM)
core/connection     Connection manager, TUN and TPROXY routing, health watchdog (JVM)
core/database       Room database, entities, DAOs, migrations and schemas (JVM)
core/data           Repositories and subscription parsing (JVM)
core/telemetry      Telemetry events and the client interface (JVM)
core/android        Android implementations of the JVM modules' platform interfaces, Sentry client
core/runtime        VpnService, process supervisors, workers, tile, native launcher
core/ui             Theme, components, adaptive layout and all resources
core/navigation     Navigation 3 keys, navigator and scene strategies
feature/*           One Compose screen tree per tab or destination
app/                Application, activity, NavDisplay root, DI assembly, packaging

License

Copyright (C) 2026 Material Xray contributors.

Material Xray's original source code, documentation, and artwork are licensed under the GNU General Public License, version 3 or later, without any warranty.

Third-party components and derived files retain their respective licenses. See Third-Party Notices for attribution, license details, and corresponding-source information.

About

Proxy client for Android with rootful capabilities and Material Design style. Powered by Xray-core.

Topics

Resources

Stars

23 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages