Rectangle 27 20

There are 3 principal ways of showing a notification in Chrome.

1) Aforementioned chrome.notifications API. It will show a toast (not merely an indication in systray), but you as a developer have little say on how it appears. Usage overview here.

2) Standard HTML Notification API. In Chrome, looks similar to chrome.notifications, except for less control over formatting and not managed by Chrome's notification center. Usage overview here.

3) If you really want control over how it's shown, the most invasive and hard way is to inject your UI into all pages with a content script.

You face several problems if you do that:

  • In general, it's harder to design the UI yourself;
  • CSS may bleed from the page and mangle your UI (though Shadow DOM can be an answer);
  • You need blanket permissions for "data on all webpages" just to show your UI. It tends to scare users away.

If you decide to go that route nonetheless, here's a question that might help: Chrome extension content scripts custom ui

I don't know if you have used evernote web clipper extension, but are those notifications shown in that extension built using the third option that you suggested?

But if you are using the option 1 or 2 (I'm trying to use number 2) how do you get the registration_id in order to send push notifications to the chrome browser? And how do you wait for that notifications? Thank you for that answer!

@eloibm Displaying notifications has absolutely nothing to do with receiving them. Meditate upon chrome.gcm and linked docs. If you still have questions, ask a new question - don't ask unrelated follow-up questions in comments, that's not the purpose of comments.

javascript - show notifications in chrome extension - Stack Overflow

javascript google-chrome google-chrome-extension google-chrome-app
Rectangle 27 5

Since you're using a fixed notification ID, it's updated instead of creating a new one.

If the notification is not closed but hidden in the Chrome notification center, it will not be shown again.

javascript - Chrome extension notification shows only once - Stack Ove...

javascript google-chrome google-chrome-extension firebase
Rectangle 27 1

You can also add a timestamp suffix so every notification is different:

var timestamp = new Date().getTime();
var id = 'myid' + timestamp;

javascript - Chrome extension notification shows only once - Stack Ove...

javascript google-chrome google-chrome-extension firebase
Rectangle 27 34

Also, with Google Chrome you can use "pretty print". See the example screenshot below showing jquery.min.js from Stack Overflow nicely indented right from my browser :)

jquery - JavaScript error (Uncaught SyntaxError: Unexpected end of inp...

javascript jquery syntax syntax-error indentation
Rectangle 27 6

Navigate to chrome://inspect/ and you can see all the pages that can be inspected. Under the section "Extensions" you should be able to see your notification page and you can inspect it.

javascript - Debugging tool for Chrome Extension notification window -...

javascript html5 google-chrome google-chrome-extension google-chrome-devtools
Rectangle 27 15

Implementation in your Google Chrome extension:

Messages passed between a Content Script and a background page are JSON-serialized.

If you want to transfer an ArrayBuffer object through a JSON-serialized channel, wrap the buffer in a view, before and after transferring.

I show an isolated example, so that the solution is generally applicable, and not just in your case. The example shows how to pass around ArrayBuffers and typed arrays, but the method can also be applied to File and Blob objects, by using the FileReader API.

// In your case: self.data = { data: new Uint8Array(xhr.response), ...
// Generic example:
var example = new ArrayBuffer(10);
var data = {
    // Create a view
    data: Array.apply(null, new Uint8Array(example)),
    contentType: 'x-an-example'
};

// Transport over a JSON-serialized channel. In your case: sendResponse
var transportData = JSON.stringify(data);
//"{"data":[0,0,0,0,0,0,0,0,0,0],"contentType":"x-an-example"}"

// At the receivers end. In your case: chrome.extension.onRequest
var receivedData = JSON.parse(transportData);

// data.data is an Object, NOT an ArrayBuffer or Uint8Array
receivedData.data = new Uint8Array(receivedData.data).buffer;
// Now, receivedData is the expected ArrayBuffer object

This solution has been tested successfully in Chrome 18 and Firefox.

// Part of the Content script
    self.data = {
        data: Array.apply(null, new Uint8Array(xhr.response)),
        contentType: xhr.getResponseHeader('Content-Type')
    };
...
sendResponse({data: self.data});

// Part of the background page
chrome.runtime.onMessage.addListener(function(data, sender, callback) {
    ...
    data.data = new Uint8Array(data.data).buffer;
ArrayBuffer
Uint8Array
<Function> .apply
  • SO bonus: Upload a File in a Google Chrome Extension - Using a Web worker to request, validate, process and submit binary data.

This Array.apply(null, new Uint8Array(xhr.response)) doesn't work for big buffers (bigger than 150Kb) raising Maximum call stack size exceedederror. Even for small buffers probably it is better to pass binary strings that JS arrays.

javascript - Chrome extension: how to pass ArrayBuffer or Blob from co...

javascript json google-chrome-extension typed-arrays xmlhttprequest-level2
Rectangle 27 577

Below is a working example of desktop notifications for Chrome, Firefox, Opera and Safari. Try it live on JSBin.

// request permission on page load
document.addEventListener('DOMContentLoaded', function () {
  if (!Notification) {
    alert('Desktop notifications not available in your browser. Try Chromium.'); 
    return;
  }

  if (Notification.permission !== "granted")
    Notification.requestPermission();
});

function notifyMe() {
  if (Notification.permission !== "granted")
    Notification.requestPermission();
  else {
    var notification = new Notification('Notification title', {
      icon: 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
      body: "Hey there! You've been notified!",
    });

    notification.onclick = function () {
      window.open("http://stackoverflow.com/a/13328397/1269037");      
    };

  }

}
<button onclick="notifyMe()">Notify me!</button>

We're using the W3C Notifications API, documented at MDN. Do not confuse this with the Chrome extensions notifications API, which is different. Chrome extension notifications obviously only work in Chrome extensions, don't require any special permission from the user, support rich text notifications, but disappear automatically and the user may not notice they have been triggered). W3C notifications work in many browsers (see support on caniuse), require user permission, stack on top of the previous notification and don't automatically disappear in Chrome (they do in Firefox).

Notification support has been in continuous flux, with various APIs being deprecated over the last three years. If you're curious, check the previous edits of this answer to see what used to work in Chrome, and to learn the story of rich HTML notifications.

There's also a different call (though with the same parameters) to create notifications from service workers, which for some reason, don't have access to the Notification() constructor.

See also notify.js for a helper library.

@mghaoui - popular != true (necessarily). i've marked this one as the correct answer.

window.webkitNotifications.checkPermission() will throw an exception in non-Chrome browsers

Close is not a method. I think you want notification.cancel() > decadecity.net/blog/2012/10/12/webkit-notification-api >> Also it appears to close on its own.

not working in Chrome Version 47.0.2526.80 dev-m while worked on Mozilla Fire fox on Windows 8

javascript - Chrome desktop notification example - Stack Overflow

javascript desktop google-chrome notifications
Rectangle 27 577

Below is a working example of desktop notifications for Chrome, Firefox, Opera and Safari. Try it live on JSBin.

// request permission on page load
document.addEventListener('DOMContentLoaded', function () {
  if (!Notification) {
    alert('Desktop notifications not available in your browser. Try Chromium.'); 
    return;
  }

  if (Notification.permission !== "granted")
    Notification.requestPermission();
});

function notifyMe() {
  if (Notification.permission !== "granted")
    Notification.requestPermission();
  else {
    var notification = new Notification('Notification title', {
      icon: 'http://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png',
      body: "Hey there! You've been notified!",
    });

    notification.onclick = function () {
      window.open("http://stackoverflow.com/a/13328397/1269037");      
    };

  }

}
<button onclick="notifyMe()">Notify me!</button>

We're using the W3C Notifications API, documented at MDN. Do not confuse this with the Chrome extensions notifications API, which is different. Chrome extension notifications obviously only work in Chrome extensions, don't require any special permission from the user, support rich text notifications, but disappear automatically and the user may not notice they have been triggered). W3C notifications work in many browsers (see support on caniuse), require user permission, stack on top of the previous notification and don't automatically disappear in Chrome (they do in Firefox).

Notification support has been in continuous flux, with various APIs being deprecated over the last three years. If you're curious, check the previous edits of this answer to see what used to work in Chrome, and to learn the story of rich HTML notifications.

There's also a different call (though with the same parameters) to create notifications from service workers, which for some reason, don't have access to the Notification() constructor.

See also notify.js for a helper library.

@mghaoui - popular != true (necessarily). i've marked this one as the correct answer.

window.webkitNotifications.checkPermission() will throw an exception in non-Chrome browsers

Close is not a method. I think you want notification.cancel() > decadecity.net/blog/2012/10/12/webkit-notification-api >> Also it appears to close on its own.

not working in Chrome Version 47.0.2526.80 dev-m while worked on Mozilla Fire fox on Windows 8

javascript - Chrome desktop notification example - Stack Overflow

javascript desktop google-chrome notifications
Rectangle 27 1

"browser_action": {
    "name": "Manipulate DOM",
    "icons": { 
        "16": "icon16.png",
        "32": "icon32.png",
        "48": "icon48.png",
        "128": "icon128.png"
    }, 
    "default_icon": "icon128.png",
    "default_popup":"popup.html"
},

Upon relocating the "icons" code out of the "browser_action" block, the icon showed up in the chrome://extensions page like it is suppose to.

"icons": { 
    "16": "icon16.png",
    "32": "icon32.png",
    "48": "icon48.png",
    "128": "icon128.png"
},
"browser_action": {
    "name": "Manipulate DOM",
    "default_icon": "icon128.png",
    "default_popup":"popup.html"
},

I had trouble placing the code in regular code blocks. It kept putting gaps in it.

javascript - Chrome extension icons not all showing - Stack Overflow

javascript css google-chrome google-chrome-extension
Rectangle 27 8

Although you've found out you can circumvent the inline script "issue" (it is a security feature), below is what it would look like if you did not do that. This shows both how to call a notification and a "window"-based dialog.

{
  "name": "Hello World!",
  "version": "1.0",
  "manifest_version": 2,
  "description": "The first extension that I made.",
  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "permissions": [
    "notifications",
    "create",
    "tabs"
  ]
}
<!doctype html>
<html>
  <head>
    <title>Dialog Prompt - Chrome</title>
    <style>
    body {
      overflow: hidden;
      margin: 0px;
      padding: 0px;
      background: white;
    }
    p {
        text-align: center;
        padding: 20px;
    }
    </style>
  </head>
  <body>
    <p>This is a dialog prompt.</p>
  </body>
</html>
var notifier,
    dialog;

function showNotify() {
    var notify;

    if (window.webkitNotifications.checkPermission() == 0) {
        notify = window.webkitNotifications.createNotification(
            "",
            'Notification Test',
            'This is a test of the Chrome Notification System. This is only a test.'
        );
        notify.show();
    } else {
        window.webkitNotifications.requestPermission();
    }
}    
function showDialog(){
    chrome.windows.create({
        url: 'dialog.html',
        width: 200,
        height: 120,
        type: 'popup'
    });
}    
function init() {
    clicker = document.querySelector('#click');
    dialog = document.querySelector('#dialog');

    clicker.addEventListener('click', showNotify, false);
    dialog.addEventListener('click', showDialog, false);
}    
document.addEventListener('DOMContentLoaded', init);

You can find the files to download here:

So basically, in the newer (more secure version), all the javascript functions must be called as callbacks to event listeners in order to execute?

No. In order to get the event listeners attached for the button click's to fire, you have to wait until the DOM is ready to be accessed. The security model in version two says that inline scripts are not allowed, so there's the added requirement to place them in an in like I've done above. I wouldn't just go around it by removing the manifest number or lowering it; it'll eventually get removed. Just get used to running it from a script file. Also, you were a native method that isn't in Chrome extensions, ie, alert().

I also updated it; I didn't realize I'd left a couple things in. Downloadable files are also updated.

"Uncaught TypeError: Cannot read property 'checkPermission' of undefined" this error shown

Javascript in Google Chrome popup extension not running - Stack Overfl...

javascript google-chrome google-chrome-extension
Rectangle 27 8

Thanks to Dr.Molle we figured this out. Here's what I did wrong:

  • The structure of the KML file needs to be like this:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://earth.google.com/kml/2.2">
<Document>
<Placemark>
<Polygon><outerBoundaryIs><LinearRing><coordinates>-73.992177,40.743465,0.0 -74.008242,40.752352,0.0 -74.006533,40.756112,0.0 -73.983973,40.748934,0.0 -73.987733,40.744149,0.0 -73.992177,40.743465,0.0</coordinates></LinearRing></outerBoundaryIs></Polygon></Placemark>
<Placemark><Polygon><outerBoundaryIs><LinearRing><coordinates>-73.973035,40.689458,0.0 -73.989784,40.683305,0.0 -74.008242,40.686381,0.0 -73.978846,40.705181,0.0 -73.977479,40.698003,0.0 -73.973035,40.689458,0.0</coordinates></LinearRing></outerBoundaryIs></Polygon>
</Placemark>
</Document></kml>

To anybody else that finds this there are a couple mistakes in the above example, and also some fallacies. It is not necessary to remove whitespace in the manner suggested. Also the example above has close tags instead of open tags above at the top of the document.

javascript - Google Maps API V3: KML Layer not showing? - Stack Overfl...

javascript google-maps-api-3 kml
Rectangle 27 15

Instead of arguing in comments that a certain approach is better, let me be more constructive and add an answer by showing a particular implementation I co-wrote myself, and explain some gotchas you may run into. Code snippets refer to a service different from Twitter, but the goal was the same. In fact, this code's goal is to report the exact number of unread messages, so yours might be simpler.

My approach is based on an answer here on SO, and instead of being polling-driven (check condition at fixed intervals) is event-driven (be notified of potential changes in condition).

Advantages include immediate detection of a change (which would otherwise not be detected until the next poll) and not wasting resources on polls while the condition does not change. Admittedly, the second argument hardly applies here, but the first one still stands.

Already step 1 has a gotcha to it. Normal content script injection mechanism, when the content script is defined in the manifest, will inject it in pages upon navigation to a page that matches the URL.

"content_scripts": [
  {
    "matches": [
      "*://theoldreader.com/*"
    ],
    "js": ["observer.js"],
    "run_at": "document_idle"
  }
]

This works pretty well, until your extension is reloaded. This can happen in development as you're applying changes you've made, or in deployed instances as it is auto-updated. What happens then is that content scripts are not re-injected in existing open pages (until navigation happens, like a reload). Therefore, if you rely on manifest-based injection, you should also consider including programmatic injection into already-open tabs when extension initializes:

function startupInject() {
  chrome.tabs.query(
    {url: "*://theoldreader.com/*"},
    function (tabs) {
      for (var i in tabs) {
        chrome.tabs.executeScript(tabs[i].id, {file: "observer.js"});
      }
    }
  );
}

On the other end, content script instances that were active at the time of extension reload are not terminated, but are orphaned: any sendMessage or similar request will fail. It is, therefore, recommended to always check for exceptions when trying to communicate with the parent extension, and self-terminate (by removing handlers) if it fails:

try {
  chrome.runtime.sendMessage({'count' : count});
} catch(e) { // Happens when parent extension is no longer available or was reloaded
  console.warn("Could not communicate with parent extension, deregistering observer");
  observer.disconnect();
}

Step 2 also has a gotcha to it, though it depends on the specifics of the service you're watching. Some pages inside the scope of the content script will not show the number of unread items, but it does not mean that there are no new messages.

After observing how the web service works, I concluded that if the title changes to something without navigation, it's safe to assume the new value if correct, but for the initial title "no new items" should be ignored as unreliable.

So, the analysis code accounts for whether it's the initial reading or handling an update:

function notify(title, changed) {
  // ...
  var match = /^\((\d+)\)/.exec(title);
  var match_zero = /^The Old Reader$/.exec(title);

  if (match && match[1]) {
    count = match[1];
  } else if (match_zero && changed) {
    count = 0;
  }
  // else, consider that we don't know the count
  //...
}

It is called with the initial title and changed = false in step 2.

var target = document.querySelector('head > title');

var observer = new window.MutationObserver(
  function(mutations) {
    mutations.forEach(
      function(mutation){
        notify(mutation.target.textContent, true);
      }
    );
  }
);

observer.observe(target, { subtree: true, characterData: true, childList: true });

For specifics as to why certain options of observer.observe are set, see the original answer.

Note that notify is called with changed = true, so going from "(1) The Old Reader" to "The Old Reader" without navigation is considered to be a "true" change to zero unread messages.

@AmalMurali observer.js is almost fine as it is, just modify URLs and title match patterns to fit your web service. Forget for now about storage.js and how the options page works, cut them away, and you can throw away large parts of background code (background.js and functions.js) that deal with things other than onMessage. The rest - you'll need to implement your own logic for dealing with reported count, and adapt manifest.json. That's a starting point, good luck.

window.MutationObserver
window.MutationObserver=window.MutationObserver||window.WebKitMutationObserver;

@RobW nice catch. In fact, I noticed it, fixed it in the codebase this was taken from, and then forgot to update here.

javascript - How to detect page title change in Google Chrome from an ...

javascript google-chrome google-chrome-extension
Rectangle 27 80

window.webkitNotifications.createNotification

If you want a more robust example (you're trying to create your own Google Chrome's extension, and would like to know how to deal with permissions, local storage and such), check out Gmail Notifier Extension: download the crx file instead of installing it, unzip it and read its source code.

Isn't there anything which works for all browsers ?

@Royi, There is a Firefox extension, as well as a native Firefox implementation which is coming sooner or later. In the case of Internet Explorer, a possible solution would be to ask users of your site to download Chrome Frame, as this would be a viable solution to get notifications working. There is some other Microsoft Solution.

javascript - Chrome desktop notification example - Stack Overflow

javascript desktop google-chrome notifications
Rectangle 27 80

window.webkitNotifications.createNotification

If you want a more robust example (you're trying to create your own Google Chrome's extension, and would like to know how to deal with permissions, local storage and such), check out Gmail Notifier Extension: download the crx file instead of installing it, unzip it and read its source code.

Isn't there anything which works for all browsers ?

@Royi, There is a Firefox extension, as well as a native Firefox implementation which is coming sooner or later. In the case of Internet Explorer, a possible solution would be to ask users of your site to download Chrome Frame, as this would be a viable solution to get notifications working. There is some other Microsoft Solution.

javascript - Chrome desktop notification example - Stack Overflow

javascript desktop google-chrome notifications
Rectangle 27 2

Awesome. By posting this and posting just the culprit code, I noticed I am using the same div as the angular-google-maps module as a container for my PlacesService. By changing this, the map rendered fine.

angular.module("app").controller("IndexCtrl", ["$scope", "$interval", "uiGmapGoogleMapApi", function($scope, $interval, uiGmapGoogleMapApi) {

    var Autocomplete;
    var PlacesService;

    $(document).ready(function() {
        Autocomplete = new google.maps.places.Autocomplete(document.getElementById("placeInput"), {});
        PlacesService = new google.maps.places.PlacesService(document.getElementById("placesContainer"));
    });

    uiGmapGoogleMapApi.then(function(maps) {
        $scope.map = { center: { latitude: 0, longitude: 0 }, zoom: 2 };
        $scope.googleVersion = maps.version;
        maps.visualRefresh = true;

    });

}]);
<div class="col-xs-12 col-md-6">
    <div class="row">
        <div class="col-xs-12">
            <div id="map"></div>
            <div class="well">
                <ui-gmap-google-map center="map.center"
                                    zoom="map.zoom"
                                    pan="true"
                >
                </ui-gmap-google-map>
            </div>
        </div>
    </div>
</div>

javascript - Angular-google-maps not showing - Stack Overflow

javascript angularjs google-maps google-maps-api-3 angular-google-maps
Rectangle 27 1

That error must be showing because of an Adblock extension.

How to Disable Adblock in chrome

You have an icon in the top right corner of your browser with a red hand, just press and click Stop Adblock

javascript - chrome shows a warining of youtube embed url in iframe - ...

javascript html google-chrome iframe embed
Rectangle 27 4

Adding a video using a tag Seems not working.

<div>
    <a class="owl-video" href="https://www.youtube.com/watch?v=Oy9GFAQ4x4w"></a>
</div>

Instead it you can replace it by Iframe to embed the video you want like this.

<div class="item-video">
   <iframe width="420" height="315" src="https://www.youtube.com/embed/Oy9GFAQ4x4w">
   </iframe>
</div>

In addition to, I've removed transitionStyle: "fade" because this property blocks the carrousel transition.

You can check it on this DEMO

Can I make the video responsive? I'd like to not specify a height or width to the iframe.

Yes, you can make the video responsive just changing the css properties whatever you want

javascript - OwlCarousel Youtube video not showing - Stack Overflow

javascript jquery video owl-carousel
Rectangle 27 3

I'm seeing the same behaviour with an extension that I am writing. It is really quite annoying, so I went digging through the Chromium source code to find out what its really doing to match the history results.

Short answer: It seems from the source code that this behaviour is intended, so if we want to retrieve all matches to a text query we are stuck with retrieving all of the history results and searching for matches ourselves in JavaScript. On a side note, don't forget to double-check the start/end times, and make sure your 'maxResults' property is large enough, as mistaken values for any of these properties will likely give you unexpected results.

The following function (in history_backend.cc) is eventually called after you call chrome.history.search with a non-empty text query.

bool URLDatabase::GetTextMatchesWithAlgorithm(
    const base::string16& query,
    query_parser::MatchingAlgorithm algorithm,
    URLRows* results) {
  query_parser::QueryNodeVector query_nodes;
  query_parser_.ParseQueryNodes(query, algorithm, &query_nodes);

  results->clear();
  sql::Statement statement(GetDB().GetCachedStatement(SQL_FROM_HERE,
      "SELECT" HISTORY_URL_ROW_FIELDS "FROM urls WHERE hidden = 0"));

  while (statement.Step()) {
    query_parser::QueryWordVector query_words;
    base::string16 url = base::i18n::ToLower(statement.ColumnString16(1));
    query_parser_.ExtractQueryWords(url, &query_words);
    GURL gurl(url);
    if (gurl.is_valid()) {
      // Decode punycode to match IDN.
      base::string16 ascii = base::ASCIIToUTF16(gurl.host());
      base::string16 utf = url_formatter::IDNToUnicode(gurl.host());
      if (ascii != utf)
        query_parser_.ExtractQueryWords(utf, &query_words);
    }
    base::string16 title = base::i18n::ToLower(statement.ColumnString16(2));
    query_parser_.ExtractQueryWords(title, &query_words);

    if (query_parser_.DoesQueryMatch(query_words, query_nodes)) {
      URLResult info;
      FillURLRow(statement, &info);
      if (info.url().is_valid())
        results->push_back(info);
    }
  }
  return !results->empty();
}

The algorithm query_parser::MatchingAlgorithm passed into this function refers to the enum shown below (from query_parser.h), and is never explicitly set from what I can tell, so it will be the DEFAULT value.

enum class MatchingAlgorithm {
  // Only words long enough are considered for prefix search. Shorter words are
  // considered for exact matches.
  DEFAULT,
  // All words are considered for a prefix search.
  ALWAYS_PREFIX_SEARCH,
};

Read the comment above the DEFAULT option -

The algorithm itself (query_parser.cc) breaks down your text query and the raw URL results into lists of "words" separated by spaces or punctuation, and checks for 'prefix matches' between each pair. This explains why if you have several pages in your history with the text "chromium" in the URL, you will get no results if you search for "hromium", but you'll get all of them if you search for "chro".

In your case, I think the search "bi" returns no results because the algorithm only looks for exact word matches for short terms, meaning that "bi" would need to be surrounded by white space or punctuation in the URL/title. This is confirmed if you do a google search for "bi", then query the history again for "bi". The google search history item will be matched since in the URL of the google search the "bi" is surrounded by punctuation and white space:

Also don't forget to check for duplicates, as the results seem to include lots of them for some reason.

javascript - Chrome extension history API not showing all results? - S...

javascript google-chrome google-chrome-extension browser-history
Rectangle 27 275

chrome.runtime.onMessage.addListener

This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).

So you just need to add return true; after the call to getUrls to indicate that you'll call the response function asynchronously.

+1 for this. It has saved me after wasting 2 days trying to debug this issue. I can't believe that this is not mentioned at all in the message passing guide at: developer.chrome.com/extensions/messaging

I've apparently had this issue before; came back to realize I had already upvoted this. This needs to be in bold in big <blink> and <marquee> tags somewhere on the page.

I swear this is the most unintuitive API I've ever used.

javascript - Chrome Extension Message passing: response not sent - Sta...

javascript google-chrome google-chrome-extension google-chrome-app
Rectangle 27 275

chrome.runtime.onMessage.addListener

This function becomes invalid when the event listener returns, unless you return true from the event listener to indicate you wish to send a response asynchronously (this will keep the message channel open to the other end until sendResponse is called).

So you just need to add return true; after the call to getUrls to indicate that you'll call the response function asynchronously.

+1 for this. It has saved me after wasting 2 days trying to debug this issue. I can't believe that this is not mentioned at all in the message passing guide at: developer.chrome.com/extensions/messaging

I've apparently had this issue before; came back to realize I had already upvoted this. This needs to be in bold in big <blink> and <marquee> tags somewhere on the page.

I swear this is the most unintuitive API I've ever used.

javascript - Chrome Extension Message passing: response not sent - Sta...

javascript google-chrome google-chrome-extension google-chrome-app