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:
- App starts and parses the deep link URL
- Navigates to the target tab
- 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:
onNewIntentreceives the new URL- Navigates to the target tab
- 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
-
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
- URL:
-
Valid deep link without connection info
- URL:
crosspoint://files - Expected: Opens Device tab, shows device selection
- URL:
-
Unknown path
- URL:
crosspoint://unknown - Expected: Opens Library tab (default)
- URL:
-
Missing host parameter
- URL:
crosspoint://files?port=80 - Expected: Opens Device tab, no auto-connect
- URL:
-
Invalid host format
- URL:
crosspoint://files?host=invalid..host - Expected: Opens Device tab, no auto-connect
- URL:
-
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
-
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
-
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.
-
No Authentication: The deep link does not include authentication. Device security relies on network-level access control.
-
Temporary Devices: Devices created from deep links (when no matching device exists) are not persisted, preventing automatic accumulation of device entries.
-
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 |