crosspoint-reader/docs/companion-app-deep-link-API.md
2026-01-25 13:43:04 -05:00

8.7 KiB

CrossPoint Companion Deep Link API

This document describes the deep link functionality that allows the CrossPoint Companion Android app to be launched from QR codes displayed on CrossPoint e-reader devices.

Overview

The CrossPoint firmware can generate QR codes containing deep link URLs. When scanned with a mobile device, these URLs launch the companion app directly to a specific tab and optionally auto-connect to the device.

URL Scheme

crosspoint://<path>?<query_parameters>

Components

Component Description
crosspoint:// Custom URL scheme registered by the app
<path> Target tab in the app (see Path Mapping)
<query_parameters> Optional device connection parameters

Path Mapping

The URL path determines which tab the app navigates to:

Path App Tab Description
files Device File browser for device storage
library Library Local book library
lists Lists Reading lists management
settings Settings App settings

Note: Unknown paths default to the Library tab.

Query Parameters

Query parameters provide device connection information for automatic connection:

Parameter Type Default Description
host string (required for auto-connect) IP address or hostname of the device
port integer 80 HTTP API port
wsPort integer 81 WebSocket port for file uploads

URL Examples

Basic Navigation (No Auto-Connect)

Navigate to a specific tab without connecting to a device:

crosspoint://files
crosspoint://library
crosspoint://lists
crosspoint://settings

Auto-Connect to Device

Navigate to Device tab and auto-connect:

crosspoint://files?host=192.168.1.100
crosspoint://files?host=192.168.1.100&port=80&wsPort=81

Custom Ports

Connect to a device with non-default ports:

crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081

Hostname Instead of IP

crosspoint://files?host=crosspoint.local&port=80&wsPort=81

Firmware Implementation

QR Code Generation

The CrossPoint firmware should generate QR codes containing the deep link URL. Example format:

crosspoint://files?host=<device_ip>&port=<http_port>&wsPort=<ws_port>

Where:

  • <device_ip> is the device's current IP address (e.g., from WiFi connection)
  • <http_port> is the HTTP API port (default: 80)
  • <ws_port> is the WebSocket port (default: 81)

Example Firmware Code (C++)

String generateDeepLinkUrl(const char* path = "files") {
    String url = "crosspoint://";
    url += path;
    url += "?host=";
    url += WiFi.localIP().toString();
    url += "&port=";
    url += String(HTTP_PORT);  // e.g., 80
    url += "&wsPort=";
    url += String(WS_PORT);    // e.g., 81
    return url;
}

// Generate QR code with:
// String url = generateDeepLinkUrl("files");
// displayQRCode(url);

App Behavior

Launch Scenarios

1. App Not Running

When the app is launched via deep link:

  1. App starts and parses the deep link URL
  2. Navigates to the target tab
  3. If device connection info is present and target is "files":
    • Checks for existing device with matching IP
    • If found: uses existing device (preserving user's custom name)
    • If not found: creates temporary connection
    • Attempts to connect automatically

2. App Already Running

When a deep link is received while the app is open:

  1. onNewIntent receives the new URL
  2. Navigates to the target tab
  3. Handles device connection (same as above)

Device Matching Logic

When connecting via deep link:

1. Look up device by IP address in database
2. If device exists:
   a. Check if ports match
   b. If ports differ, update the stored device with new ports
   c. Connect using the existing device (preserves custom name)
3. If device doesn't exist:
   a. Create temporary Device object (not saved to database)
   b. Connect using temporary device
   c. Display as "CrossPoint (<ip>)"

Error Handling

Scenario Behavior
Malformed URL App opens to Library tab (default)
Unknown path App opens to Library tab with warning logged
Invalid host format Navigation succeeds, no auto-connect
Invalid port values Default ports used (80, 81)
Connection failure Error message displayed, user can retry
Device unreachable Error message with device IP shown

Android Implementation Details

Intent Filter (AndroidManifest.xml)

<intent-filter>
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="crosspoint" />
</intent-filter>

Key Classes

Class Purpose
DeepLinkParser Parses URI into DeepLinkData
DeepLinkData Data class holding parsed deep link info
DeviceConnectionInfo Data class for host/port/wsPort
MainActivity Handles incoming intents
CrossPointApp Routes navigation based on deep link
DeviceBrowserViewModel Handles connectFromDeepLink()

Data Flow

QR Code Scan
    │
    ▼
Android Intent (ACTION_VIEW)
    │
    ▼
MainActivity.onCreate() / onNewIntent()
    │
    ▼
DeepLinkParser.parse(uri)
    │
    ▼
DeepLinkData { targetTab, deviceConnection? }
    │
    ▼
CrossPointApp (LaunchedEffect)
    │
    ├─► Navigate to targetTab
    │
    └─► If targetTab == Device && deviceConnection != null
            │
            ▼
        DeviceBrowserScreen
            │
            ▼
        DeviceBrowserViewModel.connectFromDeepLink()
            │
            ├─► Check existing device by IP
            ├─► Update ports if needed
            └─► Connect and load files

Validation Rules

Host Validation

Valid hosts:

  • IPv4 addresses: 192.168.1.100, 10.0.0.1
  • Hostnames: crosspoint.local, my-device

Invalid hosts (rejected):

  • Empty strings
  • Malformed IPs: 192.168.1.256, 192.168.1
  • IPs with invalid octets

Port Validation

  • Valid range: 1-65535
  • Out-of-range values default to 80 (HTTP) or 81 (WebSocket)
  • Non-numeric values default to standard ports

Testing

Manual Testing with ADB

Test deep links without a QR code using ADB:

# Basic navigation
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files"
adb shell am start -a android.intent.action.VIEW -d "crosspoint://library"

# With device connection
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100"
adb shell am start -a android.intent.action.VIEW -d "crosspoint://files?host=192.168.1.100&port=80&wsPort=81"

# Test while app is running (onNewIntent)
adb shell am start -a android.intent.action.VIEW -d "crosspoint://settings"

Test Cases

  1. Valid deep link with connection info

    • URL: crosspoint://files?host=192.168.1.100&port=80&wsPort=81
    • Expected: Opens Device tab, auto-connects to device
  2. Valid deep link without connection info

    • URL: crosspoint://files
    • Expected: Opens Device tab, shows device selection
  3. Unknown path

    • URL: crosspoint://unknown
    • Expected: Opens Library tab (default)
  4. Missing host parameter

    • URL: crosspoint://files?port=80
    • Expected: Opens Device tab, no auto-connect
  5. Invalid host format

    • URL: crosspoint://files?host=invalid..host
    • Expected: Opens Device tab, no auto-connect
  6. Device already exists in database

    • Precondition: Device with IP 192.168.1.100 saved as "My Reader"
    • URL: crosspoint://files?host=192.168.1.100
    • Expected: Connects using "My Reader" name
  7. Existing device with different ports

    • Precondition: Device saved with port=80, wsPort=81
    • URL: crosspoint://files?host=192.168.1.100&port=8080&wsPort=8081
    • Expected: Updates device ports, then connects

Security Considerations

  1. Local Network Only: Deep links should only contain local network addresses. The app does not validate this, but firmware should only generate URLs with local IPs.

  2. No Authentication: The deep link does not include authentication. Device security relies on network-level access control.

  3. Temporary Devices: Devices created from deep links (when no matching device exists) are not persisted, preventing automatic accumulation of device entries.

  4. No Sensitive Data: Deep link URLs should not contain sensitive information as QR codes can be photographed.

Changelog

Version Changes
1.0.0 Initial deep link support with crosspoint:// scheme