Every Android phone made in the last decade is 64-bit ARM. Not sure? Take this one.
โฌ Download APK (arm64-v8a) 32-bit ARM (armeabi-v7a) โ very old phones, some TV boxesPick by CPU, or take the universal build that carries all of them.
Universal (all ABIs, largest) x86_64 โ emulators, Chromebooks, x86 TV boxes x86 โ 32-bit IntelAutomatic build from dev ยท 77467a0 ยท 14 Sep 2026. Debug-signed: install alongside, not over, the release.
Links always point at the newest release. Minimum Android 5.0; the app checks for updates itself under Settings โ About & updates.
Operators can now name the proxy group whose current node the Home Node row, the VPN notification and the profile card show: X-Brand-PrimaryProxyGroup: <group name> (base64: prefix for non-ASCII names). It is a policy header, so it works without X-Branding-Enabled. Picking a node in another group no longer changes what Home shows, and Change node in the notification opens the picker on that group. In Global mode Home shows GLOBAL, as before.
Home and the notification also stopped disagreeing about which group to read: they now share one rule.
The node picker has a new button next to the filter that switches between tabs and dropdown lists. In the dropdown view every group is a row with its current choice; tap it to expand its nodes. Each group has its own latency test. Search, sort and filter work inside every group, and while you search, groups without a match are hidden and the rest open by themselves. Your choice is remembered. Operators can set the default with X-Brand-ProxyGroupLayout: tabs|dropdown; once you use the button yourself, your choice wins.
Group tabs are now separated by thin dividers, so long rows of groups are easier to tell apart.
Subscription cards show Updated 2 hours ago (or just now).
This also fixes how the app knew that time. It used to take it from the newest file in the profile folder, and the active config is rewritten on every connect, so "last updated" really meant "last connected". With Update before connect on, a profile you connected to every day always looked fresh and was not updated before connecting. It now uses the time the subscription itself was downloaded.
REALITY nodes now pick the right handshake on their own. Xray 24.x servers drop the X25519MLKEM768 key share, while 26.9.8+ servers require it, and a server never says which kind it is. In Auto (the new default) the app tries the classic handshake first, switches after a failure and remembers what worked for each server. Settings โ Network offers Auto / Always / Never and the REALITY client version reported to servers that check minClientVer. This replaces the 1.2.1 on/off toggle; if you had turned it on, it becomes Always.
no-resolve or src.allow-lan off), and in-app edits apply to them.ClashFest is on its way to Google Play, and the F-Droid listing is in review. Both will ship the same package, signed with the same key as these GitHub builds, so you will be able to switch between them without reinstalling. Builds from Play and F-Droid are updated by their store and have no built-in update check.
Full Changelog: https://github.com/Nemu-x/ClashFest/compare/v1.2.1...v1.2.2
1.2.0 rewrote every REALITY node to offer the X25519MLKEM768 key share (for Xray-core 26.9.8+ servers). Many servers still run an older Xray that silently drops such a ClientHello, so whole subscriptions lost YouTube, Telegram and other routes after the update.
Operators on current Xray can ship reality-opts.support-x25519mlkem768: true and client-fingerprint: chrome in the subscription themselves; mihomo honours them as-is.
Everything else from 1.2.0 is unchanged: https://github.com/Nemu-x/ClashFest/releases/tag/v1.2.0
The in-app QR scanner no longer uses ML Kit. It is now a small camera view with the ZXing decoder that was already in the app for Companion pairing, so it works on phones without Google Play services and the APK lost the 5 MB native barcode model.
Xray-core 26.9.8+ rejects a REALITY handshake that does not offer the X25519MLKEM768 key share. ClashFest now turns on support-x25519mlkem768 for every REALITY node in your subscription and uses the chrome fingerprint when the node has none or one that cannot carry ML-KEM (in the current uTLS only chrome can). Nodes inside remote proxy-providers are out of reach for this; ask your operator to set the two fields there.
Editing a File profile's config.yaml through Browse files used to be undone on the next connect: the in-app DNS, hosts, tunnels, rules and provider edits were replayed over your text. Your edit now takes over (it already contains them), pressing Back asks before throwing an edit away, and the Files screen says so up front.
Each rule source row shows the time of the last successful download next to its interval, as a real date and time, while the VPN is running.
Settings โ Network โ Stack Mode gains MIPS Stack (mihomo), the pure-Go userspace stack that became mihomo's default in 1.19.32. It can also come from a subscription (tun.stack: mips with Stack Mode on Auto) or from an operator's X-Network-Stack: mips. The app default stays System. The effective stack is now written to the Logs screen on every connect.
test.com: [1.1.1.1, 2.2.2.2]). The editor reads and writes such entries now; type them as test.com = 1.1.1.1, 2.2.2.2.IP-ASN rules; it is now replaced by a trusted ASN mirror.Subscription downloads send mihomo/<core version> ClashFest/<app version>. Panels that pick the output format by the first token (Marzban, Remnawave) keep serving the Clash Meta format, and panels that gate protocols on the core version (mikan) can now see it. A per-profile User-Agent override still replaces the whole string.
The bundled Country.mmdb is gone (the core only ever read geoip.metadb next to it) and unused post-quantum tables from the certificate library are no longer packaged, together with the scanner change about 8 MB less per architecture (compressed).
Highlights from upstream: the MIPS stack is the engine default with a new congestion-controller option (cubic / reno / bbr / bbr3), lazy receive buffers and checksum offload for it; CPU feature detection via auxv on Linux (hardware AES/SHA); MSS now accounts for TCP options; fixes for an anytls race, a nil dereference in HTTP/2 transports, sing-mux half-close, EasyTier restart after an overlay failure and mieru inbound UDP; utls 1.8.8, mieru 3.38, sing-tun 0.4.27. Full list: https://github.com/MetaCubeX/mihomo/releases/tag/v1.19.32
Tap the latency value next to any node in the picker and only that node is tested โ no more re-testing a 200-node group to check one server. The capsule shows โฆ while the test runs and the result lands in place. Works in the Profiles tab list too, and falls back to a plain TCP probe when the VPN is off.
When a subscription update fails in the background, the notification now explains it in your language and offers the fix: Subscription expired (with the date) gets a Renew button, Device limit reached gets Support, and every failure gets Retry. Operators with branding see their name, colour and logo on it.
The persistent VPN notification shows the current node, the live speed, how many days are left on the subscription, and has Disconnect and Change node buttons.
X-Network-Stack, X-Bypass-Preset) are honoured on every refresh, not only on a live fetch.announce headers can use \n for line breaks; profile-web-page-url opens from the Operator tab and About when no cabinet link is set.Highlights from upstream: the new EasyTier outbound (recognised in the node list), stack: mips for TUN, identity-secret for ZeroTier, lower gVisor memory usage, and a long list of connection-cleanup fixes (hysteria/hysteria2 UDP, VLESS decryption panic, WireGuard nil-pointer, xhttp IPv6 URLs, OpenVPN tls-auth, AmneziaWG v3, DomainSet wildcard matching). Full list: https://github.com/MetaCubeX/mihomo/releases/tag/v1.19.31
A profile can now carry a JavaScript function that rewrites its configuration before the engine loads it โ change DNS, rules, proxy groups, anything, without editing YAML, and your changes survive every subscription update.
function main(config) {
config.dns.enable = true
return config
}
It uses the signature other Clash clients already implement, so scripts written elsewhere generally work here unchanged. Find it under Profiles โ โฎ โ Config script. Check runs the script against your real config and tells you what is wrong; Insert template gives you a working starting point.
A few things worth knowing:
Operators who do not want users rewriting the config they serve can send X-Brand-Lock-Config-Script: true.
See Config Scripts in the wiki.
Brings ZeroTier outbound support, AmneziaWG v3.0, H2C and QUICv2 sniffing, a substantially rewritten sniffer, and a long list of DNS and QUIC fixes.
The app's protocol tables had drifted behind the engine. zerotier and shadowquic were missing entirely, and openvpn, tailscale, gost-relay, sudoku, dns and rematch were not recognised in the offline node list โ those nodes worked, but showed up without a protocol badge.
All of them now render correctly, with colours grouped by protocol family. Also fixed: a ZeroTier node was showing its 16-character network ID where the transport badge belongs.
The bundled faces ship at a light-ish weight that some people find hard to read. Settings โ Theme now has a Regular / Medium / Semibold / Bold picker. Leaving it alone keeps the app byte-identical to before.
Optional setting: update the subscription automatically before the tunnel comes up, so you connect with fresh nodes instead of yesterday's.
Cut background CPU and radio wakeups โ the dashboard no longer keeps work alive when nothing is on screen.
---
Upgrading: nothing to do, profiles and settings carry over.