Releases: Lemonochka/keqdroid
Release list
Keqdroid v0.25.0
Linux
- Starts on Ubuntu 22.04, Linux Mint 21 and Debian 12. 0.24.0 needed a newer system library there and closed before showing a window.
- The built-in updater installs the same kind of package the app came from: deb and rpm after the system password prompt, the tar.gz in place. Packages built from the PKGBUILD open the release page. Before, it always downloaded the AppImage.
- Updating from 0.24.0 still downloads the AppImage one last time: for deb and rpm, install the 0.25.0 package from this page.
Routing screen
- Rebuilt around one group: Direct, Via VPN and Block are rows with the entry count next to the list, and Everything else sits under them with the same three choices.
- Ready-made lists are added in one tap.
- While connected, the hint has a Reconnect button. It saves what you just typed first.
- Custom rules use the same words as the lists.
Routing on the mihomo core
- A bare word in a list (
ru,su) matches that domain zone, as on xray, instead of every domain containing those letters.susome sites direct. geoip:rules look up a site's address only when the domain strategy asks for it (IPIfNonMatch, IPOnDemand), as on xray. With AsIs,geoip:ru- Direct connections look up addresses from home even when DNS goes through the tunnel, so Russian and other sites keep their nearby servers.
- Uses 2–7 MB less memory with geo rules.
Smaller downloads
- Windows: the zip is 27 MB smaller (80 → 54 MB). The cores ship without debugger data, and the icon font shrinks from 1.6 MB to 26 KB.
- Android: the APK is 3.4 MB smaller (48.6 → 45.2 MB): unused Java code and strings in other languages are left out.
- Linux: the icon font shrinks from 1.6 MB to 26 KB.
Translations
- German and Chinese reworked against VPN clients in those languages: one word per thing, no cut-off labels on the phone.
- The Quick Settings tile and launcher shortcuts are translated into Farsi.
- With the System language, a system language the app has no translation for now gives English instead of German.
- Russian counts ending in 1 (21, 31…) show the right number and word form.
Other
- Android: the window background follows the app theme instead of the system one. On HyperOS this was a light strip under the navigation bar with a light system and a dark app.
- The Russia IPs (GeoIP) preset says when sites opened by name are caught.
Keqdroid v0.24.0
Android on 32-bit phones
- New
armeabi-v7aAPK for phones that run a 32-bit Android. - The built-in updater picks the APK that matches the phone.
- On these phones encryption runs without hardware acceleration: Vision servers are barely affected, XHTTP, Hysteria2 and WebSocket servers use more CPU.
Backup
- Exporting over an existing backup file on Android no longer leaves the end of the old file behind. Such files failed to import.
- Backups already damaged this way import again.
Network
- Checking for updates retries once when the connection to GitHub breaks mid-way, instead of failing with WRONG_VERSION_NUMBER.
- Subscription updates retry the same way.
- A failed update check is written to the app log together with the route it took.
Keqdroid v0.23.0
Fake IP
- Works on both cores: desktop TUN and Android now support it on xray too, including providers' ready-made configs.
- The switch moved to the DNS section.
Android
- The VPN reconnects by itself after the system kills the app. Always-on VPN works.
- When the firmware blocks the Quick Settings tile, it connects through an invisible window instead of opening the app.
- Permissions shows an Autostart row on firmware that has its own autostart setting.
- The tile and background reconnects no longer fail when the app window was never opened.
App log
- About > App log: the app and the Android VPN service are shown separately, with a problems-only filter and Copy all.
- Android: shows when and why the app process was closed and whether the VPN was on.
- Memory use is recorded every 10 minutes.
- Subscription contents, which carry server credentials, are no longer written to the log.
Farsi
- Translation rewritten with the terms Iranian VPN clients use; proxy chain screens translated.
- Farsi stays selected after a restart.
- Server names, addresses, versions and input fields keep left-to-right order.
- Two-column layouts keep an even gap between columns.
Other
- Paste link(s) adds a subscription link as a subscription.
- Split tunneling: the Russian apps button selects every ru.* app and verified Russian com.* apps, and no longer picks system or unrelated apps.
- The first connection after launch no longer waits for the app to read the core binary.
- A subscription whose host does not answer through the tunnel fails in about 30 s instead of 90.
- Configs no longer use fields that upcoming xray and sing-box versions remove.
- Removed the hidden kill switch: it had no toggle and could only be turned on by restoring an old backup.
- Desktop: traffic polling no longer piles up stuck requests to the core.
Keqdroid v0.22.1
Keqdroid v0.22.0
Auto server select
- New Auto toggle in the server list, turned on per subscription in Card look > Auto toggle in the server list.
- Auto picks the best server of the subscription and moves to a live one when the current server stops working.
- A server is left only if it fails a fresh ping, and only for a server that answered.
- Picking a server by hand turns Auto off. Auto can be on in one subscription at a time.
- Android, Windows and Linux.
Core settings
- Dial every address at once: all addresses of a server domain are tried in parallel.
- Own addresses for domains: fixed addresses for chosen domains (hosts).
- Resolver for specific domains: a DNS server per domain.
Faster
- Connecting on Android takes about a second instead of about three and a half.
- mihomo no longer waits four seconds on connect when the core log level is warning.
- The first connection on Windows no longer stalls on the system proxy.
- Pings on Android run a batch of servers in one core process, three batches at once; desktop measures sixteen servers at once.
Fixes
- REALITY on mihomo connects to servers on Xray 26.9.9 with
fp=firefoxor no fingerprint in the link. - Pinging with the VPN on no longer returns N/A for every server.
- A core that fails to start shows the reason instead of waiting out a timeout.
- The error under the connect button no longer flashes.
- The add button hides while the server list scrolls down and comes back on the way up.
- Linux: without polkit the app names the missing package; when run as root, TUN starts without pkexec.
- Linux downloads are 29 MB smaller.
Keqdroid v0.21.1
REALITY on mihomo stops failing against an updated server
The symptom is unmistakable and misleading in equal measure. Pings stay green,
the keys in the link are correct, the same servers keep working on the Xray
core, and mihomo answers every single one of them with "REALITY authentication
failed".
Nothing is wrong with the keys. The REALITY server shipped in Xray 26.9.9 asks
for one more thing in the client's TLS hello than its predecessor did: the
post-quantum key exchange X25519MLKEM768, offered ahead of the plain X25519 it
used to be happy with. mihomo can send it, but strips it out unless the server
entry explicitly says to keep it, and the app never said so.
Server entries the app builds for mihomo now keep that key. Servers that speak
plain TLS, and everything running on the Xray core, were never affected: Xray
sends it and always has.
The part this does not fix, and what to do about it
Keeping the key only helps if the key is there to keep, and that depends on the
TLS fingerprint the link asks for. mihomo carries its own fork of the
fingerprint library, and in it the firefox profile stopped at Firefox 120,
released before this key exchange existed; only the chrome profiles carry it.
Xray's fork has a current Firefox, which is the whole reason one and the same
link behaves differently on the two cores.
So on the mihomo core a REALITY server still cannot connect to an updated Xray
if its link asks for firefox, which is also what the app assumes when a link
names no fingerprint at all. Two ways around it until mihomo's library catches
up: add fp=chrome to the link, or run that server on the Xray core, where it
works either way.
Keqdroid v0.21.0
All four cores moved up, and one of them got stricter
Xray is now built from the 26.9.9 revision, mihomo from 1.19.31, and the
sing-box and sing-tun that carry desktop TUN inside keqrnel from 1.14.1 and
0.9.3. Every platform still runs the same Xray revision, desktop and Android
alike, so a server behaves the same wherever you connect from.
One change in Xray is worth knowing about before you update, because it can
stop a tunnel from starting at all. A vless server that has neither TLS nor
REALITY nor vless encryption is now refused outright, unless its address is a
private one; the same goes for trojan without TLS.
A lighter network stack for TUN, on mihomo
mihomo has its own userspace TCP/IP stack now, Mips, written to replace the
netstack it borrowed from gVisor. A TUN device hands the core raw IP packets,
and something has to turn those into connections inside the process: that
something used to be a piece of Google's container sandbox, general-purpose and
carrying a great deal that a proxy never asks for. Mips is written for this one
job, and it is compiled in without the build tag gVisor needs.
It appears as a fourth choice under the network stack in the TUN settings on
Windows and Linux, and only when mihomo is the core running your servers. Xray
has no such stack, so the option stays hidden there, and a value picked for
mihomo is read as gVisor on the other core rather than breaking the tunnel.
Android is unaffected either way: there the stack is fixed, and this setting
has never applied to it.
Servers on a phone: cards instead of squeezed rows
Two columns on a phone used to be list rows cut in half, and a name that fits
in one column becomes a few letters in two. In two columns each server is now a
Material card, sized and spaced the way the spec asks, with the flag, the name,
the protocol and the ping laid out to be read rather than truncated. One column
keeps the list it always was.
A phone in landscape stops wasting the screen
Turned sideways, the header with the connect button took the whole height and
the server list had nowhere to go. From 840 logical pixels of window width, and
that is window width rather than the kind of device, the app now shows a
navigation rail on the side and splits the servers screen in two: the header on
the left, the list on the right. A tablet gets the same layout, and so does a
narrow desktop window.
Windows gives the system proxy back at shutdown
Proxy mode points Windows at a local port, and until now a shutdown or a logoff
left that pointing in the registry. The port dies with the machine, so the next
boot had a system proxy aimed at nothing: no internet in browsers until the app
was opened again, which is a poor thing to discover on a machine that reboots
for updates overnight.
The runner now clears it as the session ends, before Flutter or any plugin gets
a chance to answer that message first. Only a loopback proxy is touched, so a
corporate proxy someone set by hand is left exactly as it was.
Keqdroid v0.20.2
A broken settings file no longer leaves the app with no window
A forced Windows update restarted a machine while the app was writing its
settings, and the file came back the right length and full of zeros: the
filesystem had committed the new size and lost the contents. That file is
written by truncating it and writing over the top, with no atomic swap, so a
reboot in that instant is enough to do it.
From then on the app started and never appeared. On Windows and Linux the
window is shown only once the first frame has been drawn, and the failure
happened before there was anything to draw, so the process sat in the task
manager doing nothing at all; a second launch forced the old window into view
as a blank rectangle that answered no clicks. Nothing tried against it helped,
because none of it touched the file: a fresh download, older versions, rolling
the update back, antivirus exclusions. Settings live in the profile, not in the
app folder, and every version read the same broken copy.
The app now reads that file itself before the settings library does. One it
cannot parse is set aside and replaced from a backup, refreshed at every
healthy start, so the worst case is one session of changes lost instead of
every server and subscription. A start that draws no frame within twenty
seconds shows the window anyway and says where to look, rather than leaving an
invisible process that only the task manager can end. And the desktop build now
keeps a log next to its settings: crash reporting is Android only, release
builds print nowhere, and a failure of this kind used to leave nothing behind.
Ping measures the server again when TUN is on
Through TUN a raw TCP connection measures the local end of the tunnel rather
than the server, so ping becomes a real request through a temporary core,
started as a process of its own. The tunnel has to let that process straight
out, and on mihomo it did not: the measurement travelled through the live
tunnel to the server you are connected to, and from there to the server being
measured. Two hops rarely fit in the timeout. The servers that stayed green
were the ones sharing an address with the connected server, which already has a
rule of its own, so out of twenty servers two would answer and the rest looked
dead while working perfectly.
The rule that lets the measuring core out has been in the sing-box tunnel from
the start and is now in mihomo as well, which is where it was needed: whichever
core you connect with is the one that owns the tunnel and reads those rules.
Speed test is measured the same way and was wrong for the same reason. Proxy
mode was never affected, having no tunnel to intercept anything.
The tile stops blaming the phone for its own impatience
Tapping the Quick Settings tile could answer that the system had refused to
start the VPN. It was watching the wrong signal: the service reports itself
only after it has taken its lock and begun connecting, so a stop that was still
finishing, or a core taking its time, looked exactly like a firmware ban. The
service now reports the moment it starts, and the message means what it says.
When the start really is refused, which is what ColorOS and MIUI do to an app
whose auto-launch they have switched off, the tap now opens the app and
connects from there, instead of ending at a message and nothing else.
Permissions has a new row: unrestricted background work. Switching battery
optimisation off for the app is the only exemption on Android's own list that
an app can ask for by itself, and it is what makes starting a service from a
tile legal in the first place. The row shows whether it is granted and asks for
it in one tap.
Keqdroid v0.20.1
Settings named after what you see, not after the flag behind them
A switch called "Show traffic" says nothing about which traffic or where it
will appear. The row above it, "Flagless icons in theme colours", never
mentioned servers at all. Appearance now falls into two groups, Server list and
Under the connect button, and every switch names the thing it turns on: traffic
speed and volume, VPN and direct traffic separately, connection time, the wave
coloured by ping. A section header that shouted in capitals no longer shouts.
The Russian text got the larger part of this work, because it read like a
translation, which it was. Switches stood as nouns where Russian wants a verb,
descriptions leaned on a dash in place of the missing verb, and a few strings
were still half English: "Sniffing на inbound". They now follow the other
clients that speak Russian, v2rayNG and Hiddify among them, where a switch
starts with a verb and the core's own term stays in brackets when you might
search for it. The long dashes that stood in for those verbs are gone from the
descriptions in both languages.
Two places were not translated at all. The HWID switch under Advanced was
English in every language, and the Russian warning next to a subscription
pointed at a setting name that did not exist in Russian. The lists inside
Device identity had their headings written as English strings in the code:
Android clients, Desktop clients, Cores & plain http.
A catalogue of clients that people actually run
Device identity carries a list of client User-Agents to present to a panel. The
versions in it were plausible rather than checked, and most had fallen a year or
two behind: v2rayNG 1.10 where the client is at 2.2.6, sing-box 1.11 against
1.14, Shadowrocket 2.2.65 against 2.2.92, Hiddify still under the name it
dropped two major versions ago. Every entry has been checked against the
client's own releases.
The roster matches what is in use now, INCY first among the additions, then
FlClashX, ClashMi, Koala Clash, Prizrak-Box, RabbitHole, Throne, Exclave,
Surfboard, Sparkle, ClashX Meta and VPN4TV. Clients that stopped years ago are
gone: Clash for Windows, Nekoray (which became Throne), FoXray, Clash Nyanpasu.
Happ and INCY appear once per platform because their numbering differs per
platform, which is exactly the sort of thing a panel can check.
Device models and system versions were stale in the same way: no Pixel 11, no
Galaxy S26, no iPhone 18 Pro, and the thin iPhone listed as "iPhone 17 Air", a
model that has never existed. Android 17, iOS 27 and macOS 27 are in.
Fixes
A spinner no longer starts over when the list scrolls. Ping a page of
servers and scroll: rows leave the screen and the list, which builds them
lazily, throws them away. Each spinner owned its animation and began at the
first shape, so a row coming back replayed it from the beginning. The phase now
comes from a clock shared across the app, so a spinner returning to the screen
picks up the shape and the angle its neighbours are on, and a screenful of them
turns together.
The Windows settings screen has icons, like every other screen. Four
switches sat on flat cards while the rest of the app gives every setting a row
with a circled icon.
Keqdroid v0.20.0
A switch you can flip is a switch that does something
Plenty of settings here belong to one core and not the other, and all of them
used to stand on screen at once, with a line of small print under the switch
naming the core it needed. That line gets read after the switch is on and
nothing has happened. Now a setting is simply not on screen when the core about
to run your server is the other one: traffic split apart is there on mihomo,
Mux, XMUX, fragmentation, UDP noise, the domain strategy, the split resolver
and the TUN fields of sing-box on Xray, fake-IP the other way round. Which core
runs a server is decided by the server's own format, so the screens follow the
server you have selected rather than the preference.
The server editor knows what the core accepts
Editing a server offered combinations the core refuses outright. XTLS Vision
could be switched on for an xhttp server, where the core answers "XTLS only
supports TLS and REALITY directly" and the server simply never connects. Vision
is now offered only where it works — TCP with TLS or REALITY, or with VLESS
Encryption on — and when a link already carries an impossible pair, the editor
keeps the value and says what is wrong with it instead of quietly rewriting
someone else's link.
Parameters the app has been running for months became editable: httpupgrade and
mKCP transports for VLESS, VMess and Trojan alike, with mKCP's seed, header,
MTU and TTI; early data for websocket; authority and multi mode for gRPC;
xhttp's mode, padding and extra; a pinned certificate and the name to verify it
by; REALITY's post-quantum key. Trojan finally has the choice of security it
always had in the core. The screen itself moved to the same cards, headers and
button groups as the rest of the app.
New
- Autostart with administrator rights on Windows. TUN needs them, and until
now every sign-in meant restarting the app by hand and confirming UAC. The
app registers a scheduled task instead, which Windows starts elevated without
asking. Confirmation is needed once, when the task is created. - Server icons without a flag take the theme's colours. A blue circle on a
purple palette was asked about more than once. The protocol colours are one
switch away in Appearance, for anyone who reads servers by them.
Fixes
- Windows 11 is called Windows 11. The registry still says "Windows 10 Pro" on
it, and the About screen repeated that; the build number tells them apart. - An mKCP server opened in the editor had no transport fields at all — the type
was shown and nothing under it.