Every app needs its own signing key. For a full understanding of how Android app signing works, see the official Android documentation.Generate a keystore for your app:
Replace my-app-name with your app’s name.Store the keystore file and passwords securely — losing them means you cannot update your app. All future updates must be signed with the same key.
If your app is also published on Google Play, you must use a separate
signing key for the dApp Store. You cannot reuse the same key for both stores.
Publishing multiple apps?
Each app should have its own signing key. You can keep things organized by storing multiple key aliases in a single keystore file:
Then reference the appropriate -alias when signing each app.
Expo
Native Android
Web App
By default, EAS builds an Android App Bundle (.aab). The dApp Store requires an APK instead.For signing, EAS can automatically generate and manage a keystore for you on your first build. Alternatively, you can provide your own keystore created with the instructions above.
Any web app or website can be published on the dApp Store by wrapping it in an Android WebView shell. The solana-mobile webshell command generates that Android project for you and builds a signed release APK from it.
The generated app is a WebView shell, not a Trusted Web Activity
(TWA), so it
needs no Digital Asset Links setup. Browsers are rolling out Local Network
Access restrictions
that break Mobile Wallet Adapter connections for web apps, including TWA-based
wrappers such as Bubblewrap APKs. The shell handles wallet intents natively,
so those flows keep working.
A JDK 17 or newer and the Android SDK are installed. Run solana-mobile doctor to check.
If your web app uses Mobile Wallet Adapter, it is on @solana-mobile/wallet-standard-mobilev0.5.1 or later, which detects the shell and skips the browser permission flow. See Local Network Access.
Template: Web Manifest
A web manifest is optional, but when one is available the CLI seeds the app name, icons, and start URL from it. At minimum, a manifest file includes the app’s name, icons, and start URL:
Either form prompts for whatever is still missing: application id, app name, version code and name, and the signing keystore. See webshell init for the full list of flags.
Already using Bubblewrap? Pass its twa-manifest.json to --manifest and the
CLI carries over the application id, versions, and signing key, so your
existing app updates keep working.
Pass --keystore-path to sign with the key you created above. When that path
does not exist yet, init creates a keystore there instead. Keep the keystore
file and its passwords secure — losing them means you cannot update your app.
The build prompts for the keystore password. Set SOLANA_MOBILE_KEYSTORE_PASSWORD (and SOLANA_MOBILE_KEY_PASSWORD, if the key uses a different password) to skip the prompts in CI:
Every dApp Store update needs a higher versionCode. Bump SOLANA_MOBILE_VERSION_CODE and SOLANA_MOBILE_VERSION_NAME in the generated project’s gradle.properties, then build again:
npx solana-mobile@latest webshell build my-app
Because the shell loads your live site, changes you ship to the web app itself reach users without a new APK.