Skip to content

Dispatch Android deep links via Intent URI#3902

Open
pepeladeira wants to merge 1 commit into
mainfrom
android-deeplink-intent-uri
Open

Dispatch Android deep links via Intent URI#3902
pepeladeira wants to merge 1 commit into
mainfrom
android-deeplink-intent-uri

Conversation

@pepeladeira
Copy link
Copy Markdown
Collaborator

@pepeladeira pepeladeira commented May 13, 2026

Summary by CodeRabbit

  • New Features
    • Improved Android deep linking: Deep links now intelligently route Android users directly to your installed app when available, using native Android intent URLs for a seamless app experience. If the app isn't installed, it automatically falls back to opening the link in the browser while preserving context parameters.

Review Change Stack

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 13, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dub Ready Ready Preview May 13, 2026 10:13pm

Request Review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

📝 Walkthrough

Walkthrough

This PR adds Android-specific deep-link navigation support by extracting Android package names from asset links metadata and using them to build intent:// URLs. When users on Android (excluding Firefox) tap action buttons, the app attempts native navigation via intent:// protocol with an HTTPS fallback.

Changes

Android Intent Deep-Link Navigation

Layer / File(s) Summary
Android package name extraction and wiring
apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/page.tsx
DeepLinkPreviewPage scans link.shortDomain.assetLinks for an android_app namespace entry and extracts its package_name, then passes the result to DeepLinkActionButtons as the new androidPackageName prop.
Android intent URL navigation implementation
apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx
DeepLinkActionButtons accepts androidPackageName and, when the platform is Android, the package name is present, and the user is not using Firefox, constructs and navigates to an intent:// URL with scheme, package, and HTTPS fallback; otherwise falls back to the existing HTTPS short-link behavior.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • dubinc/dub#3836: Both PRs modify the same deeplink action-buttons and page files to support the Android deep-link interstitial flow—main PR further extends DeepLinkActionButtons with an androidPackageName prop to build an intent:// fallback, building on the Android-specific platform/interstitial changes from that PR.

Suggested reviewers

  • devkiran
  • steven-tey

Poem

🐰 A rabbit hops through Android's terrain,
intent:// URLs now lead the way,
Package names extracted with care,
Firefox stays calm, with HTTPS to share,
Deep-links now native, hip-hop, hooray!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Dispatch Android deep links via Intent URI' accurately summarizes the main change: adding Android-specific deep-link navigation using Intent URI scheme.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch android-deeplink-intent-uri

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx

Parsing error: The keyword 'import' is reserved

apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/page.tsx

Parsing error: The keyword 'import' is reserved


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx (1)

32-51: 💤 Low value

Intent URL construction looks correct; one minor edge case to consider.

The intent:// URL is built from url.host + url.pathname + userQuery, which silently drops url.search and url.hash if link.shortLink ever contains them. Similarly, the fallback concatenates ${link.shortLink}?skip_deeplink_preview=1..., which would produce an invalid ?? if shortLink already had a query string. In practice, dub short links don't carry query strings or fragments, so this is purely defensive, but using URL for both branches would be more robust:

♻️ Optional defensive refactor
-      const url = new URL(link.shortLink);
-      const userQuery = searchParamsString ? `?${searchParamsString}` : "";
-      const fallback = `${link.shortLink}?skip_deeplink_preview=1${
-        searchParamsString ? `&${searchParamsString}` : ""
-      }`;
+      const url = new URL(link.shortLink);
+      const userQuery = searchParamsString ? `?${searchParamsString}` : "";
+
+      const fallbackUrl = new URL(link.shortLink);
+      fallbackUrl.searchParams.set("skip_deeplink_preview", "1");
+      for (const [k, v] of searchParams.entries()) {
+        if (k !== "skip_deeplink_preview") fallbackUrl.searchParams.append(k, v);
+      }
+      const fallback = fallbackUrl.toString();
       const extras = [
         `scheme=${url.protocol.replace(":", "")}`,
         `package=${androidPackageName}`,
         `S.browser_fallback_url=${encodeURIComponent(fallback)}`,
         "end",
       ].join(";");

-      window.location.href = `intent://${url.host}${url.pathname}${userQuery}#Intent;${extras}`;
+      window.location.href = `intent://${url.host}${url.pathname}${url.search}${userQuery}#Intent;${extras}`;

Also nit: the FxiOS part of /Firefox|FxiOS/i is iOS-specific Firefox and unreachable under the platform === "android" guard — /Firefox/i would suffice. Harmless either way.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@apps/web/app/app.dub.co/`(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx
around lines 32 - 51, The intent URL building silently drops existing query/hash
and the fallback can produce double-question-marks; update the android branch to
build both the intent target and the fallback using the parsed URL object (use
url.origin/host + pathname + url.search + url.hash when constructing the intent
path and use URL/searchParams to append skip_deeplink_preview and any
searchParamsString for the fallback) so existing ? and # are preserved and no
"??" occurs; also simplify the Firefox detection to /Firefox/i (referencing
platform, androidPackageName, link.shortLink, searchParamsString, url, and
window.location.href in the android branch).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@apps/web/app/app.dub.co/`(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx:
- Around line 32-51: The intent URL building silently drops existing query/hash
and the fallback can produce double-question-marks; update the android branch to
build both the intent target and the fallback using the parsed URL object (use
url.origin/host + pathname + url.search + url.hash when constructing the intent
path and use URL/searchParams to append skip_deeplink_preview and any
searchParamsString for the fallback) so existing ? and # are preserved and no
"??" occurs; also simplify the Firefox detection to /Firefox/i (referencing
platform, androidPackageName, link.shortLink, searchParamsString, url, and
window.location.href in the android branch).

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 68a92bbf-c7eb-4ee1-a16a-d1fea2be5e19

📥 Commits

Reviewing files that changed from the base of the PR and between 0834e7f and a8cbcf7.

📒 Files selected for processing (2)
  • apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/action-buttons.tsx
  • apps/web/app/app.dub.co/(deeplink)/deeplink/[domain]/[[...key]]/page.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant