Overview
Mobile Wallet Adapter is not available on iOS, and deep links are not a viable replacement for it. Native iOS apps that need transaction signing have to use a different key custody model instead, and wallets can reach mobile web users in Safari through a Web Extension.MWA depends on a persistent connection between the dApp and the wallet app.
iOS suspends backgrounded apps, so that connection cannot be maintained.
Why MWA is unavailable on iOS
The MWA Android SDKs use web socket servers to establish a persistent background connection between the dApp and the wallet app. This is an ongoing two-way channel that lets the dApp exchange messages with the wallet to request authorization, signing, and so on. iOS does not permit this kind of persistent communication. When an iOS app is backgrounded, the operating system suspends it, which disables any ongoing network communication from that app. An MWA implementation built on local — or even remote — web sockets is therefore not possible on iOS.Why deep links are not a substitute
The most commonly proposed workaround is wallet communication over deep links (technically Universal Links on iOS, referred to as deep links throughout this guide). Deep links cannot provide the same functionality as an MWA persistent connection, and they degrade the user experience in three ways.Excessive context switching
An MWA session requires multiple message exchanges between the wallet and the dApp. Over deep links, each message triggers a full app switch, so the number of switches grows with the number of requests. The examples below use a hypothetical idealizeddeeplinkWalletToX API. A real deep
link request/response API would be more convoluted than this, as covered in
No response callback.
deeplinkWalletToSignAll request. It stops helping as soon as one request
depends on the outcome of another, at which point the transactions have to be
separated again:
No wallet selection dialog
On Android, wallet apps register to handle MWA intents with thesolana-wallet://
scheme. When a dApp sends an MWA intent, Android displays a Chooser dialog listing
every installed wallet app that implements MWA — known as intent disambiguation.
Once the user chooses, the dApp knows which wallet to establish communication with.
iOS has no disambiguation step. Multiple apps can register to handle a standard link
like solana-wallet://, but the system provides no Chooser dialog equivalent.
Instead it opens whichever wallet app was installed first, which is unexpected and
confusing behavior for the user.
The master wallet list approach
One proposed solution is for each wallet to designate its own custom deep link scheme for MWA requests (for examplewallet-name://mwa/...). The dApp fetches a master
list of all wallet links, checks which are available on the user’s device, and shows
its own selection UI — effectively rebuilding the Chooser dialog per dApp.
Such a list would need three qualities:
- Easily accessible to the dApp
- Easy for wallets to add themselves to
- Consistently up to date, including additions from new wallets
iOS does provide
canOpenUrl,
but using it successfully requires declaring every supported URL scheme in
Info.plist in advance. When a new wallet is added to the master list, the
dApp cannot check for it until it builds and publishes a new version declaring
that scheme.No response callback
Deep links are not designed for back-and-forth message exchange, so building a request/response protocol on top of them leads to hacky patterns and architectures. A Swift function that initiates a deep link connect request is usually called from a connect button view:AppDelegate or
SceneDelegate, completely disconnected from the call site of the original request.
Getting the result back to that call site requires a workaround such as broadcasting
a notification:
Alternatives for dApp developers
iOS restricts the inter-app communication that the traditional key custody model depends on, where a wallet app stores the keypair. dApps in product spaces where that model carries too much friction have been exploring alternative models.
Because alternative custody models do not depend on app-to-app communication, they
work on iOS.
Wallet-as-a-service
A growing solution for native iOS apps is a wallet-as-a-service provider. These services give the dApp a per-app wallet for each user, rather than relying on the user having a self-custody wallet app installed. The provider manages and stores the keypair with its own implementation, such as MPC-TSS or MPC-SSS. The relevant advantages:- Users onboard faster, without the extra step of installing another app.
- Familiar Web2 patterns such as social and email login.
- No inter-app communication required, so the model works on iOS.
Passkeys
Passkeys are an emerging solution for key custody across mobile and desktop devices. They use public key cryptography to store secrets for apps and websites: a public key is stored on the server, and the private key is stored securely on the device. They are a generalized mechanism for storing secrets such as account passwords, but can be used in a roundabout way for web3 purposes such as storing keypairs. Apple provides a system-level API for integrating passkeys into an iOS app. The advantages:- Users do not need to remember a password to access their secrets. They unlock them with biometrics such as FaceID or fingerprint scanning, which is arguably both more convenient and more secure.
- Passkeys are phishing resistant. They are intrinsically linked to the app or website they were created for, so users cannot be tricked into using a passkey on a fraudulent app or website.
- Support is not consistent across platforms. The web, and Safari in particular, has the best support. Android has a more limited API, and not all browsers support the same features. It is reasonable to expect this to become more standardized over time.
- Passkeys do not support ed25519 signing or key storage directly. The ed25519 keypair is encrypted with another scheme and placed into the passkey, which means the keypair is exposed to the dApp when it is retrieved for signing.
