2006/07/04

Creating an uninstall script for an extension

On my last post I explained one way in which you can create a post-install script for an extension. I used a preference to store the current version of the just-installed extension so that future upgrades can use this preference to maybe run different code in case of an upgrade from version X to version Y, as well as running different code when doing a fresh install.
Here's where we run into a little problem: when the extension is uninstalled, the preference remains because it doesn't have it's default value set, and Firefox keeps those just in case they're needed for future installs of the same or even other extensions. So, if I install version X, uninstall it, and then install version Y, it looks like I'm doing an upgrade from X to Y, when in reality I'm doing a fresh install. So now we're need of an uninstall script, to clear this preference.
Uninstall scripts can certainly be needed for many other purposes, specially in the more complex extensions. You may need to delete files you created and won't be using anymore, make sure your preferences are removed, or undo other changes that were done on install. I would say it's professional courtesy to cleanly remove your extension and not leave lots of junk behind.
So let's get to it. As with the install script, you'll need to overlay the main window, adding a script element:
<overlay id="homepage-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/x-javascript"
src="chrome://myextension/content/overlay.js" />
</overlay>
Clearly, you can use the same overlay and script you used for the post-install script, if that's the case. The add something like this:
const MY_EXTENSION_UUID = "{CEDB5187-8A58-4958-ACF5-F6CD3BEF1927}";
function initializeOverlay() {
UninstallObserver.register();
}
var UninstallObserver = {
_uninstall : false,
observe : function(subject, topic, data) {
if (topic == "em-action-requested") {
subject.QueryInterface(Components.interfaces.nsIUpdateItem);

if (subject.id == MY_EXTENSION_UUID) {
if (data == "item-uninstalled") {
this._uninstall = true;
} else if (data == "item-cancel-action") {
this._uninstall = false;
}
}
} else if (topic == "quit-application-granted") {
if (this._uninstall) {
/* uninstall stuff. */
}
this.unregister();
}
},
register : function() {
var observerService =
Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);

observerService.addObserver(this, "em-action-requested", false);
observerService.addObserver(this, "quit-application-granted", false);
},
unregister : function() {
var observerService =
Components.classes["@mozilla.org/observer-service;1"].
getService(Components.interfaces.nsIObserverService);

observerService.removeObserver(this,"em-action-requested");
observerService.removeObserver(this,"quit-application-granted");
}
}
window.addEventListener("load", initializeOverlay, false);
I remove all documentation from the code due to space constraints. I don't want these posts to be longer than necessary. Rest assured that I'm quite obsesive about proper documentation. I just think that these little tips are more readable without it. But I'll always explain the general idea behind the code I post.
First, notice the UninstallObserver object. It's declared as a javascript singleton because we don't need more than one instance. The register and unregister methods basically add and remove this object as an observer for the "em-action-requested" (the "em" stands for Extension Manager) and the "quit-application-granted" topics. This means that the object's observe method will be called every time an action is performed in the Extension Manager, such as installation, uninstallation, enabling, or disabling of extensions, and when the application is going to exit.
In our observe method, we look for the id (UUID) of our extension. This way we know we're dealing with our extension alone. Then we look for the actions we want to observe. In this case we're interested in the "item-uninstalled" action. When the extension is set to be uninstalled, our _uninstall flag will be set to true. Also note we listen to the "item-cancel-action" action. This is very important, because the user can actually cancel uninstallation by right-clicking on the extension in the Extension Manager and selecting the Enable option. This way we know for sure the flag represents the final decision of the user.
Note that we used the "quit-application-granted" topic instead of the "unload" event to trigger the uninstall script. I do it this way because closing the browser window is not the same as quitting the application. You can have more than one browser window open, or other windows open, such as View Page Source or Javascript Console. It's unlikely that going with the "unload" event will cause problems, but it's better to stay on the safe side. There is one downside, though. An observer is created for each browser window (again, it's unlikely to have more than one when you're uninstalling the extension), so the uninstall script will be called for all observers if the user chooses the Exit menu option, closing all windows at once (very, very unlikely). This means you should plan your uninstall script so that it can be executed more than once without causing any damage.
That's it! Now you have an nice uninstall script where you can do all the cleanup you need. This solution was based on code found on a comment in the Two Ells blog, but it does have a couple of improvements.

Labels: , , , , ,


Comments:
Hi Villa,

I implement this code in my extension but it does not work.

For testing i put alert at "observe" but this alert is not also not coming and not even "register" and "unregister" is executing .

I also replace "MY_EXTENSION_UUID " with my em:id but also script is not executing.

please help me.

Nehal Pandya
 
Hi Villa,

This is nehal...
sorry for again distub you,
but i have one more ques.

Villa, is it possible to not allow user to uninstall or disable add-ons.

Thanks
Nehal Pandya
 
Try with the 'quit-application' topic. And no, it's not possible and very uncool to forbid uninstall or disabling.
 
Hi Villa,
Thanks,
That code is working fine now according to my app. it required some changes.

I want to add a functionality that if user try to uninstall/disable add-ons then it will ask for username and password and if that are correct only then user can uninstall/disable add-ons else not.
Is it possible in mozilla.
 
I want to add a functionality that if user try to uninstall/disable add-ons then it will ask for username and password and if that are correct only then user can uninstall/disable add-ons else not.
Is it possible.Please help rme..Waiting for your reply..Thank you
 
I want to add a functionality that if user try to uninstall/disable add-ons then it will ask for username and password and if that are correct only then user can uninstall/disable add-ons else not.
Is it possible?waiting for your reply.
thank you....
 
Yes, that should be possible. I can't write that code for you, but if you learn about extension development, it should be relatively easy.
 
Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?