Skip to main content

Overview

APK Extractor automatically saves WiFi-connected devices to devices.json for quick reconnection. This eliminates the need to re-enter pairing codes and ports every time you want to connect. Saved device information includes:
  • IP address
  • Connection port
  • Device label (manufacturer + model)
  • Last connected timestamp
  • Unique device ID

devices.json Structure

The devices.json file stores an array of device objects in JSON format.

File Location

Same directory as server.js (defined in server.js:11):
const DEVICES_FILE = path.join(__dirname, 'devices.json');

JSON Format

Example devices.json file:
[
  {
    "id": "1709856234567",
    "label": "Samsung Galaxy S21",
    "ip": "192.168.1.42",
    "port": "37685",
    "lastConnected": "2026-03-07T14:30:45.123Z"
  },
  {
    "id": "1709856789012",
    "label": "Xiaomi Redmi Note 10",
    "ip": "192.168.1.58",
    "port": "41234",
    "lastConnected": "2026-03-06T09:15:22.456Z"
  }
]

Field Descriptions

FieldTypeDescription
idstringUnique identifier (timestamp in milliseconds)
labelstringDisplay name (brand + model or custom name)
ipstringDevice IP address on local network
portstringADB wireless connection port
lastConnectedstringISO 8601 timestamp of last connection
The file is created automatically when you connect the first WiFi device. If it doesn’t exist, functions return an empty array.

Automatic Device Saving

Devices are saved automatically when you successfully connect via WiFi.

On WiFi Connect

When you use /api/adb/connect (server.js:598), the device is automatically saved:
app.post('/api/adb/connect', async (req, res) => {
  const { ip, port, label } = req.body;
  // ... connection logic ...
  
  if (success) {
    const devices = loadSavedDevices();
    const existing = devices.find(d => d.ip === ip);
    if (existing) {
      // Update existing device
      existing.port = port;
      existing.lastConnected = new Date().toISOString();
      if (label) existing.label = label;
    } else {
      // Add new device
      let autoLabel = label || `${ip}:${port}`;
      try {
        const serial = `${ip}:${port}`;
        const props = await runAdb(
          `shell "getprop ro.product.manufacturer && getprop ro.product.model"`,
          serial, 5000
        );
        const ls = props.trim().split('\n').map(l => l.trim());
        if (ls[0] && ls[1] && ls[0] !== 'N/A') autoLabel = `${ls[0]} ${ls[1]}`;
      } catch { }
      devices.push({
        id: Date.now().toString(),
        label: autoLabel,
        ip,
        port,
        lastConnected: new Date().toISOString(),
      });
    }
    writeSavedDevices(devices);
  }
});

Auto-Update on Reconnect

When listing devices (server.js:240), if a wireless device’s IP matches a saved device, the record is automatically updated:
// Auto-update saved device if IP matches
if (ip) {
  try {
    const saved = loadSavedDevices();
    const existing = saved.find(d => d.ip === ip);
    if (existing) {
      existing.lastConnected = new Date().toISOString();
      if (label !== serial) existing.label = label;
      writeSavedDevices(saved);
    }
  } catch { }
}
WiFi ADB ports expire when you disable wireless debugging on the device. Saved ports may become invalid and require re-pairing.

Quick Reconnection

The saved devices feature enables one-click reconnection without entering pairing codes.

List Saved Devices

Retrieve all saved devices:
GET /api/saved-devices
Response:
{
  "devices": [
    {
      "id": "1709856234567",
      "label": "Samsung Galaxy S21",
      "ip": "192.168.1.42",
      "port": "37685",
      "lastConnected": "2026-03-07T14:30:45.123Z"
    }
  ]
}
Implementation (server.js:640):
app.get('/api/saved-devices', (req, res) => {
  res.json({ devices: loadSavedDevices() });
});

Reconnect to Saved Device

Simply use the saved IP and port with /api/adb/connect:
POST /api/adb/connect
Content-Type: application/json

{
  "ip": "192.168.1.42",
  "port": "37685"
}
If the port has expired, you’ll need to re-pair with the new port and code.

Managing Saved Devices

Add or Update Device

Manually add or update a device entry:
POST /api/saved-devices
Content-Type: application/json

{
  "label": "My Phone",
  "ip": "192.168.1.100",
  "port": "12345"
}
Implementation (server.js:644):
app.post('/api/saved-devices', (req, res) => {
  const { label, ip, port } = req.body;
  if (!ip || !port) return res.status(400).json({ error: 'IP y puerto son requeridos' });
  const devices = loadSavedDevices();
  const existing = devices.find(d => d.ip === ip && d.port === port);
  if (existing) {
    if (label) existing.label = label;
    existing.lastConnected = new Date().toISOString();
  } else {
    devices.push({
      id: Date.now().toString(),
      label: label || `${ip}:${port}`,
      ip,
      port,
      lastConnected: new Date().toISOString(),
    });
  }
  writeSavedDevices(devices);
  res.json({ ok: true });
});
If a device with the same IP and port already exists, only the label and timestamp are updated.

Delete Saved Device

Remove a device by its unique ID:
DELETE /api/saved-devices/:id
Example:
DELETE /api/saved-devices/1709856234567
Implementation (server.js:665):
app.delete('/api/saved-devices/:id', (req, res) => {
  const { id } = req.params;
  let devices = loadSavedDevices();
  devices = devices.filter(d => d.id !== id);
  writeSavedDevices(devices);
  res.json({ ok: true });
});

Updating Device Information

Port Changes

When wireless debugging restarts, the connection port changes. Update it:
POST /api/saved-devices
Content-Type: application/json

{
  "ip": "192.168.1.42",
  "port": "38192",  // New port
  "label": "Samsung Galaxy S21"
}
The API uses IP as the lookup key, so it updates the existing device’s port.

