Skip to content

feat(flet build): Android queries, scheme-only deep links and activity intent filters - #7031

Open
ndonkoHenri wants to merge 12 commits into
flet-1.1.0from
feat/android-queries-6560
Open

ndonkoHenri wants to merge 12 commits into
flet-1.1.0from
feat/android-queries-6560

Conversation

@ndonkoHenri

@ndonkoHenri ndonkoHenri commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

Lets flet build declare more of the Android manifest from pyproject.toml (<queries>, scheme-only deep links, intent filters on the main activity) and fixes three cases where the generated AndroidManifest.xml came out invalid.

#6560 asks for two manifest entries that couldn't be set without a custom build template: a URL-scheme intent filter without a host, and <queries> (for an Alipay integration).

<queries>: [tool.flet.android.queries]

Android 11+ hides other apps unless the manifest's <queries> names them, so an app couldn't check for or open a payment app, and UrlLauncher.can_launch_url() returned False for undeclared schemes.

[tool.flet.android.queries]
packages = ["com.eg.android.AlipayGphone"]
providers = ["com.example.settings.files"]

[[tool.flet.android.queries.intent]]
action = "android.intent.action.VIEW"
categories = ["android.intent.category.BROWSABLE"]   # optional
data = { scheme = "alipays" }                         # or a list of tables
  • Intents follow Android's rules for <queries>: exactly one action, and scheme, host and mimeType each at most once per intent (spread over one or several <data>). path, port and mimeGroup are rejected, with an error that names the setting.
  • Package names must look like com.example.app. A provider entry may list several authorities separated by ;. Duplicates are written once.
  • Placement: entries are added after Flet's own PROCESS_TEXT intent.
  • can_launch_url(): its docstring now says how to declare schemes on Android and iOS.

Deep links with only a scheme

[tool.flet.deep_linking] rendered the Android intent filter and iOS CFBundleURLTypes only when both scheme and host were set.

  • Scheme alone: a scheme is now enough, and myapp://… opens the app.
    • Android: adds android:host only if a host is set.
    • iOS: names the URL type after the bundle id when there is no host. With a host it stays as before.
  • CLI: --deep-linking-scheme alone replaces the project's settings.
  • New errors (Android and iOS): a host without a scheme, from the CLI or pyproject.toml, and http/https without a host, which would make the Android app offer itself for every web link.
  • Flutter's deep-linking flag removed: flutter_deeplinking_enabled (Android) and FlutterDeepLinkingEnabled (iOS) are dropped from the templates. They've been on by default since Flutter 3.27, and links still open the app without them on both platforms (see Testing).
  • Code: the per-key platform/common lookup (get_deep_linking_setting()) and the CLI handling are merged into one get_deep_linking().

Intent filters on the main activity: [[tool.flet.android.activity.intent_filter]]

This covers what the deep-linking setting can't: several schemes, hosts or paths, verified App Links, file types, share targets…

[[tool.flet.android.activity.intent_filter]]
autoVerify = true                       # other keys → attributes of <intent-filter>
actions = ["android.intent.action.VIEW"]
categories = ["android.intent.category.DEFAULT", "android.intent.category.BROWSABLE"]
data = [{ scheme = "https", host = "example.com", pathPrefix = "/invite" }]
  • Placement: filters are added after Flet's launcher and deep-link filters, never replacing them.
  • Receivers: filters are checked by a shared normalize_android_intent_filters(), so [tool.flet.android.receiver] filters also accept <data> and filter attributes now.
  • Docs: links (VIEW with a URL) arrive as routes. Other intents, such as SEND, need native handling.

Fixes

  • [tool.flet.android.manifest_application] couldn't override label, name, icon or enableOnBackInvokedCallback.
    • The bug: the template always wrote those four and then appended the user's entries, so the attribute appeared twice and the Android build failed.
    • The fix: the attributes are now merged in flet build with the user's values on top, XML-escaped, and booleans written as true/false. A product name containing & also broke the manifest before.
  • Unescaped values: [tool.flet.android.meta_data] values and [tool.flet.android.provider] attributes containing &, < or ", such as a URL with a query string, made the manifest invalid. Every value in the manifest template is now escaped, including permission and feature names.

Docs

  • publish/android.md: new Queries and Activity intent filters sections, and the Application attributes and Receivers sections are updated.
    • Flet's built-in entries: translations show them, labelled apart from the example's entries: the FileProvider, INTERNET, the leanback/touchscreen features, the PROCESS_TEXT query, the launcher filter and the four <application> defaults.
    • Hierarchy: every translation starts at <manifest>.
  • iOS, macOS and deep-linking translations: they start at <plist>/<dict> or <manifest> instead of loose <key>s. The deep-link filter is shown inside the main activity.
  • Deep linking (publish/index.md):
    • the host is optional;
    • a link's path and query become page.route;
    • https on iOS needs Universal Links;
    • more Android filters are covered in the Activity intent filters section.
  • Routing guide: a new Deep links section (handle page.route at startup and in on_route_change). Page.route and Page.on_route_change mention deep links.

Testing

  • flet-cli tests: 923 passed, 1 skipped. New tests cover resolution, validation errors and the rendered manifest / Info.plist for queries, <application> attributes, deep links, activity and receiver filters, and escaping. The existing deep-linking tests now call get_deep_linking().
  • Android emulator (Android 16), APKs built from this branch:
    • Queries:
      • with a VIEW + tel query, can_launch_url("tel:123") is True;
      • without one, can_launch_url("sms:123") is False, although Google Messages handles sms:.
    • manifest_application: label = "Queries & Co" with allowBackup = false builds, and aapt reports the label Queries & Co.
    • Scheme-only deep link (fletprobe):
      • a cold start from fletprobe://pay/result?x=1 gives page.route == "/result?x=1";
      • a link while the app runs fires on_route_change with /second?y=2;
      • this works without Flutter's flag.
    • Activity filters:
      • Matching: https://example.com/invite/abc and fletprobe2://x/two match the app, and https://example.com/other doesn't, so pathPrefix applies.
      • autoVerify: kept in the merged manifest, and pm get-app-links lists example.com.
      • Routes: opening the https link gives page.route == "/invite/abc?ref=1".
  • iOS simulator (iOS 26.5), the same scheme-only probe: cold start /result?x=1, then on_route_change with /second?y=2, without FlutterDeepLinkingEnabled.

Fixes #6560

Summary by Sourcery

Extend flet build to configure Android manifest visibility and intent handling while making mobile deep links more flexible and generated manifests valid.

New Features:

  • Add Android manifest queries configuration for package, intent, and provider visibility declarations.
  • Add configurable intent filters for the Android main activity and extend receiver filters with data elements and attributes.
  • Allow scheme-only deep links on Android and iOS, with validation for incomplete web and host configurations.

Bug Fixes:

  • Fix generated Android manifests that failed when application attributes were overridden or manifest values contained XML-special characters.

Enhancements:

  • Remove obsolete Flutter deep-linking template flags and consolidate deep-link configuration resolution across platforms.
  • Document Android queries, activity intent filters, scheme-only deep links, and deep-link routes.

Build:

  • Update the bundled serious_python dependency to version 6.1.3.

Documentation:

  • Expand Android publishing and routing documentation with manifest configuration examples and deep-link handling guidance.

Tests:

  • Add coverage for Android manifest rendering, validation, escaping, application overrides, queries, activity and receiver filters, and scheme-only deep links on Android and iOS.

@sourcery-ai

sourcery-ai Bot commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Sorry @ndonkoHenri, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 1 day and 6 hours by commenting @sourcery-ai review. Upgrade to get a review now.

@ndonkoHenri ndonkoHenri linked an issue Oct 31, 2026 that may be closed by this pull request
@ndonkoHenri ndonkoHenri changed the title flet build: Android queries, scheme-only deep links and activity intent filters feat(flet build): Android queries, scheme-only deep links and activity intent filters Oct 31, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: ee6b7e3
Status: ✅  Deploy successful!
Preview URL: https://bdf10949.flet-website-v2.pages.dev
Branch Preview URL: https://feat-android-queries-6560.flet-website-v2.pages.dev

View logs

…oks up

Android 11+ hides other apps unless the manifest's <queries> names them,
so an app couldn't check or open a payment app or a URL scheme handler,
and UrlLauncher.can_launch_url() returned False. The new table takes
package names, intents (one action, optional categories, data with
scheme, host and mimeType at most once each, per Android's <queries>
rules) and provider authorities, validated with errors that name the
setting. They are rendered after Flet's own PROCESS_TEXT intent.
The Providers, Permissions and Features translations now include what
Flet always or by default adds (the FileProvider, INTERNET, leanback and
touchscreen), labelled apart from the example's entries, and every
manifest translation starts at <manifest> so each element shows under
its real parent. The FileProvider note becomes plain text in Providers.
The template always wrote android:label, android:name,
android:enableOnBackInvokedCallback and android:icon, then appended every
[tool.flet.android.manifest_application] entry, so overriding one of
them produced the attribute twice and the Android build failed on the
invalid manifest. The attributes are now merged in flet build with the
app's entries on top, values are XML-escaped (a product name with "&"
broke the manifest too) and booleans are written as true/false.
… top element

The Export options, Entitlements and deep-linking translations started at
loose <key> or <meta-data> elements; they now start at <plist>/<dict> or
<manifest>, so each element shows under its real parent (the deep-link
filter under the main activity). The Info.plist translations get one
indentation style.
flet build added the Android intent filter and iOS CFBundleURLTypes only
when both scheme and host were set, so a myapp:// link couldn't open the
app without inventing a host. The scheme alone is now enough: the host is
added on Android only if set, and iOS names the URL type after the bundle
id without one. A host without a scheme, or http/https without a host,
which would make the Android app claim every web link, stops the build.
--deep-linking-scheme alone replaces the project settings. Flutter's
deep-linking flags are dropped from both templates: they are on by
default (verified on an Android emulator and the iOS simulator).
The routing guide gets a Deep links section: a link's path and query
become page.route when it opens the app and trigger on_route_change while
the app runs. Page.route and on_route_change say so too, and the publish
docs link to the guide.
Apps can now add their own intent filters to the main activity, after
Flet's launcher and deep-linking filters: several link schemes, hosts or
paths, verified App Links (autoVerify), file types or share targets. A
filter takes actions, categories, a data table or list whose entries
become <data> attributes, and filter attributes. Receivers use the same
filter rules, so their filters gain <data> and attributes too. The docs
say that links arrive as routes and other intents need native handling.
…filters

Cover resolution, validation errors and the rendered Android manifest and
iOS Info.plist for the settings added on this branch, and receiver
filters with <data> and attributes.
…oid manifest

These blocks wrote names and values into AndroidManifest.xml unescaped,
so a meta_data value or provider attribute containing &, < or ", such as
a URL with a query string, made the manifest invalid and the Android
build failed. Every value in the template is now escaped.
@ndonkoHenri
ndonkoHenri force-pushed the feat/android-queries-6560 branch from 3812b06 to ee6b7e3 Compare November 2, 2026 00:46

This branch has not been deployed

No deployments
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.

intents and broadcasts on android

1 participant