Platform notes
How the same-device flow (spec §8) looks on each platform: how a wallet gets the request and the caller's origin, what has been tested, and what hasn't. These notes are not normative; the spec's origin rule TR-2 points here for platform formats.
Android
Chrome on Android hands a Digital Credentials API request to Google Play services, which shows the picker and launches the chosen wallet. The reference Android wallet works like this:
- Registration. The wallet registers an entry with Credential Manager through
androidx.credentials.registry.provider.RegistryManager.registerCredentials, with a WebAssembly matcher. The matcher reads each incoming request and decides whether to show the wallet in the picker. - The request. When the patient picks the wallet, its handler activity receives the
org-iso-mdocrequest and reads the SMART request fromrequestInfoWRQ-5. - The web origin.
CallingAppInfo.getOrigin(allowlist)returns the page's origin only when the calling app's package name and signing-certificate fingerprint are on the wallet's privileged-caller allowlist. A production wallet keeps a list of the browsers it trusts. The reference wallet's development build trusts whichever caller it sees, which is fine for testing and wrong for production. - The response. The wallet returns it with the three-argument
PendingIntentHandler.setGetCredentialResponse(intent, response, request)onandroidx.credentials1.7.0-alpha03. That overload hands the response to the browser as a file, so responses of any size get through. Use it rather than the older two-argument form.
Native Verifier apps
A native app uses the web flow. It opens a page on its own domain in a browser surface, the page runs the client library as any web page would (platform wallets and web wallets alike), and the page hands the checked result back to the app. Wallets bind the response to that page's origin; the app trusts the page because it's the app owner's own domain.
Two ways back carry a result of any size:
- The app's own backend (Android and iOS). The page posts the result to the API the app already talks to, under the patient's existing session, and the app fetches it there.
- A Custom Tabs message channel (Android). The app opens the page in a Custom Tab and asks for a message channel, which Chrome grants after checking the app against the page's domain with Digital Asset Links. The page sends the result to the app in parts, so a result of any size gets through. This works end to end: a web wallet opened from the page keeps its link back to it, and a large response arrives intact (Android 17, Chrome 145). The Native Verifier apps guide has the code.
Not yet tested on iOS: which in-app browser surface (SFSafariViewController or
ASWebAuthenticationSession) offers the Digital Credentials API. Safari itself does.
Calling platform wallets directly on Android
On Android an app can also skip the browser and call platform wallets through
CredentialManager.getCredential with a GetDigitalCredentialOption; web wallets aren't
reachable this way. Android reports no origin for an app caller, but it gives the Wallet the app's package name
and signing certificates. The origin string is then android:apk-key-hash: followed by the base64url
SHA-256 of the app's signing certificate TR-2, the format Android's holder
documentation, Multipaz, and Google Wallet use. The app computes the same string for its own transcript. The
reference Android wallet uses it.
A Wallet can't yet name a native app that calls it, so it says that an app is asking; how Wallets should identify native app callers is still open.
iOS and Safari
- Browser. Safari 26 (iOS, iPadOS, and macOS 26) ships the Digital Credentials API with the
org-iso-mdocprotocol. On a Mac, the request continues on a nearby iPhone. - Registering as a wallet. A wallet app answers through an Identity Document Provider extension. The
entitlement that allows this (
com.apple.developer.identity-document-services.document-provider.mobile-document-types) lists a handful of document types by default; Apple approves additional ones on request. A wallet needsorg.smarthealthit.checkin.1approved for it before it can register for this document type. - Reading the SMART request. Before the patient interacts, the extension sees only a parsed summary of the
request, without
requestInfo. Once the patient interacts, the extension callssendResponse, and its closure receives the raw request:deviceRequestandencryptionInfo, includingrequestInfoWRQ-5. - Letting the patient choose. The wallet can hold that closure open while it shows its own screens, item by item HOLD-1, and complete it with the sealed response when the patient is done. This isn't a documented pattern, but it works on iOS 26.
- The origin. Safari gives the extension the calling page's origin as a URL, which reads
https://clinic.example/with a trailing slash. The transcript uses the origin without it TR-2, so strip the slash before hashing. For a page in an iframe, the origin is the top-level page's. - Native iOS apps have no public API for asking a third-party wallet directly. They use the pattern in Native Verifier apps.
- There is no reference iOS wallet or checked-in iOS capture yet. The Swift package implements the Verifier and Wallet sides and runs the spec's conformance tests.
Desktop browsers
On a computer, Chrome can offer to continue on a phone by showing a QR code. The phone's wallet answers, and the transcript is bound to the desktop page's origin. The spec leaves cross-device flows out of scope (§1.4), but the messages are the same. This project's automated tests don't cover it.
What has been tested
| Setup | Versions | How |
|---|---|---|
| Android phone, Chrome, reference wallet | Android 17, Chrome 151, Play services 26.32 | By hand, including large responses |
| Android emulator, Chrome, reference wallet, Testing EHR | API 37 image, Chrome 145, Play services 26.11 | Nightly in CI; the large-response scenario runs by hand on a phone, since the emulator's Chrome 145 predates the browser's large-response path |
| Native Android app as Verifier, through a Custom Tab | Android 17, Chrome 145 | Automated, with the example app and the SMART Testing Wallet |
| Native Android app as Verifier, direct | Android 17 | Automated, with the example app |
| Web wallets in any browser | Current Chrome and Chromium | After every deploy and nightly, by the Testing EHR self-test |
The real Chrome-to-Android capture that Appendix A walks through came from the emulator setup above.