Deep-Links
The app registers one or more URL schemes (see CFBundleURLTypes in
AppInfo.plist). The primary scheme for documentation and QR templates is
sharx://. The full list of registered schemes, including any compatibility
aliases, is shown in the app under Settings → Supported URL schemes
(tap-to-copy templates) and is defined in DeepLinkParser.supportedSchemes.
Handler: RootTabView.handleDeepLink(_:). Parser: DeepLinkParser.
Examples below use
sharx://. Any scheme registered in the list above is treated the same: the parser resolves host, path, and query; only the path patterns below are recognized.
URL schemes (header)
| Scheme | Role in docs & QR |
|---|---|
sharx:// |
Primary — used in this documentation and in-app QR generation. |
Other registered schemes in the app use identical deep-link paths and
query syntax; only the sharx:// prefix is used here for clarity.
Supported link types (overview)
| Purpose | URL header (scheme + path) | Query or path body | Details |
|---|---|---|---|
| Add subscription | sharx:// + path add |
Query string: url (required), name (optional) |
Add a subscription |
| Import routing profile | sharx:// + path routing/add/ |
Path after add/: Base64 of RoutingProfile JSON (see routing-profile-schema.md) |
Import a routing profile |
All other host/path combinations are ignored (no error shown).
Add a subscription
Header, body, and examples (separated)
| Content | |
|---|---|
| Header | sharx://add — the path component is the literal add (add-subscription action). |
| Body (query string) | url=<subscription_URL>&name=<optional_name>. The subscription URL is required and must be a valid URL after percent-decoding. name pre-fills the add form. |
Full URL shape
sharx://add?url=<subscription_URL>&name=<name>
| Query parameter | Required | Description |
|---|---|---|
url |
yes | Subscription source URL. Percent-encode the value so :/?&# in the target URL do not break the deep-link. |
name |
no | Pre-fills the subscription name (%20 for spaces, UTF-8 percent-encoding supported). |
Behaviour
DeepLinkParser.parseAddSubscriptionreads query items case-insensitively (URL,Url,urlall work).- A modal Add subscription sheet (
AddSubscriptionForm) opens with the URL and name prefilled. - The user can edit and confirm; then the regular subscription pipeline runs (see subscription-http.md).
Example URLs (query body only; header + body combined)
| Use case | Full URL (copy-paste) |
|---|---|
| URL only | sharx://add?url=https%3A%2F%2Fexample.com%2Fsub%2Fabc |
| URL + name | sharx://add?url=https%3A%2F%2Fexample.com%2Fsub%2Fabc&name=Work%20VPN |
| Non-ASCII name (UTF-8) | sharx://add?url=https%3A%2F%2Fexample.com%2Fsub%2Fabc&name=%D0%A0%D0%B0%D0%B1%D0%BE%D1%87%D0%B8%D0%B9 |
Import a routing profile
Header, body, and example URL
| Content | |
|---|---|
| Header | sharx://routing/add/ — fixed prefix. |
| Body | Everything after routing/add/ is the payload (no leading ?). The payload is Base64 (URL-safe - / _ allowed) encoding a JSON RoutingProfile (schema: routing-profile-schema.md). Decoded by RoutingAnnounceDecoder. |
Full URL shape
sharx://routing/add/<payload>
Limits
| Check | Limit | Error key |
|---|---|---|
| Valid Base64 | — | routing.error.base64 |
| Valid JSON | — | routing.error.json |
| Decoded payload size | 512 KiB | routing.error.large |
Behaviour
DeepLinkParser.parseRoutingAddPayloadtakes the substring afterrouting/add/and decodes it.- On success, a confirmation sheet appears (
RoutingImportConfirmView). - On confirm, the profile is saved via
RoutingProfileStore.upsertin the App Group (group.com.sharxapps.connect); the tunnel extension can read it. - Re-importing the same
idoverwrites the previous profile (by design).
Example URL (payload body)
sharx://routing/add/eyJpZCI6InJvdXRpbmctMDEiLCJuYW1lIjoiQmFzZSIsInJ1bGVzIjpbXX0=
(Base64 decodes to {"id":"routing-01","name":"Base","rules":[]}.)
Where links come from
| Source | Mechanism | Notes |
|---|---|---|
System onOpenURL |
WindowGroup { … }.onOpenURL in RootTabView |
iOS / macOS hands off the URL from another app or Safari. |
| QR scanner | QRCodeScannerView → NotificationCenter.post(.sharxInternalDeepLinkOpen) |
QR opened inside the app. |
| Clipboard / other internal | NotificationCenter.post(.sharxInternalDeepLinkOpen) |
Any internal URL can be routed the same way. |
onOpenURL is not used when the link was obtained only inside the app (e.g.
QR scan) — the notification path covers that.
What deep-links do not do
- No VPN connect/disconnect over links. Use the in-app control or the system VPN UI; links cannot start or stop the tunnel.
- No direct add of a single server via
vless://,vmess://,trojan://,ss://,hysteria2://,socks://,wireguard://— add servers only via a subscription URL (sharx://add?url=…). - No auto-refresh of routing from a remote
sourceURL(autorouting/…style flows). Imports are one-shot.
Open an issue if you need a flow that is missing.
Legacy and unsupported URL patterns
The app only loads subscription bodies over HTTPS; the body is read as plaintext after TLS. Obfuscated URL paths for subscription delivery are not handled in the client.
Unknown paths and non-documented link styles are ignored.
See: subscription-http.md.