Fix PWA installation for Brave/Android - Complete rewrite

Critical fixes for PWA installation:
1.  Use proper Vite PWA registration with virtual:pwa-register
2.  Simplified manifest.json (removed verbose name, fixed orientation)
3.  Added 'any maskable' dual-purpose icon for better compatibility
4.  Removed crossorigin from manifest link (causes issues)
5.  Simplified start_url to just '/'
6.  Added msapplication-TileColor meta tag
7.  Set injectRegister: 'auto' in Vite config
8.  Use public/manifest.json directly instead of generating

This should now work on Brave Browser Android with proper 'Install App' prompt.
Test: Clear site data, visit site, should see install prompt within 30 seconds.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Dorian
2026-02-03 00:26:31 +00:00
parent a61da35357
commit 39feb722f5
4 changed files with 29 additions and 54 deletions

View File

@@ -14,8 +14,10 @@
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="IndeedHub">
<meta name="application-name" content="IndeedHub">
<meta name="msapplication-TileColor" content="#0a0a0a">
<meta name="format-detection" content="telephone=no">
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
<link rel="manifest" href="/manifest.json" crossorigin="use-credentials">
<link rel="manifest" href="/manifest.json">
</head>
<body>
<div id="app"></div>

View File

@@ -1,26 +1,23 @@
{
"name": "IndeedHub - Decentralized Media Streaming",
"name": "IndeedHub",
"short_name": "IndeedHub",
"description": "Stream films and content on the decentralized web powered by Nostr and Bitcoin",
"start_url": "/?source=pwa",
"start_url": "/",
"scope": "/",
"display": "standalone",
"orientation": "any",
"orientation": "portrait-primary",
"background_color": "#0a0a0a",
"theme_color": "#0a0a0a",
"prefer_related_applications": false,
"icons": [
{
"src": "/icons/icon-192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "any"
"type": "image/png"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
"type": "image/png"
},
{
"src": "/icons/icon-192-maskable.png",
@@ -33,9 +30,15 @@
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/icons/icon-512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
],
"categories": ["entertainment", "video", "streaming"],
"categories": ["entertainment"],
"lang": "en-US",
"dir": "ltr"
}

View File

@@ -3,6 +3,7 @@ import { createPinia } from 'pinia'
import router from './router'
import App from './App.vue'
import './style.css'
import { registerSW } from 'virtual:pwa-register'
const app = createApp(App)
@@ -11,11 +12,14 @@ app.use(router)
app.mount('#app')
// Register PWA service worker
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').catch(() => {
// Service worker registration failed, that's okay
// Register PWA service worker with auto-update
const updateSW = registerSW({
immediate: true,
onNeedRefresh() {
// Auto-reload when new content is available
updateSW(true)
},
onOfflineReady() {
console.log('App ready to work offline')
},
})
})
}

View File

@@ -8,46 +8,12 @@ export default defineConfig({
vue(),
VitePWA({
registerType: 'autoUpdate',
injectRegister: 'auto',
includeAssets: ['icons/*.png', 'assets/fonts/*.otf'],
devOptions: {
enabled: false
},
manifest: {
name: 'IndeedHub - Decentralized Media Streaming',
short_name: 'IndeedHub',
description: 'Stream films and content on the decentralized web powered by Nostr and Bitcoin',
theme_color: '#0a0a0a',
background_color: '#0a0a0a',
display: 'standalone',
start_url: '/',
scope: '/',
icons: [
{
src: '/icons/icon-192.png',
sizes: '192x192',
type: 'image/png',
purpose: 'any'
},
{
src: '/icons/icon-512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any'
},
{
src: '/icons/icon-192-maskable.png',
sizes: '192x192',
type: 'image/png',
purpose: 'maskable'
},
{
src: '/icons/icon-512-maskable.png',
sizes: '512x512',
type: 'image/png',
purpose: 'maskable'
}
]
},
manifest: false, // Use public/manifest.json instead
workbox: {
maximumFileSizeToCacheInBytes: 10 * 1024 * 1024, // 10 MB limit
globPatterns: ['**/*.{js,css,html,ico,png,svg,jpg,jpeg,woff,woff2,otf}'],