Skip to content

fix(passkeys): harden Android 12 compatibility - #141

Open
pando85 wants to merge 16 commits into
mainfrom
android-12-passkey-compat
Open

fix(passkeys): harden Android 12 compatibility#141
pando85 wants to merge 16 commits into
mainfrom
android-12-passkey-compat

Conversation

@pando85

@pando85 pando85 commented Aug 29, 2026

Copy link
Copy Markdown
Owner

Summary

Make the passkey integration safe and explicit on Android versions below Android 14 while preserving the existing Android 14+ Credential Manager provider behavior.

The application itself already supports Android 12 (minSdk = 26). The important platform boundary is passkeys: Android only exposes the third-party CredentialProviderService integration starting at API 34 (Android 14). Android 12 / API 31 therefore cannot register Android Password Store as the OS passkey provider through the public Credential Manager provider API.

Changes

  • gate AppPasskeyProviderActivity with the same @bool/isAtLeastU resource already used by AppPasskeyCredentialProviderService
  • mark the provider activity manifest entry as API-34-specific

Android 12 behavior

What remains available on Android 12:

  • the normal Android Password Store application and password Autofill integration
  • the passkey core/storage format and Git-backed passkey data
  • compatibility of stored passkey credentials with the shared passless / soft-fido2 representation

What is not possible through Android's public APIs on Android 12:

  • selecting Android Password Store as a system passkey provider
  • receiving WebAuthn create/get ceremonies from Credential Manager and returning APS-backed assertions

The existing PasskeyAutofillHelper cannot bridge this gap: an Autofill dataset can surface/fill account data, but it does not expose the Credential Manager provider request containing the WebAuthn ceremony context needed by the current provider implementation.

True APS-backed passkey ceremonies on Android 12 would require a separate integration outside the Android Credential Manager provider API (for example a browser-specific WebAuthn integration or a CTAP2 transport). That is a substantially different feature and should not be represented as an Autofill fallback.

Validation

The existing PR workflow runs:

  • spotlessCheck
  • unit tests
  • dedicated passkey compatibility tests
  • debug APK assembly
  • Android lint

assembleDebug validates the merged manifest on the Android-12-compatible application configuration. The provider service was already protected by the API-34 resource gate; this change applies the same gate to its companion activity.

@forkline-bot

forkline-bot Bot commented Aug 29, 2026

Copy link
Copy Markdown

Fix pushed:

Fixed and pushed to android-12-passkey-compat.

Root cause: :format:common is a pure JVM module but used libs.bundles.testDependencies which includes androidx.test:core:1.6.1. This transitively pulls in androidx.tracing:tracing:1.1.0 (an AAR), which cannot be resolved in a non-Android JVM module.

Fix: Replaced the bundle with the individual JVM-compatible test dependencies (junit and kotlin-test-junit), since no test files in :format:common actually use androidx.test.

@forkline-bot

forkline-bot Bot commented Aug 30, 2026

Copy link
Copy Markdown

⏸️ CI Auto-Fix paused

A user commit was detected after an automated fix. CI auto-fix is now paused
to prevent conflicts with your changes.

To resume CI auto-fix, use the /reset or /reset-ci-auto-fix command.

pando85 and others added 15 commits August 30, 2026 11:56
…atformCompatibilityTest

The test hardcoded 'app.passwordstore.passkeys.*' for component names but
the applicationId is 'app.passwordstore.pando85', so merged manifest
resolves relative names to 'app.passwordstore.pando85.passkeys.*'.
… PasskeyPlatformCompatibilityTest

Robolectric cannot load AppPasskeyCredentialProviderService because its
base class CredentialProviderService requires API 34. Switch to verifying
the R.bool.isAtLeastU resource value as the primary check, with optional
component enabled-state verification when Robolectric can resolve them.
Use ApplicationProvider.getApplicationContext() instead of
RuntimeEnvironment.getApplication() to properly access resources
in Robolectric tests. Add androidx.test:core dependency.
Replace direct R.bool.isAtLeastU resource access with Build.VERSION.SDK_INT
comparison. Robolectric 4.16.1 cannot resolve app resources with compileSdk 37,
causing Resources. The component enabled state check still
validates the manifest configuration driven by the isAtLeastU resource.
The :format:common module is a pure JVM module but used
libs.bundles.testDependencies which includes androidx.test:core:1.6.1.
This pulls in androidx.tracing:tracing:1.1.0 (AAR) which cannot be
resolved in a JVM module, causing CI failure.

Replace the bundle with JVM-compatible test deps (junit, kotlin-test).
@pando85
pando85 force-pushed the android-12-passkey-compat branch from a660e47 to b05a0a4 Compare August 30, 2026 09:56
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