GrapheneOS in Practice: What Worked, What Didn't and What's Still Missing
In part one I explained why I keep doing things the hard way, and in part two who is actually prying the doors open. This is the hard way itself: the choices I made turning a Pixel 10 Pro running GrapheneOS into a phone I can live with, what worked, what didn’t, and what I still haven’t solved. If you’re thinking about making the switch, I hope it saves you a few of the Saturday afternoons it cost me.
One rule shaped almost every decision: no Google account on the phone. Sandboxed Google Play is installed, because a few things depend on it, but it has never been signed in. As I write, the only accounts on the phone belong to my own calendar and contacts sync and my messaging app. That rule is the source of most of the friction below, and it’s also the point.
The Install: The Easy Part

The GrapheneOS web installer does the whole job from a browser over a USB cable, and at the end you lock the bootloader again. It went very smoothly, and faster than I’d expected. Compared with my CyanogenMod days, when an unlocked bootloader was the permanent price of freedom, this was the easiest part of the whole exercise.
Where the Apps Come From
There are 53 apps on the phone that didn’t come with it, and choosing where each one comes from is most of the work. Here’s how they split:
| Source | Apps | What it’s for |
|---|---|---|
| Obtainium | 26 | Open source apps, straight from each developer’s GitHub page or website where possible, otherwise from the F-Droid repository, all with update tracking. Obtainium also keeps itself up to date. |
| Aurora Store | 19 | Commercial and closed apps from Google’s Play catalogue, including Magic Earth, downloaded with an anonymous login, so no Google account is involved. |
| GrapheneOS App Store | 5 | GrapheneOS’s own store: sandboxed Google Play, Android Auto (installed, but parked: see below) and Accrescent, a privacy-focused app store with signed, verified updates. |
Shell (adb) | 2 | Sideloaded from my laptop, including a test build of my own app. |
| Direct download | 1 | The bootstrap: Aurora Store. Obtainium started the same way, but now updates itself, so it counts under its own row. |
You’ll notice there’s no F-Droid client in that list. That’s deliberate. An app store, even a good open source one like F-Droid, puts a separate maintainer in the normal release path between me and the people who wrote the app. Obtainium takes that intermediary out: there’s no central store, and updates come directly from the developer. In practice that didn’t work for every app. Some GitHub repositories had no build for the phone’s processor architecture, and others had their own quirks. The fallback was to check the F-Droid repository, which worked for most of them, but I still added those apps through Obtainium, which can use F-Droid as a source, so there’s one interface on the phone instead of two. Going direct matters for some apps in another way too: FairEmail’s Pro activation, for example, only works on the developer’s own build.
One app took a second attempt. At first Podverse refused to install through Obtainium from either its GitHub repository (which publishes no release builds) or the F-Droid repository, so I installed the F-Droid build from my laptop over adb. When I reinstalled it later, Obtainium installed it from the F-Droid repository without complaint, so it now gets updates like everything else. Aurora’s one setting worth knowing about: leave the installation method on the default Session installer. The older Native mode is deprecated and breaks apps that ship as split packages.
What I ended up with, by job:
- Messaging: Molly (a hardened fork of Signal), SimpleX, and Element for Matrix. Discord for the projects that live there (yes, that one makes even me roll my eyes, and it’s next on the list to go).
- Calls: baresip, an open source SIP client, for outgoing internet calls (more below).
- Social: Mastodon, Bluesky, Pixelfed, Primal (Nostr), P2Play for PeerTube, Flickr, and Circle for communities hosted on Circle.so.
- Email, calendar and contacts: FairEmail, Etar for the calendar, and DAVx⁵ syncing both with my own server.
- Notes and bookmarks: Obsidian, Markor and Floccus.
- Photos: Immich, backing up to my own server instead of Google Photos.
- Maps: Magic Earth, on the phone in a holder rather than on the car’s screen (see Android Auto below), and GPSTest, an open source app that shows what the phone’s GPS is actually reporting.
- Listening: Podverse for podcasts, Audiobookshelf for audiobooks, Tidal for music and ABC listen for radio. VLC for everything else.
- Security and network: Bitwarden (backed by my own Vaultwarden server), Tailscale, and ntfy for notifications.
- Tinkering: Termux, KDE Connect, Home Assistant (the minimal build without Google services) and RikkaHub for talking to my own language models.
- Australian and Austrian life: the BOM weather app, Australia Post, Boost Mobile and, yes, the HoT (Hofer Telekom) app, for trips home and to keep my Austrian mobile number.
Android Auto: From Must-Have to Parked
If you drive, start here, because this is where GrapheneOS fights you hardest. When I started, Android Auto was one of the few things I wasn’t prepared to give up. Navigation on the car’s screen was the main reason, with podcasts close behind, and I was ready to put in whatever work it took. This is how that work went, and why I ended up deciding it wasn’t worth it. The setup steps are all still here, because they’ll save you hours if you want Android Auto more than I turned out to.
Installing it. Install Android Auto from the GrapheneOS App Store (the Apps app). That’s it: no Google account, no computer, and the App Store keeps it updated. GrapheneOS refuses to let any other store install it, including Aurora and Google’s own Play Store, because Android Auto gets elevated privileges for driving a car’s screen and GrapheneOS controls who can hand it those. That’s a deliberate security control, not a bug. The App Store’s copy runs a version or two behind Google’s catalogue (17.6 against 17.8 when I checked), which hasn’t mattered so far.
I learnt this the hard way, and it cost me far more time than I’d like to admit. When Aurora’s install failed, the log said only “the first-party package source and shell” could install Android Auto. I read “first-party” as Google’s Play Store, and instead of checking GrapheneOS’s usage guide, I spent hours exporting the files from Aurora, checking their signatures, installing them from my laptop over adb and working out how I’d keep them updated. “First-party” meant GrapheneOS’s own App Store, and the usage guide says so in as many words. I’ve since reinstalled Android Auto the official way. Call it a proper RTFM moment, and a humbling one for someone who has been flashing phones since 2014. The lesson: read the project’s own documentation before believing your interpretation of a log message.
Making it connect. Installing is only half the job. Android Auto has no launcher icon, and on GrapheneOS its privileged permissions all default to off. They live under Settings → Apps → Sandboxed Google Play → Android Auto. Sandboxed Google Play is its own entry under General on the Apps page, not the Google Play Store in the app list, which is where I looked first.
| Toggle | My setting | Why |
|---|---|---|
| Permissions for wired Android Auto | On | Needed for the USB connection and the car’s display |
| Permissions for wireless Android Auto | On | Our second car only does wireless Android Auto. Turn it off if you only ever plug in, because wireless needs much more access |
| Reroute audio to the car | On | Media and navigation through the car’s speakers |
| Handle phone calls | On | Hands-free calls |
The same screen links to Android Auto’s notification access (needed for messages on the car’s screen), its app info, where you grant the usual permissions such as location, microphone, contacts, phone and SMS, and its own settings screen, which is otherwise hard to find. And GrapheneOS, by default, only allows a USB-C connection to charge while the phone is locked, so unlock the phone before plugging in, or the car never sees it.
Getting past “check your phone”. With all of that done, my Mitsubishi Triton finally started Android Auto, then showed “When safe, check your phone to start Android Auto”. The phone showed a notification saying it was connected, and nothing else. Android Auto puts its first-run setup screen on top of whatever the phone is showing, which needs the Display over other apps permission. Stock Android grants that silently, but GrapheneOS doesn’t. Turning it on in Android Auto’s app info got the car accepted.
Getting the apps to show up. The next drive got me the Android Auto home screen with none of my apps on it. Android Auto quietly hides any app that wasn’t installed by the Play Store, and every app on my phone came through Aurora, Obtainium or adb. The fix is buried in Android Auto’s developer mode: in its settings, tap Version ten times, then turn on Developer settings → Unknown sources. Google’s own warning dialog says these settings “should not be used to circumvent Android Auto’s app approval requirements”, which tells you exactly what the installer check is for. With that on, Tidal, Audiobookshelf, ABC listen and VLC all appeared, and Molly’s messages come through as notifications. Podverse appeared too, but with nothing in it (more on that below).
Navigation: the wall. Magic Earth still didn’t appear. Navigation apps get stricter treatment, and GrapheneOS’s usage guide is blunt about the rule: apps only appear on the car’s screen if they were installed from the Play Store. The developer switch that rescued my other apps didn’t stretch to navigation. I tried everything short of signing in:
- following Magic Earth’s own FAQ for copies installed outside the Play Store (developer mode, Unknown sources, sideload), which is exactly what I’d already done;
- reinstalling Magic Earth through Aurora (a “Play Store” link had quietly opened in Aurora anyway, which is worth knowing if you’re testing this);
- reinstalling it over
adbwith the Play Store recorded as the installer, which Android allows but which still records the computer as the one that started the install.
None of it worked. Magic Earth’s own suggestion for GrapheneOS users is a separate profile with Google Play signed in, which is the same wall with a different door. The only remaining fix is to sign in to the Play Store with a Google account and install Magic Earth from there. I decided not to. Magic Earth went into a holder on the dashboard instead, which quietly took away the main reason I’d wanted Android Auto in the first place.
None of this is Magic Earth’s fault. I contacted its support team because the speed reading jumps all over the place. That isn’t fixed yet, but the first reply came back fast and was very thorough, and I was extremely impressed. It’s good to see, and it makes me feel the Premium subscription was money well spent. The phone’s GPS turned out to be fine, and OsmAnd showed the same jumps, so whatever is going on isn’t Magic Earth’s alone. I’m sticking with it, because we badly need good alternatives to Google Maps.
The “app approval” Google talks about has nothing to do with whether an app is safe to use while driving. Magic Earth has already passed Google’s car app review, and the same app works on Android Auto for anyone who installs it from the Play Store. Mine is blocked only because it came from a different shop. That’s not safety. It’s a gatekeeper using control of the car’s screen to push people into its own store, and Europe’s top court has already said that refusing to let other apps onto Android Auto can be an abuse of Google’s dominance. I wrote about why that matters, and why we still have no open alternative, in part two.
Podcasts: a disappointment. Podverse showed up on the car’s screen, but empty: no podcasts, no queue, not even its menu tabs, while the phone showed plenty. The app itself works fine without Google, and the car’s screen was the only problem. And this time Google isn’t to blame. The F-Droid build of Podverse switches Android Auto off in its own code, and only the Play Store build has it. Getting that build without a Google account went nowhere: Aurora’s anonymous logins answered with “server busy”, then “not available in your country” for an app that is listed in Australia, and the APK mirrors I’d trust don’t carry it. So I’m back on the F-Droid build, playing podcasts from the phone with the sound going to the car’s speakers over Bluetooth. It worked so well that I barely missed the car’s screen, which should have told me something.
That’s a shame, because Podverse is otherwise the app I want. Its Podcasting 2.0 support is right up to date (chapters, transcripts, live episodes, Value4Value payments to creators), and sync between the phone and the browser just works. The quiet Android repository turned out to have a good explanation: the current app is frozen while the team builds its replacement. In December 2025 they closed every issue on the old app to focus on Podverse’s next generation, which is developed in the open and already running as an alpha at alpha.podverse.fm. The new app handles Android Auto in its own native code, with no Google Play Services involved, and a de-Googled build for F-Droid is part of the plan.
So instead of patching the old app, I tried the new one. I forked it and set up my own build: the de-Googled version, pointed at the public alpha and installed from my laptop over adb.
The build installed without a fuss, and the new app looks good. What it can’t do yet is sign in, so there’s no sync with my Premium account or the browser: the alpha server answers the app’s sign-in and sign-up requests with “not found”. I’ve reported it to the developers. Without sync it isn’t usable day to day, so I’ve gone back to the F-Droid build of the current app, installed through Obtainium, and I’ll switch as soon as sign-in and syncing work.
I’m happy to pay for the open source and privacy-respecting software I rely on. I have a FairEmail Pro licence, a Podverse Premium membership and a Magic Earth Premium subscription. Paying is only part of it, though. An alpha build is there to find rough edges, so I’ll keep testing it, reporting issues and sending pull requests for the small things I can fix. React Native isn’t one of my skills (I’m more of a Flutter person), but build scripts, documentation and careful bug reports are, and the first small change, letting a personal build set its own app name and package, is already in my fork. Until the new app ships, that’s the most useful thing I can give a project I want to succeed.
Ditching it. Then I added it all up. Navigation, the main reason I wanted Android Auto, was never going to reach the car’s screen without a Google login. Podcasts weren’t on it either. What it did do well was play audio, and Bluetooth plays music and podcasts perfectly with none of the setup: no privileged permissions, no developer switches, no unlocking the phone before plugging in and no “check your phone” on the dashboard. Messages on the car’s screen are something I can live without. And Android Auto was the most privileged app on the phone, with access to my location, microphone, contacts, calls and messages, and wireless mode needs more again. That’s a lot of access to hand over for a nicer-looking music player. So I’ve stopped using it. I haven’t uninstalled it yet, because I still want to see whether the new Podverse app fills the car’s screen where the old one left it empty. But day to day, Magic Earth stays in the holder, the sound goes over Bluetooth, and the biggest headache of the whole exercise has gone with it.
Hands-free calls over Bluetooth work in both cars too, including the one that only does wireless Android Auto.
Looking back, I’d have saved myself a few Saturday afternoons by asking a simpler question first: what do I actually need the car’s screen for?
Notifications Without Google
Without Google’s push service, apps either hold their own connection open or poll for new messages, and both cost battery.
- I run my own ntfy server, and alerts from my own systems land there: monitoring, backups and container updates. The phone holds one connection to it, which costs far less battery than keeping a VPN to my home network up just to receive notifications. ntfy can also act as a UnifiedPush distributor, so other apps can push through it instead of each polling on its own. The server is ready for that, but I haven’t switched any apps over yet. The official Mastodon app doesn’t support UnifiedPush, but Tusky and Moshidon (a fork of the official app) do.
- Mastodon and Bluesky were the heaviest battery users in my first measurement. Apps where instant notifications don’t matter get set to Restricted in their battery settings.
- FairEmail now checks mail hourly between 06:00 and 22:00, instead of holding a connection open all day. The schedule is a Pro feature. I paid for Pro with a donation, and activation is tied to each installation, so after a reinstall you request it again from inside the app. I’ve only tested activation with the GitHub build, and it doesn’t work with the Play Store one.
Internet Calls: baresip
Some of my outgoing calls go through an internet phone service (SIP) rather than the mobile network, so I needed a SIP app. baresip is an open source (BSD) Android app built on the long-running baresip SIP library. It hooks into Android’s own calling system, so its calls are handled like any other call (audio routing, Bluetooth), and it doesn’t need to keep a connection open around the clock. I installed it through Obtainium.
Two settings are worth knowing about. If your provider enforces encrypted connections (TLS), which is a good thing, it will expect the audio to be encrypted as well, so set the account’s Media encryption to SRTP-MAND. Otherwise the provider will reject your calls. If a call won’t connect, baresip’s Debug and SIP Trace settings show the provider’s reply. Turn them off again afterwards, because the log then records every call.
And if you only make calls, you can turn off registration for the account. Most providers check your password on each call anyway, so outgoing calls still work, and the app doesn’t have to keep a connection to the server open all day. The trade-off is that you can’t receive calls through the app. That’s fine for me: my own PBX (the phone system that answers my number) decides where incoming calls go, depending on the time of day and whether I’m away.
Texting From the Desk: KDE Connect Instead of Messages for Web
Google’s Messages for Web was one of the things I used most during the working day: a browser tab on the laptop, paired with the phone, for reading and answering texts without picking the phone up. It’s slick, but it needs Google’s Messages app on the phone and Google’s servers link the phone to the browser.
Its replacement is KDE Connect, an open source app on both the phone and the laptop (it runs happily on my GNOME desktop, not just KDE’s own). The two devices pair over the local network and talk to each other directly, encrypted, with no server in the middle. Texts appear in a separate desktop app, KDE Connect SMS, where I can read whole conversations and reply.
It’s been a bit of a change, and the interface takes some getting used to. Sending a text was less polished than in Google’s version at first: my conversations showed phone numbers instead of names. That turned out to be a setup gap, not a missing feature. The SMS app takes names from the contacts KDE Connect copies over from the phone, and KDE Connect on the phone had never been given permission to read them. Android only grants contacts access when an app asks and you agree, and KDE Connect had never asked. One permission and one plugin switch later, more than 5,000 contacts (my own address book, synced to the phone from my own server) arrived on the laptop, and the names appeared.
Even with numbers instead of names it was perfectly workable, and texting is only a small part of what KDE Connect does. On my laptop it also:
- shows the phone’s notifications on the desktop;
- shares the clipboard both ways, and sends files and links in either direction;
- browses the phone’s storage from the file manager;
- turns the phone into a touchpad and keyboard for the laptop, or a remote for presentations;
- controls music and video playing on either device, and pauses the laptop’s music when a call comes in;
- runs commands I’ve set up on the laptop with a tap on the phone;
- makes a lost phone ring from the laptop.
Messages for Web is a texting tool. KDE Connect is a remote control for the phone, and one I expect to lean on far more than I ever did Google’s.
Battery
I measured it properly. With the battery statistics reset at 80% one afternoon, the phone ran 24 hours on battery and used 2,483 mAh, about half of the 4,812 mAh battery it reports, with close to three hours of screen time. That’s about 100 mAh an hour, against nearly 150 an hour in my first 12-hour measurement before I changed anything: about 30% less, and enough for close to two days on a charge. With the screen off it used about 60 mAh an hour, and it spent almost 18 of the 24 hours in deep idle.
Where the rest went surprised me. The mobile radio is no longer the clear villain: the phone was on mobile data for less than three hours of the day. Wi-Fi drew about as much power as the mobile radio, roughly 1,000 mAh each, and the Wi-Fi chip was awake for 83% of the day, waking the phone almost 10,000 times. The likely culprit is KDE Connect, the app I’ve just praised. It held a Wi-Fi multicast wakelock for the entire 24 hours, which keeps Wi-Fi listening for my laptop announcing itself on the home network. The app itself is billed less than 1 mAh, because the cost lands on the Wi-Fi chip instead.
KDE Connect’s own code explains it. The app keeps searching the network for other devices for as long as it runs, and it never stops running. But it has a setting that switches the searching off: Trusted networks limits discovery to Wi-Fi networks you name, and devices you’ve already paired still connect on any network. I’ve turned it on with no networks listed, so the phone never goes looking, and my laptop, already paired, still connects. The catch is that the setting only works once the app has location permission, because it needs to read the network’s name, which is an odd trade on a phone set up for privacy. There’s a second catch, and it’s one I happen to like: when the phone moves to a different network, it no longer reconnects by itself, so I open KDE Connect on the phone when I want the laptop to connect. I’d rather connect when I mean to, but anyone who relies on it reconnecting quietly in the background will find that a step backwards.
It worked. Over the next 18 hours the wakelock was held for about two minutes in total. The Wi-Fi chip was awake less than half the time instead of 83%, it woke the phone almost three-quarters less often, and Wi-Fi drew about a quarter less power. With the screen off the phone used about 47 mAh an hour instead of 60. The overall rate didn’t drop, but that day had more screen time and navigation, so it isn’t a fair comparison. It’s a known problem: a KDE bug report from earlier this month describes the same behaviour, and someone has posted a fix that limits the searching to 30 seconds at a time and still searches straight after a network change, so it keeps the automatic reconnection my workaround gives up. That should be the default, rather than a setting that needs location access to switch off.
A longer run settled it. From a full charge on the evening of 31 October, the phone ran 35 hours on battery and used 3,060 mAh, about two-thirds of the battery, with almost four hours of screen time. That’s about 87 mAh an hour, down from 100 in my first full measurement and nearly 150 before I changed anything, which puts a full charge at more than two days. KDE Connect’s wakelock stayed gone: the only Wi-Fi multicast wakelock in those 35 hours was four minutes, held by sandboxed Google Play, and Wi-Fi woke the phone about 2,500 times a day instead of almost 10,000. The biggest single drain this time was ABC listen, at close to 900 mAh, nearly all of it the mobile radio: a couple of hours of live radio streamed over mobile data, mostly with the screen off. That was the most expensive thing I did with the phone all day and a half, and it had nothing to do with GrapheneOS.
The biggest wins so far came from system settings, not apps: turning off mobile data always active (so the mobile radio rests while on Wi-Fi), the always-on display and Wi-Fi scanning, and capping the screen at 60 Hz. My VPN to my home network was the sneaky one: its keep-alive packets wake the radio constantly, and the cost gets booked to the system rather than the app. It now runs only when I need it.
Camera
I bought the Pixel 10 Pro for its camera, so this mattered. Google Camera runs fine on GrapheneOS without a Google account, and it’s still the best option for Night Sight and HDR+. It’s also one of the biggest battery users, mostly from processing after each shot. GrapheneOS ships its own camera app, which is much lighter. It has a Night mode on Pixels, but not the HDR+ processing Google Camera applies to every shot. I keep both.
Banking and Payments
I’ve left banking until last, and haven’t moved my banking apps across yet. Some banking apps refuse to run on GrapheneOS because they fail Google’s Play Integrity check, and PrivSec.dev keeps a list of which ones work. Tap-to-pay through Google Wallet doesn’t work on GrapheneOS at all. I’ll report back on how my banks fare in a later update.
Still Unsolved: Google Lens and Google Translate
Two Google apps don’t have a free and open source replacement that I’m happy with yet, and both get used a lot in our house.
Google Translate. The promising candidates all run on-device, which is better for privacy than any cloud service:
- Offline Translator (GPL) runs Mozilla’s Firefox Translations models through the Bergamot engine and reads text from images with Tesseract, so it can translate a photographed menu or sign without a connection.
- RTranslator focuses on spoken conversations, translating between two phones in real time, entirely on-device. Its next version is funded through NLnet.
In practice, Offline Translator hasn’t worked out for me. Typed text translates reasonably well, but reading text from photos (Italian menus, for example) was too poor to use, and voice input wasn’t much better. It’s not even close to Google Translate, unfortunately, so I’ve removed it and I’m still looking.
Google Lens. Lens does several jobs, and they need different replacements:
- Reading text from the camera: Image Toolbox has an F-Droid build that swaps Google’s ML Kit for open libraries and recognises text in more than 120 languages. MakeACopy is a fully offline scanner with text recognition.
- Identifying plants: nothing does it quite like Lens. iNaturalist comes closest among open source apps (its app is MIT-licensed). Pl@ntNet isn’t open source, but like iNaturalist it’s built by non-profits and research institutions, and every identification feeds a shared scientific record rather than an ad profile. For a gardener, that’s a trade I’m happy to make.
- “What is this?” visual search: no good answer yet.
If you’ve found good open source answers for either, please tell me. I’m on Mastodon as @leogaggl@social.coop, and replies to this post reach me there too.
What I’d Tell Someone Starting Out
- Decide your Google account rule on day one. Mine was no Google account at all, and it shaped every choice that came after it.
- Set up your app stores before moving anything across. Get Obtainium and Aurora Store working first, and keep a laptop with
adbhandy for the first month. It got me out of trouble more than once. - If you drive, ask whether you need Android Auto at all. Bluetooth may already do everything you actually use.
- Set up a backup before you need it. GrapheneOS’s built-in backup, Seedvault, can write to a USB stick plugged into the phone, with no cloud involved. Mine sat switched off for weeks before I noticed.
- Write down every fix as you go. Your future self is the next person you’ll be helping.
Sources
- GrapheneOS. Install guide, Features, Usage guide and its Android Auto section.
- GrapheneOS issue tracker. Android Auto does not show any of my Map apps (#3004).
- Magic Earth. FAQ, including its Android Auto, sideloading and GrapheneOS advice.
- Aurora Store, Obtainium, Accrescent and F-Droid.
- FairEmail and ntfy.
- baresip for Android and the baresip SIP library.
- KDE UserBase. KDE Connect, including its plugin list and how contact sync works.
- Offline Translator and RTranslator (see also NLnet: RTranslator 3.0).
- Image Toolbox and MakeACopy.
- Podverse. Next-generation app source (AGPL-3.0), the public alpha and the Android source for the current app.
- PrivSec.dev. Banking app compatibility with GrapheneOS.
Comments
Be the first to comment! Reply to this post from your Mastodon/Fediverse or Bluesky account, or mention this post's URL in your reply. Your comment will appear here automatically via webmention.
Follow this blog on Mastodon at @gaggl.com@web.brid.gy or on Bluesky at @gaggl.com