Add to Home Screen not prompt after Beforeinstallprompt event fired - manifest

Add to home screen not prompt even after its meets all PWA specification and checked by on Light House.
I have tried below code to check whether app already installed or not. but appinstalled Event not getting triggered and beforeinstallprompt Event gets fired successfully.
// appinstalled
window.addEventListener('appinstalled', (evt) => {
app.logEvent('a2hs', 'installed');
});
// beforeinstallprompt
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault();
deferredPrompt = event;
});```
// manifest.json
`{
"name": "demo",
"short_name": "demo",
"icons": [{
"src": "/static/public/icon/icon-192x192.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "/static/public/icon/icon-512x512.png",
"sizes": "192x192",
"type": "image/png"
}
],
"start_url": "/",
"orientation": "portrait",
"display": "standalone",
"theme_color": "#085689",
"background_color": "#085689",
"gcm_sender_id": "103xx3xxx50x",
"gcm_user_visible_only": true
}
`
// service worker
`self.addEventListener('fetch', (event) => {
console.log('event', event);
});`

Remove this line from your code
event.preventDefault();
Starting with Chrome 76, preventDefault() stopped the automatic mini-infobar from appearing
More details here
https://developers.google.com/web/fundamentals/app-install-banners/

event.preventDefault();
This is causing you the problem. Remove it.

By removing the event.preventDefault() you have no longer control over the event !
I suggest a lean manner to control the event, and get the information about installation, try the code below :
window.addEventListener('beforeinstallprompt', (event) => {
event.preventDefault();
deferredPrompt = event;
deferredPrompt.prompt();
deferredPrompt.userChoice.then(result => {
if(result.outcome === "accepted") {
// TODO whatever you want to do when the user accept to install the app
} else {
// TODO whatever you want to do when the user refuse to install the app
});
})

Related

Keyboard Shortcuts for chrome extension can be seen in chrome://extensions/shortcuts but not working

This is a chrome extension which clears the input fields of the webpage. it works perfectly fine when I click at the extension.
I tried to give a keyboard shortcut to it. it was working at first but next day when I opened chrome extension was not there(maybe because I kept my extension in my chrome's profile folder at /home/user/.config/google-chrome/Profile 3/Extensions/). so chrome might have not recognised and removed it because it's not from store.
I added it again but this time keyboard shortcut was not working. I don't have any knowledge of developing extensions. I just looked up at the google.developer guides and created this.
// manifest.json
{
"name": "Reset Answers",
"description": "Resets checkboxes, radio button, Input Text!",
"version": "0.0.0.1",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": ["activeTab", "scripting"],
"action": {},
"commands": {
"_execute_action": {
"suggested_key": "Alt+C",
"description": "clears input fields"
}
},
"icons": {
"16": "/images/icon16.png",
"48": "/images/icon48.png",
"128": "/images/icon128.png"
}
}
// background.js
chrome.action.onClicked.addListener((tab) => {
chrome.scripting.executeScript({
target: {tabId: tab.id},
func: clear,
});
});
function clear() {
var elements = document.getElementsByTagName("input");
for (let i = 0; i < elements.length; i++) {
if (elements[i].type == "text" || elements[i].type == "number") {
elements[i].value = "";
} else if (elements[i].type == "radio" || elements[i].type == "checkbox") {
elements[i].checked = false;
}
}
}
chrome.commands.onCommand.addListener((command) => {
});
I tried calling clear function inside that event listener function is also not working.
chrome://extension/shortcuts page shows the extension and the shortcut like this but its not working.
Alt+C is not being used for any other keyboard shortcut on my pc. What I am doing wrong here?
Certain operating system and Chrome shortcuts (e.g. window management) always take priority over Extension command shortcuts and can not be overwritten.
The following sample outputs to console.log when Ctrl+Shift+1 is entered.
manifest.json
{
"name": "hoge",
"version": "1.0",
"manifest_version": 3,
"commands": {
"command1": {
"suggested_key": "Ctrl+Shift+1",
"description": "hoge"
}
},
"background": {
"service_worker": "background.js"
}
}
background.js
chrome.commands.onCommand.addListener((c) => {
switch (c) {
case "command1":
console.log("command1");
break;
}
});

How to executeScript for webRequest event onBeforeRequest in Google Chrome Extension

Following Chrome Extension Manifest V3 rule I want to create an extension, that listens to particular network request and, for startes, just log them to the console of the currently opened tab (later I want to add custom script and styles to the page in the current tab).
For this I try to utilize chrome.scripting.executeScript.
When I implement the sample from https://github.com/GoogleChrome/chrome-extensions-samples/blob/main/examples/page-redder/manifest.json it works like expected for the chrome.action.onClicked listener.
As soon as I try to execute a script within the chrome.webRequest.onBeforeRequest listener, this error pops up:
Error in event handler: TypeError: Error in invocation of
scripting.executeScript(scripting.ScriptInjection injection, optional
function callback): Error at parameter 'injection': Error at property
'target': Missing required property 'tabId'.
at chrome.webRequest.onBeforeRequest.addListener.urls ()
Missing required property tabId? I assume it has to do with the lifecycle, but I cannot figure out what to do. This is my manifest:
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js",
"matches": [ "<all_urls>"]
},
"host_permissions": [
"<all_urls>"
],
"permissions": [
"activeTab",
"tabs",
"webRequest",
"webNavigation",
"management",
"scripting"
]
}
And this is my script, I just slightly modified the "redden"-example:
function reddenPage(url) {
console.log(url);
}
chrome.webRequest.onBeforeRequest.addListener((tab) => {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: reddenPage,
args: [tab.url],
});
},
{urls: ["*://*.google.com/*"]},
[]);
I don't know exactly why, but the script from Github seems not work. This is how it works:
It's not only a couple of changed brackets, look at tab instead of (tab), but also tab.tabId instead of tab.id:
chrome.webRequest.onBeforeRequest.addListener(tab => {
chrome.scripting.executeScript(
{
target: { tabId: tab.tabId },
function: reddenPage,
args: [details.url],
},
() => { console.log('ZZZ') });
}, {
urls: ['<all_urls>']
});

Chrome Extension cause "Uncaught (in promise) Error: Cannot access a chrome:// URL"

I am following how to make chrome extension getting started that is posted in chrome official site https://developer.chrome.com/docs/extensions/mv3/getstarted/
And I copied and pasted all code and run on the same way. But in my case, When I run chrome.scripting.executeScript, It causes "Uncaught (in promise) Error: Cannot access a chrome:// URL" error.
I don't know what is problem. Here is my code that had been copied from the link above.
manifest.json
{
"name": "Getting Started Example",
"description": "Build an Extension!",
"version": "1.0",
"manifest_version": 3,
"background": {
"service_worker": "background.js"
},
"permissions": ["storage", "activeTab", "scripting"],
"action": {
"default_popup": "popup.html",
"default_icon": {
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
}
},
"icons": {
"16": "/images/get_started16.png",
"32": "/images/get_started32.png",
"48": "/images/get_started48.png",
"128": "/images/get_started128.png"
}
}
background.js
let color = '#3aa757';
chrome.runtime.onInstalled.addListener(() => {
chrome.storage.sync.set({ color });
console.log(`default color: ${color}`);
});
popoup.js
// Initialize button with user's preferred color
let changeColor = document.getElementById('changeColor');
chrome.storage.sync.get('color', ({ color }) => {
changeColor.style.backgroundColor = color;
});
// When the button is clicked, inject setPageBackgroundColor into current page
changeColor.addEventListener('click', async () => {
console.log('clicked');
console.log(chrome.tabs);
let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
console.log(tab);
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: setPageBackgroundColor,
});
});
// The body of this function will be executed as a content script inside the
// current page
function setPageBackgroundColor() {
chrome.storage.sync.get('color', ({ color }) => {
document.body.style.backgroundColor = color;
});
}
popup.html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="button.css" />
</head>
<body>
<button id="changeColor"></button>
<script src="popup.js"></script>
</body>
</html>
Do you have an idea??
When you try to trigger the event make sure that you are not in chrome://extensions/ or something similar.
You can check the URL and avoid inject the script for "chrome://":
// skip urls like "chrome://" to avoid extension error
if (tab.url?.startsWith("chrome://")) return undefined;
chrome.scripting.executeScript({
//...
I also do this in the background.js because I'm injecting the script there:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// skip urls like "chrome://" to avoid extension error
if (tab.url?.startsWith("chrome://")) return undefined;
if (tab.active && changeInfo.status === "complete") {
chrome.scripting.executeScript({
//...
Note. To have access to tab.url you need "tabs" in manifest (V3) "permissions".

My Service Worker does not load the page offline and no Manifest is fetched

I am creating a progressive website www.seta-capital.com, on the inspector I do not receive any error, I see the registration of the service worker but the website doesn't load offline, Lighthouse tool says that no service worker is present and no manifest is fetched. Can you please tell me if I am doing something wrong?
I created my very simple manifest.json
{
"short_name": "Seta",
"name": "Seta Capital",
"icons": [
{
"src": "../img/logo_no_writing.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "../img/logo_no_writing.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6"
}
In my index.php I added my Script to locate the json
And I added a service Worker registration script:
<script>
if('serviceWorker' in navigator) {
navigator.serviceWorker
.register('../js/sw.js')
.then(function() { console.log("Service Worker Registered");
});
}
</script>
Finally my sw.js file is:
self.addEventListener('install', function(e) {
e.waitUntil(
caches.open('setacapital').then(function(cache) {
return cache.addAll([
'../',
'../index.php',
'../css/Formcss.css',
'../js/jquery-2.1.0.min.js',
'../js/circle-progress.min.js',
'../css/Formcss2.css',
'../img/bg.jpg',
]);
})
);
});
self.addEventListener('fetch', function(event) {
console.log(event.request.url);
event.respondWith(
caches.match(event.request).then(function(response) {
return response || fetch(event.request);
})
);
});
that won't work.
your index.php is probably a complex dynamically creating file.. depending on a lot of other php code and database queries.
you would need to cache a pre-rendered file like an index.html file.

Passing message from background.js to popup.js

I'm trying to implement my own chrome extension on which, on a certain event, create a browser notification and fills the popup with data calculated in background.js
Here is my manifest.json file:
{
"name": "Dummy name",
"description": "Description",
"manifest_version": 2,
"version": "1.1.3",
"icons": {
"16": "icon_16.png",
"48": "icon_48.png",
"128": "icon_128.png",
"256": "icon_256.png"
},
"browser_action": {
"default_icon": "icon_48.png",
"default_title": "Test",
"default_popup": "popup.html"
},
"permissions": ["background","webRequest","webRequestBlocking","webNavigation","tabs","notifications"],
"background": {
"scripts":["jquery-1.8.1.min.js","classy.js","background.js"]
}
}
My call to sendMessage in background.js
show : function(result) {
var that = this;
chrome.extension.sendMessage({greeting: "hello"}, function(response) {
console.log(response);
});
if(window.webkitNotifications) {
var notification = webkitNotifications.createHTMLNotification('notification.html');
notification.show();
setTimeout(function(){
notification.cancel();
}, '7000');
}
}
My message listener in popup.js (from chrome extension samples)
chrome.extension.onMessage.addListener(
function(request, sender, sendResponse) {
console.log(sender.tab ?
"from a content script:" + sender.tab.url :
"from the extension");
if (request.greeting == "hello")
sendResponse({farewell: "goodbye"});
});
The only error I get is a
Port error: Could not establish connection. Receiving end does not
exist.
Thank you for your help!
Popup doesn't have tab id so you will get the error.
You can use chrome.runtime.sendMessage and chrome.runtime.onMessage.addListener in that case.
So in background.js
chrome.runtime.sendMessage({
msg: "something_completed",
data: {
subject: "Loading",
content: "Just completed!"
}
});
And in popup.js
chrome.runtime.onMessage.addListener(
function(request, sender, sendResponse) {
if (request.msg === "something_completed") {
// To do something
console.log(request.data.subject)
console.log(request.data.content)
}
}
);
I hope it would be helpful to you.
To solve this you need to first send a handshake message to background.js and then send the actual data from background.js to popup.js
For Example: In my case what i did was
popup.js
chrome.runtime.sendMessage({data:"Handshake"},function(response){
});
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
str = JSON.stringify(message.data);
});
background.js
chrome.runtime.onMessage.addListener(function(message,sender,sendResponse){
//alert(message.data);
chrome.runtime.sendMessage({data:datax},function(response){
});
});
What iam trying to do is that as soon as we click on icon the handshake message is sent to the background.js and when it recieves it we can then send the variable or any data whick we wanted to send on popup.js to render it on popup.html.
These are the two simplest ways I've found to send data from background.js to popup.js:
1) Using storage
Save values into storage and once popup gets opened, it gets the values from storage and displays them in the popup.
background.js
chrome.storage.sync.set({ 'dataValue1': 'Some data 1.' });
chrome.storage.sync.set({ 'dataValue2': 'Some data 2.' });
popup.js
function updatePopup() {
chrome.storage.sync.get(['dataValue1', 'dataValue2'], function (data) {
document.getElementById("popupElement1").innerText = data.dataValue1;
document.getElementById("popupElement2").innerText = data.dataValue2;
});
}
document.addEventListener('DOMContentLoaded', updatePopup);
popup.html
<html>
<head>
<script src="popup.js"></script>
</head>
<body>
<p id="popupElement1"></p>
<p id="popupElement2"></p>
</body>
</html>
manifest.json
{
"name": "Background2popup",
"version": "1.0",
"manifest_version": 2,
"description": "This is a demo",
"browser_action": {
"default_popup": "popup.html"
},
"background": {
"scripts": [
"background.js"
]
},
"permissions": [
"<all_urls>",
"storage",
"tabs"
]
}
2) Using chrome.runtime.sendMessage()
Once popup opens, you send a message from popup to background to establish the connection/handshake (otherwise, you would get a 'Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.' if you try to send a message from background to popup and popup isn't open). Once with the connection established, you use sendResponse from background to send the data you wanted to send to popup in the first place.
background.js
chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
if (request.method == "getStatus") {
console.log(request.data)
sendResponse({ method: "peepee", data: "poopoo" })
}
});
popup.js
chrome.runtime.sendMessage({ method: "getStatus", data: "xxx" }, function (res) {
document.getElementById("popupElement1").innerText = res.method;
document.getElementById("popupElement2").innerText = res.data;
return true;
});
popup.html & manifest.json are the same as in the first example
localStorage solution
Because the popup does not have a persistent state, you may want to use localStorage to store the popup state and preload it when popup opens and the storage event to keep track of changes to the state while the popup is open.
Background:
localStorage.setItem('popupData', JSON.stringify({ tabReady: true }));
Popup:
// Load the state from localStorage when popup opens
let popupData = JSON.parse(localStorage.getItem('popupData'));
// Keep track of changes to the popup state while the popup is open
window.addEventListener('storage', (e) => {
if (e.key === 'popupData') {
popupData = JSON.parse(e.newValue);
console.log(popupData.tabReady);
}
});
Use runtime.sendMessage to send messages to background script, and tabs.sendMessage from background to content script.
Please note that you need to specify tab id:
chrome.tabs.query({ active: true }, (tabs) => {
chrome.tabs.sendMessage(tabs[0].id, { greeting: 'hello' }, (response) => {
console.log(response);
});
});
You can find full example and documentation here: https://developer.chrome.com/extensions/messaging#simple