cswork / libraryOpen practice workspace

Articles

Android App Links Interview Questions: Verification, Back Stacks, and Login Redirects

Prepare for Android App Links interviews with a verification fixture, adb checks, cold and warm Back-stack matrix, secure login redirects, and fallback tests.

An Android App Link can fail in two independent places. The operating system may never verify that a domain belongs to your app, so a tap opens the browser. Or verification may succeed and the app may open—then lose the intended destination, show the wrong screen after login, or make Back behave strangely. Interview answers that say only “add an intent filter and assetlinks.json” miss that second half.

This guide uses an original fixture: https://links.example.com/orders/42 should open order 42 in a signed-in app, preserve that destination through login for a signed-out user, and have a deliberate Back path. It is not a claim about a particular employer's mobile interview. Evidence boundary: platform verification and Navigation behavior below come from Android's documentation; the sample host, route, state table, and security checks are editorial exercises. Test on the Android versions and navigation stack you actually support.

State the two contracts before changing code

The first contract is domain association: the app declares an eligible HTTPS URL in its manifest, and the domain publishes a Digital Asset Links statement associating that host with the app's package name and signing certificate. Android's verification guide describes this handshake. If it fails, your in-app route handler can be perfect and still never receive the tap as an automatically verified App Link.

The second contract is navigation: once the app receives the URI, it parses a permitted route, finds order 42, resolves authentication, and constructs a back stack appropriate to the entry point. An OS “verified” status says nothing about the existence of order 42, whether the user may read it, or whether Back returns to the right place. Treat these as separate tests with separate owners: web/domain and release-signing configuration on one side; app route and state handling on the other.

Before proposing a fix, ask what the interviewer observed. Did the link open a browser or chooser? Did it open the correct app but wrong activity? Did it reach login and then home instead of the order? Did Back unexpectedly exit? Different symptoms point to different boundaries. Also ask whether the test build uses the same signing certificate as production and whether the host in the tapped URL exactly matches the declared and published host.

Build a minimal verification fixture

For a conventional activity-based App Links setup, a manifest filter can declare VIEW, DEFAULT, BROWSABLE, HTTPS, the intended host, and android:autoVerify="true". The exact activity and route handling are application-specific:

<intent-filter android:autoVerify="true">
    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.DEFAULT" />
    <category android:name="android.intent.category.BROWSABLE" />
    <data android:scheme="https" android:host="links.example.com" />
</intent-filter>

The domain then serves https://links.example.com/.well-known/assetlinks.json over HTTPS with the app's package and SHA-256 signing fingerprint. A conceptual statement is:

[{"relation":["delegate_permission/common.handle_all_urls"],
  "target":{"namespace":"android_app","package_name":"com.example.orders",
            "sha256_cert_fingerprints":["AA:BB:...:FF"]}}]

That abbreviated fingerprint is a placeholder, not a deployable value. Android's troubleshooting guidance emphasizes the accessible association file, correct package name, and certificate fingerprint. A common production trap is using a local debug keystore fingerprint while the distributed app is signed through Play App Signing. Check the certificate that signed the installed artifact, not the certificate you happen to have in a local build script. Do not assume a redirect from www to a bare host or a login-protected association file will work; serve the statement at each declared host's required path according to the platform rules.

Be precise about host and path matching. The example filter handles URLs on the host; application routing must still reject unsupported paths such as /admin or malformed order IDs. If you add multiple hosts or complex filters, verification behavior can vary by Android version. The official verification guide documents differences around multi-host verification and user-selected defaults. Do not diagnose a single screenshot without the device version, package, installed signature, and domain state.

Probe the device instead of guessing

On a controlled test device, reset the app-link state and request verification according to the official manual verification steps, then inspect the result. For the appropriate Android version, the documented pm commands include:

adb shell pm set-app-links --package com.example.orders 0 all
adb shell pm verify-app-links --re-verify com.example.orders
adb shell pm get-app-links com.example.orders

Verification is asynchronous; inspect after the system has had time to process it. These commands do not replace an end-to-end tap test. Use a real HTTPS link from a browser, message, or test harness; inspect the intent received by the activity and the final screen. A successful association file fetch does not guarantee the installed app's signature matches it. Conversely, an app opening a URL because the user selected it manually does not prove automatic domain verification succeeded.

