Appendix B: Install and Uninstall Scripts

Add-ons normally run code at startup, and as it is covered in the main tutorial, all you need is a load event handler and a little code. It is also common for an add-on to require to run a script only when it is installed for the first time, or every time it is updated. It can be used to write or copy necessary files to the profile folder, like the initial DB the add-on will use for storage. A few others require cleanup code to be run after the add-on is uninstalled. This appendix covers these cases with simple code that should work for most add-ons.

Install Scripts

Just like with a regular initialization function, we want a load event handler:

// rest of overlay code goes here.
window.addEventListener(
  "load", function() { XulSchoolChrome.BrowserOverlay.init(); }, false);  

Then all we need is some persistent flag that ensures that the first run code is only run once. The best approach in this case is to use a preference, as explained in the Handling Preferences section. So, if we were to use FUEL, we can do the following in the init function:

init : function() {
  let firstRunPref = "extensions.xulschoolhello.firstRunDone";

  if (!Application.prefs.getValue(firstRunPref, false)) {
    Application.prefs.setValue(firstRunPref, true);
    // all the rest of the first run code goes here.
  }
}

In this case you would need to declare the first run preference in your default preferences file, with a default value of false. You should also change the preference value before you run any other first run code. Keep in mind that the user could have set multiple Firefox windows to open at startup, so there's a race condition on which window will run the first run code.

If you need to run code on every update, or some of them, the code would be very similar. Instead of a boolean preference, it would be best to use a string preference with the last-installed add-on version. And then do a version comparison to decide which code to run. The current version number can be hard-coded in the first run function, or you can use the Add-on Manager to dynamically get it. This can get tricky with the Firefox 4 AddonManager, so it's probably best to keep it simple.

Uninstall Scripts

There are two common cases for needing these: cleaning up local data and presenting an uninstall feedback form. Regarding local data, it is debatable if it is good practice to remove it or not. If an add-on is uninstalled and later installed again, it might be desirable for preferences and other settings to be kept. Another argument in favor of keeping that data is that Firefox doesn't delete its profile folders after it is uninstalled, so it would be consistent to keep it. On the other hand, local data that is no longer needed takes unnecessary disk space and can contain private information that users forget is there. It's up to the developer's discretion.

Uninstalling an add-on happens in 2 stages: first the add-on is flagged to be uninstalled, and then the add-on is actually removed. In the case of Bootstrapped Extensions, both steps happen at the same time. In the case of "traditional" extensions, like those explained in the tutorial, both steps happen at different times. In this case the user is told that Firefox needs to restart in order for the extension to be completely removed. Then the user has the option to restart right away, wait to restart whenever is convenient, or even cancel the uninstall operation. The add-on will not be completely removed until the browser is restarted.

So, in order to detect the first stage, you'll need to add an event listener using the addAddonListener method. The data parameter explains the action being performed.

If you detect your add-on is going to be uninstalled at this stage, it's a good time to show the uninstall feedback form. It is not a good time to clean up your files, at least not without prior user consent. Remember that the user can revert this decision. So, you should listen to other events, like canceling the operation, to make sure that you know what is going on. Set a boolean flag that indicates if your add-on is set to be uninstalled or not, and reset it when necessary.

The second stage is knowing when the application is actually going to be closed. Then you'll have reasonable certainty that the add-on will be removed and you can perform any cleanup operations safely. For this, you need to add an observer for the quit-application topic. This is when you'll know the application will close. Then you can check the flag you set up on the first stage and perform any necessary deletions. You shouldn't perform very time-consuming operations here, at least not without telling users what is going on.