Skip to main content
This guide covers setup and troubleshooting for running the Flutter mobile app on Android emulators and physical devices, especially when the app must connect to the local Hiro League gateway over the network.

Quick rules

  • Emulator to local service: Use 10.0.2.2 (Android Studio) or 10.0.3.2 (Genymotion)
  • Physical phone to local service: Use the PC’s real LAN IP, for example 10.0.1.54
  • Never from a phone: Do not use localhost or virtual adapter IPs like 172.22.x.x
  • Gateway URL for phone: Use ws://<LAN_IP>:8765
  • Gateway binding: The gateway must listen on 0.0.0.0:8765 or on the LAN IP — not only 127.0.0.1:8765

Running the Flutter app on a physical Android device without USB

Use ADB wireless debugging.

Phone setup

  1. Enable Developer options.
  2. Open Developer options.
  3. Turn on Wireless debugging.
  4. Open Wireless debugging and choose Pair device with pairing code.
  5. Keep that screen open so the phone shows the IP, pairing port, and pairing code.

PC setup

Run:
adb pair <phone-ip>:<pairing-port>
Enter the pairing code shown on the phone. Then connect to the device debug port:
adb connect <phone-ip>:<debug-port>
adb devices
If the device appears in adb devices, run the app:
cd d:\projects\hiroleague\device_apps
flutter devices
flutter run

If wireless pairing does not work

  • Make sure the phone and PC are on the same Wi-Fi network.
  • Re-run adb connect.
  • Accept any RSA or debug prompt on the phone.
  • Restart ADB:
adb kill-server
adb start-server

Android 10 or older

Fully cable-free first-time pairing is usually not supported. A USB setup step may be required first.

Running on the Android emulator

If the app is running on the Android emulator, ADB pairing is usually not needed. The emulator is already available to Flutter. Use:
flutter devices
flutter run

Emulator host IP rule

If the app must access a backend or service running on the same PC:
  • Android Studio emulator: use 10.0.2.2
  • Genymotion: use 10.0.3.2
Example:
http://10.0.2.2:5000
For the Hiro League gateway on the emulator:
ws://10.0.2.2:8765

Finding the correct PC IP for a physical phone

To see the machine’s IPv4 addresses:
ipconfig
Or:
(Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -notlike '127.*' -and $_.PrefixOrigin -ne 'WellKnown'}).IPAddress

How to choose the correct IP

Use the IPv4 address from the active LAN adapter that your phone can reach. Example from a typical setup:
  • 10.0.1.54 is a correct machine IP for phone access (LAN adapter with a real default gateway).
  • 172.22.192.1 is a Hyper-V virtual switch adapter and should not be used for the phone.

Rule of thumb

  • Prefer the adapter with a real default gateway.
  • Ignore loopback 127.0.0.1.
  • Ignore virtual adapters unless that network is intentionally being used.

Verifying whether port 8765 is listening

Check whether anything is listening on port 8765:
Get-NetTCPConnection -LocalPort 8765 -State Listen
See exact bind addresses and process ID:
netstat -ano | findstr :8765

Healthy result for phone access

You want to see one of these:
  • 0.0.0.0:8765
  • <LAN_IP>:8765

Bad result

If you only see:
  • 127.0.0.1:8765
  • ::1:8765
then the gateway is bound only to localhost and phones cannot connect.

Testing local reachability from the PC

Test whether the PC can reach its own service on the LAN IP:
Test-NetConnection -ComputerName 10.0.1.54 -Port 8765

Interpretation

  • TcpTestSucceeded : True means the service is reachable at that address and port from the PC.
  • TcpTestSucceeded : False means either:
    • the app is not listening correctly
    • the port is blocked
    • the service is bound only to localhost

Hiro League Gateway bind troubleshooting

The most common failure is that hirogateway is configured to bind to localhost:8765. That allows desktop local access but blocks phones.

Symptom

netstat shows:
127.0.0.1:8765 LISTENING
and the phone cannot connect.

Correct state

After fixing the bind host, netstat shows:
0.0.0.0:8765 LISTENING

How to inspect current gateway instances

From the gateway package directory:
uv run hirogateway instance list
uv run hirogateway instance show default
This reveals the configured bind host and port for the instance.

How to fix the gateway host

Stop the gateway if needed:
uv run hirogateway stop --instance default
Update the registry host to 0.0.0.0:
$reg = "$env:LOCALAPPDATA\hirogateway\registry.json"
$j = Get-Content $reg -Raw | ConvertFrom-Json
$j.instances.default.host = "0.0.0.0"
$j | ConvertTo-Json -Depth 8 | Set-Content $reg
Start the gateway again:
uv run hirogateway start --instance default --foreground
Verify:
netstat -ano | findstr :8765

Important file

The gateway instance registry lives at:
%LOCALAPPDATA%\hirogateway\registry.json
A typical registry looks like:
{
  "default_instance": "default",
  "instances": {
    "default": {
      "name": "default",
      "path": "C:\\Users\\augr\\AppData\\Local\\hirogateway\\instances\\default",
      "host": "0.0.0.0",
      "port": 8765
    }
  }
}
The host should be 0.0.0.0 for phone access.

Checking hirocli workspace defaults

For a local setup, no changes are needed. hirocli runs on the same machine as the gateway, so its default workspace config can still use:
ws://localhost:8765
That is valid for the desktop process itself.

Practical rule

  • Desktop hirocli: ws://localhost:8765
  • Physical phone app: ws://<LAN_IP>:8765
Only change hirocli workspace gateway_url if the gateway is moved to a different machine.

Windows firewall

If the gateway is bound correctly but the phone still cannot connect, Windows firewall may be blocking the port.

Test from the PC

Test-NetConnection -ComputerName 10.0.1.54 -Port 8765
If this fails, firewall or bind settings are likely still wrong.

Add a firewall rule

Run PowerShell as Administrator and allow inbound TCP on 8765:
New-NetFirewallRule -DisplayName "Hiro League Gateway 8765" -Direction Inbound -Protocol TCP -LocalPort 8765 -Action Allow

If the firewall command says access denied

PowerShell was not running as Administrator.

Checking whether the phone is on a reachable network

The phone must be on a network that can route to the PC.

What to verify on the phone

Open Wi-Fi settings and inspect the connected network:
  • Confirm the phone is on Wi-Fi, not mobile data.
  • Confirm it is not on a guest network.
  • Confirm VPN is off during debugging.
  • Confirm there is no AP isolation or client isolation.

Compare IP ranges

Example addresses from a working setup:
  • PC IP: 10.0.1.54
  • Phone IP: 10.0.6.98
Both are in the 10.x.x.x private space. They may not be on the same exact subnet, but if they can route through the same gateway, the connection will work. Router behavior matters.

If the phone reports “failed to open websocket connection”

That usually means:
  • the phone can reach the target IP enough to try opening a socket
  • but the connection is being blocked, refused, or rejected before the WebSocket session is established
At that point, focus on:
  • gateway bind host
  • firewall
  • Android cleartext policy
  • router isolation

Android app policy: cleartext traffic (ws://)

Android may block insecure cleartext traffic unless the app manifest allows it. This matters when using:
ws://10.0.1.54:8765
instead of secure wss://.

Required manifest settings

The app manifest must include:
  • android:usesCleartextTraffic="true"
  • android.permission.INTERNET
File: device_apps/android/app/src/main/AndroidManifest.xml

Current required shape

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET"/>
    <application
        android:label="hiro_app"
        android:name="${applicationName}"
        android:icon="@mipmap/ic_launcher"
        android:usesCleartextTraffic="true">

After changing the manifest

Rebuild the app:
cd d:\projects\hiroleague\device_apps
flutter clean
flutter pub get
flutter run

Correct URLs to use

Use the right URL depending on the environment.

Physical phone to local gateway

ws://10.0.1.54:8765

Android emulator to local gateway

ws://10.0.2.2:8765

Desktop local process to local gateway

ws://localhost:8765

Do not use

  • ws://localhost:8765 from the phone
  • ws://172.22.192.1:8765 from the phone (unless intentional)

Full troubleshooting workflow

Use this sequence whenever device connection fails.
  1. Confirm the app is using the correct URL for the environment.
  2. If using an emulator, use 10.0.2.2.
  3. If using a phone, find the correct PC LAN IP with ipconfig.
  4. Verify the service is listening with:
netstat -ano | findstr :8765
  1. If you only see 127.0.0.1:8765, fix the gateway bind host to 0.0.0.0.
  2. Confirm local reachability from the PC:
Test-NetConnection -ComputerName 10.0.1.54 -Port 8765
  1. If needed, add a Windows firewall rule.
  2. Verify the phone is on Wi-Fi, not guest mode, and not using VPN.
  3. Ensure Android manifest allows cleartext traffic for ws://.
  4. Rebuild the app and test again.
  5. If it still fails, inspect Flutter logs and gateway logs during a connection attempt.

Useful commands reference

Find PC IP

ipconfig
(Get-NetIPAddress -AddressFamily IPv4 | Where-Object {$_.IPAddress -notlike '127.*' -and $_.PrefixOrigin -ne 'WellKnown'}).IPAddress

Check port listener

Get-NetTCPConnection -LocalPort 8765 -State Listen
netstat -ano | findstr :8765

Test TCP connectivity

Test-NetConnection -ComputerName 10.0.1.54 -Port 8765

Open firewall port

New-NetFirewallRule -DisplayName "Hiro League Gateway 8765" -Direction Inbound -Protocol TCP -LocalPort 8765 -Action Allow

Inspect gateway instance config

uv run hirogateway instance list
uv run hirogateway instance show default

Restart ADB

adb kill-server
adb start-server

Connect to a wireless Android device

adb pair <phone-ip>:<pairing-port>
adb connect <phone-ip>:<debug-port>
adb devices

Run Flutter app

cd d:\projects\hiroleague\device_apps
flutter run