Use a small diagnostic table during an interview:

ObservationBoundary to inspect firstDiscriminating check
Browser opensManifest/domain verification or user settingpm get-app-links, host, fingerprint, assetlinks.json
App opens wrong screenURI parsing and route dispatchLog sanitized URI path and matched route
Order opens only while signed inDeferred navigation/auth statePreserve a validated order route through login
Back exits or loops unexpectedlyTask/back-stack constructionTest entry context and intent flags

Avoid logging access tokens, full private query strings, or personally identifying order data just to debug routing. Capture the scheme, host, route type, and a non-sensitive correlation ID.

Back and Up depend on entry context

Android's Navigation deep-link documentation explains that explicit and implicit deep links can construct different task histories, and an implicit deep link's behavior depends on whether FLAG_ACTIVITY_NEW_TASK is present. In one case, a synthetic stack includes start destinations; in another, Back can return to the app that launched the link while Up navigates within your app. The navigation principles further distinguish Back and Up across tasks. Therefore, “Back always returns to home” is not a safe interview answer.

Write a desired behavior for each entry point, then test it. For a cold app start from a browser, open order 42 and decide whether Back returns to browser or to an in-app parent under the navigation architecture and flags in use. For an existing app task, tap the same link and check whether prior in-app history is replaced or preserved. For a notification or an explicit PendingIntent deep link, test the constructed parent stack separately. Do not let an accidental singleTop optimization change route handling: the Navigation docs note that a reused activity may require handleDeepLink() in onNewIntent() because it will not be processed automatically as a new activity launch would.

Entry stateExpected question, not a universal answerTest assertion
Cold, signed inWhich task owns the order destination?Exact order shown; Back path matches design
Warm, signed inDoes the existing activity receive a new intent?New URI handled once; old route not reused
Cold, signed outWhere is the order route held through login?Login succeeds, then order 42 appears once
Invalid or unverified hostDoes the browser remain the safe fallback?App does not claim unsupported URL

Preserve the destination through login without an open redirect

Android's conditional-navigation guidance uses a deep link to an authenticated destination as a common example: redirect to login, then resume the protected destination. The key interview decision is state ownership. Parse the incoming URI into a typed, allowed internal route such as OrderDetail(orderId=42). Store that route in navigation state or a controlled saved-state mechanism that survives the expected lifecycle transition. After authentication, re-check the user's authorization for order 42, navigate to it once, and consume the pending route. If login fails or the user cancels, follow an explicit safe fallback.

Do not keep an arbitrary next=https://... URL and launch it after login. That can become an open redirect or send a user to an attacker-controlled destination. Validate scheme and host before parsing, allow-list route shapes, and treat an order ID as untrusted input until the backend authorizes it. If the route contains sensitive query parameters, strip them from logs and avoid persisting them longer than needed. A link is navigation input, not authorization.

The login flow can also pollute the back stack if it remains beneath the order detail screen. Decide whether Back from the order should return to the app's parent screen, the previous app, or a stable post-login destination; then remove or replace the login destination as appropriate. A test should assert that Back never reveals a stale login screen after authentication and never replays the same pending link indefinitely.

A review-ready test matrix

Use at least two installed builds if debug and production signatures differ, and test the same HTTPS URI against both. Test Android versions representative of your support range, not just an emulator running the latest image. Test cold start, warm start, logged-out state, expired session, missing order, order belonging to another user, browser fallback, link from a notification, and duplicate taps. For each, record three outcomes: OS resolver, app destination, and Back/Up result. This makes failures localizable.

Do not mock away the domain handshake in every test. Unit-test the route parser and auth redirect separately, but include a device-level verification check that uses the actual manifest, signed artifact, and hosted association file. Then include an end-to-end tap that confirms the received URI reaches the intended screen. If verification changes after a release, compare the installed signature, host set, assetlinks response, and device app-link state before rewriting navigation code.

When discussing rollout, mention observability: count link opens by verified host and route type, failed route parsing, post-login resumes, and unauthorized order responses without storing sensitive URLs. A spike in browser fallbacks after a signing or domain change differs from a spike in login-loop events after an app release. That distinction turns an interview answer into an operational plan.

Sources and further reading