Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GNirl

GNirl is a native macOS menu bar app that provides reliable Android reverse tethering over USB. It wraps gnirehtet with automatic reconnection, health monitoring, and ADB keepalive — solving the stability issues that make raw gnirehtet unusable for long sessions.

The Problem

gnirehtet works great for a few seconds, then silently dies. ADB connections go stale, the tunnel drops on idle, macOS power management kills the USB link, and the Java/Rust client crashes with no recovery. You're left restarting the process every 10 seconds.

GNirl fixes all of that.

Features

  • Menu bar app — lives in your status bar, zero windows needed
  • Automatic reconnection — detects device disconnects, gnirehtet crashes, and ADB staleness within 5 seconds and reconnects automatically
  • ADB keepalive — sends periodic pings to prevent USB idle sleep
  • Sleep management — prevents macOS from sleeping while connected, auto-reconnects on wake
  • Live log window — watch gnirehtet traffic in real time with copy/clear
  • Colored status icons — green (connected), red (dropped), orange (connecting), gray (idle)
  • Custom icon support — drop your own PNGs for each status state

Requirements

  • macOS 14+ (Sonoma or later)
  • ADBbrew install --cask android-platform-tools
  • gnirehtetbrew install gnirehtet
  • Android device with USB debugging enabled

Installation

Quick Start

# Install dependencies
brew install --cask android-platform-tools
brew install gnirehtet

# Clone and build
git clone https://github.com/YOUR_USERNAME/GNirl.git
cd GNirl
./build.sh

# Open the app
open GNirl.app

From Source

swift build -c release
cp .build/release/GNirl GNirl.app/Contents/MacOS/GNirl
open GNirl.app

Usage

  1. Plug in your Android via USB (USB debugging must be enabled)
  2. Open GNirl from the menu bar
  3. Click your device from the dropdown list
  4. Done — the icon turns green and your phone has internet through your Mac

The first time you connect, GNirl automatically installs the gnirehtet APK on your device.

Menu Bar

Icon Meaning
Green icon Connected and working
Red icon Dropped/error — will auto-reconnect
Orange icon Connecting
Gray icon Idle, waiting for device

Log Window

Click Open Log Window to see live gnirehtet output. Use Copy All to grab the full log, or Clear to reset it.

Important: Stop / uninstall the VPN when you’re done

gnirehtet sets up a VPN/tunnel on your Android. If you unplug the phone (or quit GNirl) without stopping the tunnel, your phone can get stuck with the VPN active and lose Wi‑Fi/mobile data.

When you’re finished:

  1. In GNirl, disconnect/stop the current device so the VPN is torn down (go back to Idle / ensure the device shows as disconnected).
  2. Only then unplug the USB cable.

If your phone gets stuck:

  • Reconnect the phone to USB and use GNirl to restore/stop the tunnel, or restart the phone’s network (toggle airplane mode / reboot) to clear the stale VPN state.

Custom Status Icons

Drop PNG files into GNirl.app/Contents/Resources/ with these names:

File Shown when
status_connected.png Connected
status_connecting.png Connecting
status_error.png Dropped/error
status_idle.png Idle/disconnected

Icons are automatically scaled to 20pt for the menu bar. Any resolution works.

Custom App Icon

Convert your PNG to .icns and place it at:

GNirl.app/Contents/Resources/AppIcon.icns

Or use the included conversion script:

./scripts/make-icon.sh your-image.png

How It Works

GNirl is a thin Swift supervisor around gnirehtet:

  1. ADBWatcher polls adb devices -l every 3 seconds to detect connected Android devices
  2. GnirehtetService launches gnirehtet run as a child process and monitors it:
    • Health check every 5 seconds (process alive + device still connected)
    • ADB keepalive every 10 seconds (prevents USB idle sleep)
    • Exponential backoff reconnect (2s → 4s → 8s → 30s max)
    • IOPMAssertion to prevent system sleep while connected
    • Graceful SIGINT shutdown on disconnect

Troubleshooting

Device not showing in menu bar

  • Make sure USB debugging is enabled on your phone
  • Check adb devices in Terminal — if it shows unauthorized, tap "Allow" on the phone's prompt
  • Try a different USB cable (some are charge-only, no data)
  • On the phone, set USB mode to File Transfer or Charging (not "USB tethering" — that's the opposite direction)

Connection drops every few seconds

  • The old Python script issue is gone — GNirl's health check and keepalive prevent this
  • If it still happens, check the log window for gnirehtet errors
  • Try gnirehtet reinstall <serial> from the menu bar to refresh the APK

gnirehtet "Fail to deregister TCP stream" warnings

These are harmless gnirehtet noise. The Rust TCP stack spams them on every connection close. Traffic flows normally.

App won't launch (unidentified developer)

Right-click GNirl.appOpen → click Open in the dialog. This is a one-time macOS Gatekeeper bypass for ad-hoc signed apps.

Credits

  • gnirehtet by Genymobile — the reverse tethering engine
  • Built with Swift and SwiftUI

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages