Here are the key differences in what mobile apps can do that PWAs cannot:
Device Hardware Access Mobile apps have deeper hardware integration - they can access advanced camera features (manual controls, RAW capture), use all sensors simultaneously, control flashlight/torch, access detailed battery information, and interact with specialized hardware like NFC chips, barcode scanners, or IoT devices through direct APIs.
File System and Storage Native apps get unrestricted file system access, can write to any directory, access other apps' shared files, and manage large file operations efficiently. PWAs are sandboxed with limited storage APIs and can't freely browse or modify the device's file system.
Background Processing Mobile apps can run true background processes, execute tasks when the app is closed, perform intensive computations without browser limitations, and maintain persistent background services. PWAs have limited background sync capabilities and are restricted by browser lifecycle management.
System Integration Native apps can modify system settings, register as default apps for file types or URLs, integrate deeply with the OS (like custom keyboards or accessibility services), and access system-level APIs. PWAs operate within browser security constraints.
Performance and Memory Mobile apps have direct access to device resources, can use platform-specific optimizations, allocate memory more freely, and achieve better performance for resource-intensive tasks like gaming, video editing, or complex calculations.
Cross-App Communication Native apps can communicate directly with other apps, share data through system-level mechanisms, and integrate with platform-specific features like Siri Shortcuts, Android Intents, or system-wide search.
Specialized APIs Mobile apps can access platform-specific features like HealthKit, advanced location services, biometric authentication beyond basic WebAuthn, and carrier/telephony information.
The gap is narrowing as web standards evolve, but native apps still have significant advantages for complex, hardware-intensive, or deeply integrated applications.
A link preview, or more technically, a rich preview or unfurl, commonly generated by messaging platforms like WhatsApp, Slack, LinkedIn, etc.
This preview is made possible by specific HTML tags in the <head> section of the webpage—primarily using Open Graph and Twitter Card metadata.
Here’s what a website (like www.ameen.guru) typically includes in its HTML <head> to generate such a preview:
<!-- Title -->
<meta property="og:title" content=" Page name" />
<!-- Description -->
<meta property="og:description" content="some description" />
<!-- URL -->
<meta property="og:url" content="https://www.ameen.guru/" />
<!-- Image (thumbnail shown in preview) -->
<meta property="og:image" content="https://www.ameen.guru/logo.png" />
<!-- Optional: Define type -->
<meta property="og:type" content="website" />
<!-- Optional: Twitter card support -->
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:title" content="page name" />
<meta name="twitter:description" content="some desc" />
<meta name="twitter:image" content="https://www.ameen.guru/logo.png" />
When you paste a URL in platforms like WhatsApp:
The platform makes a request to fetch the HTML of the page.
It scans for og:* and twitter:* meta tags.
It uses these tags to render the preview (title, image, description, and URL).
If you want www.ameen.guru to generate such previews, add Open Graph meta tags in your static website's HTML like so:
<head>
<meta property="og:title" content="Domain and some basic description" />
<meta property="og:description" content="some nice descrioption use AI to generate one." />
<meta property="og:image" content="https://www.ameen.guru/img/your-preview-image.png" />
<meta property="og:url" content="https://www.ameen.guru/" />
<meta property="og:type" content="website" />
</head>
Manually clearing the cache:
// Clear the entire cache
localStorage.clear();
sessionStorage.clear();<p></p>
Appending a cache-busting query parameter to the URL:
// Append a timestamp to the URL
window.location.href = <code>${window.location.origin}${window.location.pathname}?bust=${Date.now()}</code>;<p></p>
This technique forces the browser to fetch a new version of the resource by including a unique query parameter in the URL, which the browser will not cache.
Using the
Cache-Control
HTTP header:
// Set the Cache-Control header to prevent caching
fetch('/my-resource', {
headers: {
'Cache-Control': 'no-cache, no-store, must-revalidate'
}
});
The Cache-Control header can be used to control how the browser caches the response. Setting it to no-cache, no-store , and must-revalidate will prevent the browser from caching the response.
Invalidating the cache using the unload event:
window.addEventListener('unload', () => {
// Invalidate the cache here
localStorage.clear();
sessionStorage.clear();
});
The unload event is fired when the user navigates away from the page, and can be used to invalidate the cache before the page is unloaded.
Using a service worker to control caching:
// In your service worker script
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.open('my-cache').then((cache) => {
return cache.match(event.request).then((response) => {
if (response) {
return response;
}
return fetch(event.request.clone()).then((response) => {
cache.put(event.request, response.clone());
return response;
});
});
})
);
});
Service workers allow you to have more fine-grained control over caching, including the ability to invalidate the cache programmatically.
The choice of technique will depend on your specific use case and the requirements of your application. For example, if you need to invalidate the cache for a specific resource, using a cache-busting query parameter or the Cache-Control header might be the most appropriate approach. If you need to invalidate the cache for the entire application, using
localStorage.clear() or the unload event might be more suitable.