Skip to content
GitHubGet started

Platform setup

Flutter SDK

Make DecTog links open your app directly with iOS Universal Links and Android App Links, add custom schemes, and verify the association files DecTog serves for your account.

A hosted DecTog link looks like https://{username}.dectog.com/{slug}. For a tap to open your installed app without a browser round trip, iOS needs Universal Links and Android needs App Links. Both rely on a file served from your link domain, and DecTog serves those files for you from the app records in the dashboard.

Register the app first in Dashboard → Apps (see Apps). The fields that matter here:

Field Validation
iOS bundle ID Looks like com.company.app
Apple Team ID 10 uppercase letters or digits (Apple Developer → Membership)
Android package Looks like com.company.app
SHA-256 fingerprints One per line, 32 colon-separated hex pairs, stored uppercase. Include the Play App Signing key, not only the debug key.
iOS / Android app scheme Letters, digits and + - . only, without ://. http, https and javascript are rejected.

Both association files are built for the whole account: every app with the required identifiers appears in them.

  1. Save the bundle ID and the Team ID in the app record. The file goes live once both are saved.

  2. Add the Associated Domains entitlement. Create ios/Runner/Runner.entitlements if it does not exist, and make sure every build configuration and flavor uses an entitlements file that carries it.

    ios/Runner/Runner.entitlements
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>com.apple.developer.associated-domains</key>
    <array>
    <string>applinks:{username}.dectog.com</string>
    </array>
    </dict>
    </plist>

    Replace {username} with your DecTog username (self-hosted: applinks:{username}.{root}). Use the explicit host, not a wildcard: for applinks:*.dectog.com iOS fetches the association file from the parent domain, and the apex serves none (it answers 400 because no username can be read from the host), so the wildcard form never verifies. Enable the Associated Domains capability on the App ID in your Apple Developer account. With a custom link domain, add applinks:go.yourbrand.com as a second entry: it serves the same file.

  3. Rebuild and reinstall the app. iOS downloads and verifies the association file at install or update time, so an already-installed app only picks it up after a reinstall or an update.

  4. Test by tapping a real link from Messages or Notes. Typing the URL into Safari’s address bar does not open the app.

No Info.plist or AppDelegate change is needed. Links arrive through the app_links plugin, which already handles Universal Links and custom schemes.

What DecTog serves. https://{username}.dectog.com/.well-known/apple-app-site-association is built from every app in the account that has both a bundle ID and a Team ID:

{
"applinks": {
"apps": [],
"details": [
{
"appIDs": ["ABCDE12345.com.example.myapp"],
"components": [{ "/": "/*" }]
}
]
},
"webcredentials": {
"apps": ["ABCDE12345.com.example.myapp"]
}
}

Every path on the domain is claimed (/*). The webcredentials block lists the same app IDs, so password AutoFill can also associate the domain with your app. When no app in the account has both identifiers, the file answers 404 {"error":{"code":"not_found","message":"Configuration not found"}}.

A custom scheme is optional. Save it in the app record (myapp, without ://) and register it on both platforms:

ios/Runner/Info.plist
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>myapp</string>
</array>
</dict>
</array>
android/app/src/main/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="myapp" />
</intent-filter>

How DecTog uses it:

  • A link without a deep-link path opens myapp://{username}/{slug}?dtg_l={username}/{slug}. A link with a deep-link path opens myapp://{path}?dtg_l={username}/{slug}, so the path’s first segment becomes the URI authority. The dtg_l tag (after dtg_click when present) is how the SDK knows which link it was. Universal Links and App Links always deliver the https://{username}.dectog.com/{slug} form instead.
  • On iOS a scheme only opens from a direct user tap, such as the “Open in app” buttons on DecTog’s pages. A server redirect to a scheme never launches an iOS app; Universal Links are the only automatic mechanism.
  • On Android the scheme, together with the package, enables the intent:// bounce described above.

Each platform section of the app editor has a Verify button next to the file path. It fetches the saved association file for the whole account (through the ?u={username} form on the dashboard host) and shows a one-line summary:

File Messages
Universal Links “✓ N app ID(s) served” or “✕ No app IDs configured”
App Links “N package(s), SHA-256 fingerprints present”, “N package(s), MISSING fingerprints” or “No packages configured”

Both report Endpoint replied <status>: … or Fetch failed: … when the fetch fails. The check reads what is saved, not what you typed into the form, so save first.

The association files resolve the account from the request host ({username}.{root}) or from an explicit ?u={username} query, which always wins. Two consequences:

  • In path mode (a root domain that starts with localhost, the local development default) the host carries no username, so the files are only reachable as http://localhost:8787/.well-known/apple-app-site-association?u={username} and …/assetlinks.json?u={username}. Without ?u= the response is 400 {"error":{"code":"invalid_request","message":"Subdomain not found in host"}}.
  • Universal Links and App Links require a real HTTPS domain that the OS can fetch. Local hosts such as http://10.0.2.2 or https://localhost never pass verification; on Android 12 and newer they open the app only from explicit intents (adb) or after the user enables the link in system settings. Use custom schemes and adb or simctl during development, as described in Testing.

Every response carries x-hostname and x-subdomain headers naming the host and the resolved username. Self-hosted deployments serve the files from their own root domain; see Well-known, SEO and routing.