Skip to content

Android delivery: target the app package explicitly so am start can never show a chooser #63

Description

@V3RON

Problem

appduct link --open android and the MCP appduct_connect tool deliver the bootstrap link with an implicit intent (packages/appduct/src/cli/open-target.ts, deliverAndroid):

adb shell am start -a android.intent.action.VIEW -d '<scheme>:///?appduct=...'

No package or component is named. Android resolves the intent by scheme alone, so whenever more than one installed app declares that scheme, the OS shows the "Open with" disambiguation dialog instead of opening the app. At that point the session is never claimed and appduct_wait_for_session blocks for its whole timeout, with nothing telling the agent why. This is the same class of failure as the iOS "Open in App?" alert, and defeats the point of the agent path, which exists so no one has to tap on the device.

This is not exotic. Typical ways to end up with two matching apps on one emulator:

  • Product flavors with applicationIdSuffix (com.example.app and com.example.app.dev) that share one manifestPlaceholders["appductScheme"] / expo.scheme.
  • A released build and a debug build of the same app installed side by side.
  • Two projects that both picked a generic scheme name.

Proposal

Pass the application id to am start so resolution is explicit:

adb shell am start -a android.intent.action.VIEW -d '<link>' -p <applicationId>

-p limits resolution to that package, so the chooser cannot appear, and a missing package fails loudly ("Activity not started, unable to resolve Intent") rather than hanging the wait. The CLI already reads project files statically to find the scheme (native-scheme.ts reads app/build.gradle for manifestPlaceholders, and app.json for Expo), so applicationId from the same Gradle file, or android.package from app.json, can be resolved the same way, with a --package flag / package argument as the override, mirroring how --scheme works today. If no application id can be resolved, keep today's implicit intent so nothing regresses.

Out of scope for this issue, and only worth considering later: a debug-only exported BroadcastReceiver so delivery needs no activity at all. The -p change is enough to close the chooser gap.

Notes

  • usesLoopbackAddress and the adb reverse step are unaffected.
  • The ios-device path already takes a bundleId and validates its shape (letters, digits, ., -); the same validation applies to an Android application id.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions