Branding & Deep Links
One PNG becomes every icon and launch screen on iOS and Android, and links to your site open the right screen in your app. Both are configured in absolute.config.ts; you never edit an asset catalog or an intent filter.
#Icons and splash
Only icon is required. Each optional field refines one platform, and anything you leave out is made from the icon. Paths are relative to the project, and each file can be up to 32 MiB.
import { defineConfig } from '@absolutejs/absolute';
export default defineConfig({
mobile: {
appId: 'com.example.shop',
appName: 'Shop',
server: { productionOrigin: 'https://shop.example.com' },
branding: {
icon: 'assets/mobile/icon.png',
android: {
backgroundColor: '#0B1020',
foreground: 'assets/mobile/android-foreground.png',
monochrome: 'assets/mobile/android-monochrome.png'
},
ios: {
darkIcon: 'assets/mobile/ios-dark.png',
tintedIcon: 'assets/mobile/ios-tinted.png'
},
splash: {
backgroundColor: '#FFFFFF',
darkBackgroundColor: '#0B1020',
logoScale: 0.25
}
}
}
});| branding. | What it is | Format |
|---|---|---|
icon | Required. The app icon on iOS and older Android launchers | Square PNG, at least 1024×1024 |
android.foreground | Adaptive-icon artwork; keep it inside Android’s safe zone | Transparent PNG, 1024×1024 |
android.backgroundColor | Adaptive-icon background color | #RRGGBB, default #FFFFFF |
android.backgroundImage | Adaptive-icon background image, in place of a color | Opaque PNG, 1024×1024 |
android.monochrome | Turns on Android themed icons | Transparent PNG, 1024×1024 |
ios.darkIcon | The iOS dark-appearance icon | PNG, 1024×1024 |
ios.tintedIcon | The iOS tinted-appearance icon | PNG, 1024×1024 |
splash.backgroundColor | Launch screen background, light mode | #RRGGBB, default #FFFFFF |
splash.darkBackgroundColor | Launch screen background, dark mode | #RRGGBB, default #111111 |
splash.logoScale | Size of the centered icon on the launch screen | 0.1 to 0.4, default 0.2 |
splash.image | A finished launch image, used instead of the centered icon | Square PNG, at least 2732×2732 (also splash.darkImage) |
#Generate
mobile assets produces every size each platform needs, including Android’s monochrome icon and iOS’s dark and tinted icons. mobile sync runs it for you whenever the artwork or config changes.
bunx absolute mobile assets --preview --yes # generate, plus a preview page
bunx absolute mobile assets --check # fail if anything is stale
bunx absolute mobile assets android --yes # one platform onlymobile assets instead of editing Android launcher resources or the iOS AppIcon.appiconset by hand. The release check warns when branding is missing and fails when it is invalid or out of date.#Deep links
A link to https://shop.example.com/orders/42 opens the app on the same page your site shows at /orders/42, whether the app was closed or already running. Universal links on iOS and app links on Android are the HTTPS kind; a custom scheme is the shorter fallback. In a custom-scheme link the word right after shop:// is ignored and the path follows it, so shop://open/orders/42 opens /orders/42; so does shop:///orders/42.
| Feature | HTTPS links | Custom scheme |
|---|---|---|
| Example | https://shop.example.com/orders/42 | shop://open/orders/42 |
| Opens the app from a browser, email or message | ||
| Falls back to your website without the app | ||
| Proves you own the domain | ||
| Configured by | deepLinks.hosts and your server | deepLinks.scheme |
import { defineConfig } from '@absolutejs/absolute';
export default defineConfig({
mobile: {
appId: 'com.example.shop',
appName: 'Shop',
server: { productionOrigin: 'https://shop.example.com' },
deepLinks: {
scheme: 'shop',
hosts: ['links.example.com'],
apple: { appIdPrefix: 'ABCDE12345' },
android: {
sha256CertificateFingerprints: [
'14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5'
]
}
}
}
});| deepLinks. | Meaning |
|---|---|
scheme | The custom URL scheme. Defaults to your appId in lowercase. |
hosts | Extra domains that open the app. Your productionOrigin host is always included. Hostnames only: no ports, wildcards or paths. |
apple.appIdPrefix | Your Apple Team ID, ten letters or digits. Required in production when iOS is a platform. |
android.sha256CertificateFingerprints | The SHA-256 fingerprint of every certificate that signs a build people install. Required in production when Android is a platform. |
mobile sync writes these into the native projects: Android intent filters with automatic verification, and the iOS URL scheme and associated domains entitlement. Links that carry a username or password are refused. The sign-in callback uses the same scheme and is handled by Auth, not your pages.
#Team ID and fingerprints
keytool -list -v -keystore release.keystore -alias upload | grep SHA256Fingerprints can be written with or without colons and in any case.
#Association files
Apple and Google check that you own a domain by fetching a file from it. Your AbsoluteJS server serves both, built from your config, with no route to write:
| Path | For | Contains |
|---|---|---|
/.well-known/apple-app-site-association | iOS universal links | Your Team ID and appId, matching every path |
/.well-known/assetlinks.json | Android app links | Your appId and certificate fingerprints |
{
"applinks": {
"details": [
{
"appIDs": ["ABCDE12345.com.example.shop"],
"components": [{ "/": "/*" }]
}
]
}
}deepLinks.apple.appIdPrefix when mobile.platforms includes iOS, or without deepLinks.android.sha256CertificateFingerprints when it includes Android, so a release never ships with links that silently open the browser. Development works without them.Every domain in hosts must serve the same files. If another server hosts one of them, write the files out and deploy them there. Once deployed, --verify fetches each host’s files and checks they match exactly, with no redirects.
bunx absolute mobile associations # write both files to .absolutejs/mobile/associations
bunx absolute mobile associations --verify # fetch them from every host and compare#Reading links in code
Routing needs no code: the page for the link’s path opens by itself. To react to the link as well, such as recording where a visit came from, use links from @absolutejs/devices. It works the same on the web, where the launch link is the page’s own URL.
import { links } from '@absolutejs/devices';
const launch = await links.getLaunchLink();
const referral = launch?.query.get('ref');
if (referral) recordReferral(referral);
const stopListening = await links.onOpenLink((link) => {
if (link.pathname.startsWith('/invite/')) showInviteBanner();
});
await links.openExternal('https://status.example.com');
await stopListening();openExternal opens http and https links in the system browser in the app; on the web it also allows mailto: and tel:.