Custom Labels

You can override the auto-detected label with a custom name:
POST /api/saved-devices
Content-Type: application/json

{
  "ip": "192.168.1.42",
  "port": "37685",
  "label": "Work Phone"  // Custom label
}

CLI Saved Devices Management

The batch script provides a menu for managing saved devices (apk-downloader.bat:1068).

View Saved Devices

The script reads devices.json using PowerShell:
for /f "usebackq delims=" %%L in (`powershell -Command "$d=Get-Content '!DEV_FILE!' -Raw|ConvertFrom-Json;$i=0;foreach($dev in $d){$i++;Write-Output \"$i|$($dev.label)|$($dev.ip)|$($dev.port)|$($dev.id)\"}"`) do (
    set "SLINE=%%L"
    for /f "tokens=1-5 delims=|" %%a in ("!SLINE!") do (
        set /a SAVED_COUNT=%%a
        set "SAVED_LABEL_%%a=%%b"
        set "SAVED_IP_%%a=%%c"
        set "SAVED_PORT_%%a=%%d"
        set "SAVED_ID_%%a=%%e"
    )
)

Connect to Saved Device

Select a device and the script attempts connection (apk-downloader.bat:1123):
echo  Conectando a !SC_IP!:!SC_PORT!...
"%ADB_EXE%" connect !SC_IP!:!SC_PORT! 2>&1 | findstr /i "connected" >nul 2>&1
if %errorlevel%==0 (
    echo  [OK] Conectado a !SC_LABEL!
) else (
    echo  [!] No se pudo conectar. Los puertos pueden haber caducado.
)

Delete Saved Device

Removes a device from the JSON file using PowerShell (apk-downloader.bat:1186):
powershell -Command "$f='!DEV_FILE!';$d=Get-Content $f -Raw|ConvertFrom-Json;$d=$d|Where-Object{$_.id -ne '!DEL_ID!'};if($d -eq $null){$d=@()};ConvertTo-Json @($d) -Depth 5|Set-Content $f"

Loading and Writing Functions

Load Saved Devices

Reads devices.json with in-memory caching (server.js:50):
function loadSavedDevices() {
  if (_savedDevicesCache) return _savedDevicesCache;
  try {
    if (fs.existsSync(DEVICES_FILE)) {
      _savedDevicesCache = JSON.parse(fs.readFileSync(DEVICES_FILE, 'utf8'));
      return _savedDevicesCache;
    }
  } catch { }
  _savedDevicesCache = [];
  return _savedDevicesCache;
}
The cache (_savedDevicesCache) prevents reading the file on every API call. It’s updated when devices are written.

Write Saved Devices

Updates the file and cache (server.js:62):
function writeSavedDevices(devices) {
  _savedDevicesCache = devices;
  fs.writeFileSync(DEVICES_FILE, JSON.stringify(devices, null, 2), 'utf8');
}
The file is written with 2-space indentation for readability.

Port Expiration Handling

Critical: WiFi ADB ports expire when you:
  • Disable wireless debugging
  • Restart the device
  • Toggle airplane mode
  • Disconnect from WiFi network
When a saved port expires:
  1. Connection attempts will fail with timeout or “connection refused”
  2. You must re-enable wireless debugging on the device
  3. A new pairing code and ports are generated
  4. Re-pair using /api/adb/pair with the new code
  5. Connect using /api/adb/connect with the new port
  6. The saved device is automatically updated with the new port

CLI Re-pairing Flow

The batch script handles expired ports gracefully (apk-downloader.bat:1150):
if %errorlevel%==0 (
    echo  [OK] Conectado a !SC_LABEL!
else (
    echo  [!] No se pudo conectar. Los puertos pueden haber caducado.
    echo  ¿Deseas re-vincular este dispositivo? [S/N]
    set /p RELINK_CHOICE="  "
    if /i "!RELINK_CHOICE!"=="S" (
        set /p NEW_PAIR_PORT="  Nuevo puerto de vinculacion: "
        set /p NEW_CODE="  Codigo de vinculacion: "
        "%ADB_EXE%" pair !SC_IP!:!NEW_PAIR_PORT! !NEW_CODE!
        
        set /p NEW_CONN_PORT="  Nuevo puerto de conexion: "
        "%ADB_EXE%" connect !SC_IP!:!NEW_CONN_PORT!
        
        # Update port in devices.json
        powershell -Command "...$e.port='!NEW_CONN_PORT!';..."
    )
)

Best Practices

IP Address Stability

For reliable reconnection:
  • Assign static IP to your device in router settings (DHCP reservation)
  • Use static IP on the device’s WiFi settings
  • Avoid letting IP addresses change due to DHCP lease expiration

Regular Cleanup

Periodically remove devices you no longer use:
DELETE /api/saved-devices/{old-device-id}

Backup devices.json

The file is a simple JSON array - back it up to preserve your saved devices:
cp devices.json devices.backup.json

Troubleshooting

Device Not Saving

If devices aren’t being saved after connection:
  1. Check devices.json file permissions (must be writable)
  2. Verify the connection was successful (check response from /api/adb/connect)
  3. Look for errors in server logs

Connection Fails for Saved Device

Possible causes:
  • Port expired (re-pair required)
  • Device IP changed (update IP in saved devices)
  • Device disconnected from WiFi
  • Wireless debugging disabled on device

Duplicate Devices

The API uses IP + port as the uniqueness key. If you connect to the same device with different ports, you may have duplicates. Delete the old entry manually.

Invalid JSON Format

If you manually edit devices.json and break the JSON syntax:
  1. The file will fail to parse and return an empty array
  2. Fix the JSON syntax or delete the file
  3. The file will be recreated on the next device save

Build docs developers (and LLMs) love