Pages

Tuesday, June 5, 2012

Building Chrome extensions with GWT


Recently i took a look into Google Chrome Web Store. 
The web store as you can take a look for yourself, is loaded with apps, which many of them are given free.


I decided to understand what it takes from a simple developer like myself to build such an app which I can run on my browser & distribute on the Chrome Web Store.


Surprisingly, it does not take a lot of effort to write such an app/extension, especially if you're already familiar with a little bit of web development.
Google Chrome Extensions: http://code.google.com/chrome/extensions/overview.html


So what you really need is some knowledge of JavaScript, HTML & CSS to make a neat extension.


For me the real story began when I realized that for such requirements, one could actually use the (amazing) GWT framework to write such an extension. 
If you never looked into GWT, my personal recommendation is that you absolutely must in case you're into web-development. GWT is a truly incredible tool from my experience.


If you look at the file structure of such an extension, you can see from the "Google Chrome Extensions - Getting Started" tutorial (http://code.google.com/chrome/extensions/getstarted.html) that we're talking about 4 important files:

  1. manifest.json - This file if you like is some kind of a descriptor of your extension.
  2. An HTML file "hosting" your extension. 
  3. A JavaScript file containing all the cool interaction with your extension, and your script.
  4. A CSS file - for styling.

When you write your GWT application in Java and compile it afterwards, you get such files, except for the first one. That you will have to add yourself to the project.


So enough of "blabing" - Lets dive right into "How to do it" (if you're impatient, just scroll to the bottom of the page to download a zip file of the project):


1. Start a new web-application project in Eclipse, and let it create the default skeleton of the project.



2. After the project has been created, make some clean up in the project's structure by deleting the "server" and the "shared" packages.


3. Edit the .gwt.xml file and make sure the file's contents is something like:
<?xml version="1.0" encoding="UTF-8"?>
<module rename-to='mychromeext'>

  <!-- Inherit the core Web Toolkit stuff.                        -->
  <inherits name='com.google.gwt.user.User'/>
  <!-- Inherit the default GWT style sheet.  You can change       -->
  <!-- the theme of your GWT application by uncommenting          -->
  <!-- any one of the following lines.                            -->
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>
  <!-- <inherits name='com.google.gwt.user.theme.standard.Standard'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.chrome.Chrome'/> -->
  <!-- <inherits name='com.google.gwt.user.theme.dark.Dark'/>     -->
  <!-- Other module inherits                                      -->
  <!-- Specify the app entry point class.                         -->
  <entry-point class='com.techdrum.chrome.ext.example.app.client.MyChromeExt'/>
  <!-- Specify the paths for translatable code                    -->
  <source path='client'/>

  <set-property name="user.agent" value="safari"/>
</module>
4. Delete the auto-generated Async file and it's matching service file.

5. Write some GWT code in the MyChromeExt.java file, something very simple like - 

package com.techdrum.chrome.ext.example.app.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextBox;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class MyChromeExt implements EntryPoint {
/**
* This is the entry point method.
*/
public void onModuleLoad() {
final Button sendButton = new Button("Send");
final TextBox nameField = new TextBox();
// We can add style names to widgets
sendButton.addStyleName("sendButton");
// Add the nameField and sendButton to the RootPanel
// Use RootPanel.get() to get the entire body element
RootPanel.get("nameFieldContainer").add(nameField);
RootPanel.get("sendButtonContainer").add(sendButton);
// Focus the cursor on the name field when the app loads
nameField.setFocus(true);
nameField.selectAll();
}
}
6. Almost done! Create a new file called "manifest.json" and place it under the "war" directory.
The file should contain the following:

{
  "name": "My GWT ext",
  "version": "1.0",
  "description": "Simple GWT Extension!",
  "browser_action": {
    "default_popup": "MyChromeExt.html"
  },
  "permissions": [
  ],
   "web_accessible_resources": [
    "mychromeext /E949D2D1E7CE643145D4D3D5FC28BB31.cache.html"
  ]
}
*Note the stressed file name!

7. Compile the project.

8. Match the file name with the .cache.html suffix under the directory mychromeext to the one mentioned in paragraph 6. 
So if you have something like BF13DA7B8EE69ECA8CAA8F35290E1E1E.cache.html
then your new manifest.json should look like:

{
  "name": "My GWT ext",
  "version": "1.0",
  "description": "Simple GWT Extension!",
  "browser_action": {
    "default_popup": "MyChromeExt.html"
  },
  "permissions": [
  ],
   "web_accessible_resources": [
    "mychromeext/BF13DA7B8EE69ECA8CAA8F35290E1E1E.cache.html"
  ]
}

9. That's it! Now you're ready to deploy your new extension on Google Chrome.
    To do that - open Chrome, and open the Extensions window:


10. Make sure to check the "Developer Mode" box, and then click on "Load unpacked extension..."
Select the war directory of the compiled project, and your new extension should appear on the Chrome toolbar next to the address bar.
When clicking on it, you'll see your app:


Congratulations!



Get the full code of the project here.