Friday, April 25, 2014

Allow External Content in Google Chrome Apps

We've all experienced it before. You find yourself needing to know how to do something so you Google it. However, your search is so specific that the results don't quite line up with what you're looking for. You need to know something advanced, but the top results only tell you what you already know.

Case in point. I have been developing a Google Chrome app, App for Outlook.com, which allows you to use the Outlook.com web service as a Chrome App. It gives you the ability to pin it to your favorite application launcher, keeps you logged in, and otherwise integrates it with the OS as if it were a native app.

Microsoft provided an official "Chrome App" for Outlook.com, but this was merely a shortcut that opens the site in a new tab. I wanted to run Outlook.com as if it were Outlook itself, particularly on my Mac where I can't use Outlook to connect and get the full experience (Outlook.com can only be accessed via POP or IMAP on Mac OSX). Although I had never developed a Chrome app before, I decided to write one to give Outlook.com a proper desktop experience!

After doing some research, I quickly learned the Chrome App APIs and discovered that writing apps for Chrome is pretty easy. A Chrome App is simply comprised of CSS, HTML, and JavaScript code stored locally in your browser. Before I knew it, I had a shell of an app made out of a few .HTML and .JS files.

However, Chrome's security model posed some challenges. The security model requires you to use a special, Chrome specific HTML tag, called a webview, to embed external HTML in the app. It didn't take me way too long to figure that out; a few easy Google searches pointed me directly to the documentation. Soon I had Outlook.com displaying in my app and I thought I was pretty close to done. I didn't even write much code to pull it off!

I was wrong. I soon realized that I couldn't open any external links in Outlook.com. The Chrome app security model prevents external links from redirecting the current page in a webview. Google wasn't helping much either as the top search results only pointed to Google's page about external content. Sadly that page doesn't explain how to handle links embedded in a web view.

After spending a long time trying to solve the problem, I finally found a solution. I created a 'newwindow' event listener to detect when a link was clicked in the webview. When a link is clicked, the listener intercepts the target URL and then opens a new window with the name "_blank", pointing to the target URL. This tells the Chrome app to open the external link outside the application in a new browser window (or tab, depending on your configuration). Here's the JavaScript code I used to pull it off.

function openNewBrowserWindow(newWindowEvent) {
  window.open(newWindowEvent.targetUrl,"_blank");
}

webview = document.getElementById('webview');
webview.addEventListener('newwindow', openNewBrowserWindow);

This is exactly how the full Microsoft Outlook desktop client behaves when you click an external link in an e-mail, which is exactly what I wanted to replicate with App for Outlook.com.

Of course, this only handles external links in a webview. Adding an external link to your app's internal HTML files won't work either. What if you want to provide an external link your app's support page?

Thankfully you don't even need JavaScript for that. Simply add a link to your HTML file and set the target attribute to "_blank".

<a href="Support" target="_blank">www.stephenbonar.com</a>


Sadly this was not offered as a workaround in any documentation I managed to find. I hope this posts helps another poor soul who found Google's documentation (and search results) lacking. If this post has helped you, please feel free to leave a comment!