I am using Next.js 15 and I never had any problems with adding splash screens to my applications until I used the newest version of Next.js (15.0.3).
I can install the application successfully and it looks like my manifest loads properly and my app icon works as well. When I look at the head tag in the browser inspector I also see that all my "apple-touch-startup-image" links are registered correctly and the images are linked and can be found in the public folder.
Everything looks like it should, so I have no clue what the error could be. I was thinking that maybe it is because of the Next.js version because that's the only thing different from my other working projects but I'm not sure. Is there something else that I am missing?
I added the following code in my root layout "/src/app/layout.tsx":
export const metadata: Metadata = {
...,
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: APP_DEFAULT_TITLE,
startupImage: [
{
media:
"screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: portrait)",
url: "/assets/apple-splash-2048-2732.jpg",
},
{
media:
"screen and (device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2) and (orientation: landscape)",
url: "/assets/apple-splash-2732-2048.jpg",
},
...
]
}
My manifest "src/app/manifest.ts" looks like this:
export default async function manifest(): Promise<MetadataRoute.Manifest> {
const cookieStore = await cookies();
let appType: AppType = "user";
if (cookieStore.get("app-type")?.value === "admin") {
appType = "admin";
} else if (cookieStore.get("app-type")?.value === "employee") {
appType = "employee";
}
const getStartUrl = () => {
switch (appType) {
case "employee":
return routes.employeePortal.root;
case "admin":
return routes.adminPortal.root;
default:
return routes.userPortal.root;
}
};
return {
name: "App name",
short_name: "App name",
description: "App description",
start_url: getStartUrl(),
display: "standalone",
background_color: "#ffffff",
theme_color: "#ffffff",
icons: [
{
src: "/assets/manifest-icon-192.maskable.png",
sizes: "192x192",
type: "image/png",
purpose: "any",
},
{
src: "/assets/manifest-icon-192.maskable.png",
sizes: "192x192",
type: "image/png",
purpose: "maskable",
},
{
src: "/assets/manifest-icon-512.maskable.png",
sizes: "512x512",
type: "image/png",
purpose: "any",
},
{
src: "/assets/manifest-icon-512.maskable.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
],
};
}
I spent hours trying to debug this very same issue, until I noticed that Next.js replaced the deprecated apple-mobile-web-app-capable
meta tag with mobile-web-app-capable
. Apparantly, the former (deprecated) meta tag is still needed for splash images to work on iOS. There's an issue adressing this now.
Until they fix it, this workaround solved it for me:
appleWebApp: {
capable: true,
statusBarStyle: "default",
title: APP_DEFAULT_TITLE,
startupImage: [...]
},
other: { 'apple-mobile-web-app-capable': 'yes' }, // add this line