【问题标题】:Mozilla Add-On Execute code on first runMozilla 附加组件 首次运行时执行代码
【发布时间】:2026-01-10 17:05:01
【问题描述】:

我目前正在构建一个插件,我想在第一次运行时执行特定代码。更具体地说,我想单击我的添加按钮,浏览我的文件并选择一个可执行文件。这个浏览过程应该只在第一次运行时完成,因为我希望我的按钮“记住”在第一次运行后打开这个特定文件。

jetpack.future.import("me");

var buttons = require('sdk/ui/button/action');

var button = buttons.ActionButton({
  id: "execute-jar",
  label: "Download Report",
  icon: {
    "16": "./icon-16.png",
    "32": "./icon-32.png",
    "64": "./icon-64.png"
  },
  onClick: handleClick
});

jetpack.me.onFirstRun(function(){    jetpack.notifications.show("Oh boy, I'm installed!");});

function handleClick(state) {   

    let {Cc, Ci} = require('chrome');
    var file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
    file.initWithPath("C:\\Users\\QaziWa\\DownloadReportPPE.jar");

    if(file.exists()){
        file.reveal();
        file.launch();
    }
    else {
        console.log('Failed.');
    }
}

我在 MDN 上找到了这个:https://developer.mozilla.org/en-US/docs/Archive/Mozilla/Jetpack/Meta/Me

但是,这是已存档的内容,当我尝试此操作时,我的代码没有成功并得到:“消息:ReferenceError:jetpack 未定义”。

在这一点上,我很困惑,因为我已经查看了几个与我想要的相关的问题,但我无法弄清楚如何在我的插件中实现这个急需的功能。有人能指出我正确的方向或提供一些有效的代码示例吗?

编辑:为了清楚起见:我不想硬编码路径。我打算添加允许用户选择他们希望执行的文件的功能。我的主要问题是如何仅在第一次运行时执行某个代码块?

【问题讨论】:

  • 您将选择的文件的完整文件名/路径存储为preference。如果该首选项不包含文件名或不存在,则运行文件的选择逻辑/浏览。
  • 抱歉,这不是我要的。在这一点上,我只想知道如何仅在第一次运行附加组件时执行某个函数或代码块。为了清楚我的要求,我已经编辑了 OP。
  • 我没有说硬编码路径。在运行您希望仅在第一次单击按钮时运行的代码后,您创建一个已创建的 preference 或设置为某个值(文件名)。在运行该代码之前,检查是否存在表明您已运行第一次运行代码的值(即您没有文件名),如果该值不存在则运行第一次运行代码。您需要的是在应用程序重新启动时存储文件名的东西。首选项旨在做到这一点。
  • 虽然不是特定于 SDK 的,Appendix B: Install and Uninstall Scripts 对此进行了一些讨论。 jetpack.me.onFirstRun() 基本上是这样做的,但是抽象了创建表明它已经运行过一次的首选项的过程。

标签: javascript firefox-addon firefox-addon-sdk mozilla jpm


【解决方案1】:

拥有首次运行代码的一般情况是,您使用存储在preference 中的某种标志来指示您是否已运行代码。首选项是 Firefox 中用于在应用程序重新启动时存储简单数据的内容。标志可以是多种类型中的任何一种(字符串、数字、布尔值等)。您只需要有一个可以测试的值,以查看您是否已运行您的首次运行代码。这种情况的一般情况在 MDN 上的 Appendix B: Install and Uninstall Scripts 中进行了讨论,但该页面不是 SDK 特定的。当您的附加代码开始运行时,您将测试该标志是否表明您已经运行了您的首次运行代码。如果标志指示您尚未运行第一次运行代码,则运行该代码并设置标志以指示它已运行。你可以稍微修改一下,让代码只在升级到新版本(只是另一个标志)时运行,等等。

在这种情况下,我们还需要在 Firefox 重新启动时存储用户选择的文件名/路径。鉴于我们已经需要存储该信息,并且这是我们需要首次运行代码来获取的信息,chosenFilename 的有效性也可以用作运行首次运行代码的标志。因此,您将选择的文件的完整文件名/路径存储为preference。如果该首选项不包含文件名,则运行文件的选择逻辑/浏览(您的首次运行代码)。

在这种情况下,如果在我们尝试打开文件时发现存储的文件不存在(例如,用户删除/移动了文件),我们也会运行代码来浏览文件。显然,您还应该有一种方法让用户手动启动文件选择器。幸运的是,当我们声明 type as file 时,simple-prefs system 会为我们解决这个问题。 “Browse”按钮将显示在选项对话框中,用户可以使用该按钮手动选择不同的文件。

类似的东西:

let {Cc, Ci} = require('chrome');
let preferences = require("sdk/simple-prefs").prefs;
let winUtils = require("sdk/window/utils");
const nsIFilePicker = Ci.nsIFilePicker;

function chooseFilename(){
    //If you only want .jar files then you would specify that in the filter(s):
    preferences.chosenFilename = browseForFilePath(nsIFilePicker.filterAll);
    //Just assume that it is valid. Should verify here that filename is valid.
}

function openChosenFilename() {   
    let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
    file.initWithPath(preferences.chosenFilename);
    while(!file.exists()){
        //The file we had is no longer valid. We need a valid filename so try choosing it
        // again. Keep doing so until it actually exists.
        chooseFilename();
        file.initWithPath(preferences.chosenFilename);
    }
    return file;
}

//The following function was copied from promptForFile(), then modified: 
//https://developer.mozilla.org/en-US/Add-ons/SDK/Tutorials/Creating_reusable_modules
function browseForFilePath(fileFilters) {
    let filePicker = Cc["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
    let recentWindow = winUtils.getMostRecentBrowserWindow();
    filePicker.init(recentWindow, "Select a file", nsIFilePicker.modeOpen);
    filePicker.appendFilters(fileFilters);
    let path = "";
    let status = filePicker.show();
    if (status === nsIFilePicker.returnOK || status === nsIFilePicker.returnReplace) {
        // Get the path as string.
        path = filePicker.file.path;
    }
    return path; //"" if invalid
}

if(preferences.chosenFilename.length<5) {
    //This is our first run code. We only run it if the length of the chosenFilename 
    //  is less than 5 (which is assumed to be invalid).
    //  You can have any first run code here. You just need to have the 
    //  preference you test for (which could be a string, boolean value, number, whatever) 
    //  be set prior to exiting this if statement. In this specific case,
    //  it is a filename. Given that we also want to store the filename persistent
    //  across Firefox restarts we are checking for filename being stored as a preference
    //  instead of an additional flag that says we have already run this code.
    chooseFilename();
}

let file = openChosenFilename();
file.reveal();
file.launch();

您的package.json 还需要:

"preferences": [{
    "name": "chosenFilename",
    "title": "Filename that has been chosen",
    "description": "A file the user has chosen",
    "type": "file",
    "value": ""
},

【讨论】: