我在MDN上比较这个例子: https://developer.mozilla.org/en-US/docs/Mozilla/Tech/XPCOM/Reference/Interface/nsIProtocolHandler#Implementation
关于如何创建自定义协议的附加组件: https://addons.mozilla.org/en-US/firefox/files/browse/141969/file/components/AboutFosdem.js#top
有人可以详细说明它正在尝试做什么。 SMTP的东西让我失望。
我无法理解MDN上的那个例子正在做什么,无论它在没有chrome.manifst的情况下做了什么。我知道附加组件正在创建“fosdem:// blah”,其中blah是我想要的基于WhereToGo
中的定义,但它使用chrome.manifest。
我认为mdn示例与addon做同样的事情,我会做这样的事情来设置我的自定义协议后复制粘贴mdn代码:
function myCustomBlah() {}
myCustomBlah.prototype =
makeProtocolHandler("mycustomblah",
-1,
"b14c2b67-8680-4c11-8d63-9403c7d4f757"); //i can generate any id
var components = [myCustomBlah];
const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
答案 0 :(得分:4)
Alrighty让我们给出一个更合理的自定义协议处理程序示例。
我决定实现一个ddg:
协议处理程序,一旦注册就可以用来在地址栏中输入ddg:some search terms
(以及其他内容),它会加载DuckDuckGo搜索页面以进行“一些搜索”术语”。
需要实现nsIProtocolHandler
接口。
这个示例组件的作用是“重定向”到DuckDuckGo(好吧,不是真正重定向,但它返回duckduckgo.com的频道)。请参阅内联评论。
var {classes: Cc,
interfaces: Ci,
manager: Cm,
results: Cr,
Constructor: CC
} = Components;
Cm.QueryInterface(Ci.nsIComponentRegistrar);
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const SCHEME = "ddg";
const DDG_URI = Services.io.newURI("https://duckduckgo.com/?q=%s", null, null);
const nsIURI = CC("@mozilla.org/network/simple-uri;1", "nsIURI");
function DuckDuckGoProtocolHandler() {}
DuckDuckGoProtocolHandler.prototype = Object.freeze({
classDescription: "DuckDuckGo Protocol Handler",
contractID: "@mozilla.org/network/protocol;1?name=" + SCHEME,
classID: Components.ID('{858ea860-129a-11e4-9191-0800200c9a66}'),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIProtocolHandler]),
// nsIProtocolHandler
scheme: SCHEME,
defaultPort: -1, // No default port.
// nsIProtocolHandler
allowPort: function(port, scheme) {
// This protocol handler does not support ports.
return false;
},
// nsIProtocolHandler
// Our protocol handler does not support authentication,
// but it is OK to be loaded from any web-page, not just privileged pages""
protocolFlags: Ci.nsIProtocolHandler.URI_NOAUTH |
Ci.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
// nsIProtocolHandler
newURI: function(aSpec, aOriginCharset, aBaseURI) {
// Nothing special here, actually. We were asked to create a new URI.
// If there is a base-URI, this means that the browser tries to resolve
// a dependent resource (an image, script) or the user clicked on a relative link.
// In this case we cannot really return another "ddg" URI, but need to return
// the proper https URI.
if (aBaseURI && aBaseURI.scheme == SCHEME) {
return Services.io.newURI(aSpec, aOriginCharset, DDG_URI);
}
// We don't care about the charset, so just ignore that
// (we support what nsIURI supports).
let rv = new nsIURI();
rv.spec = aSpec;
return rv;
},
// nsIProtocolHandler
newChannel: function(aURI) {
// We were asked to open a new channel.
// We could implement an entirely custom channel that supports
// (most of) nsIChannel. But that is tremendous work and outside
// of the scope of this basic example (which is about protocol handlers and
// not channels).
// Or we can just return any other channel we can create.
// Since we're going to implement the "ddg:" protocol, lets just open a
// regular https channel to duckduckgo.com, use the URI as the search term
// and return that channel.
let spec = DDG_URI.spec.replace("%s", aURI.path);
let channel = Services.io.newChannel(spec, aURI.originCharset, null);
// Setting .originalURI will not only let other code know where this
// originally came from, but the UI will actually show that .originalURI.
channel.originalURI = aURI;
return channel;
}
});
如果我们的组件是JavaScript组件,我们需要实现NSGetFactory
通过chrome.manifest注册。幸运的是,XPCOMUtils.jsm
有一个帮手。
var NSGetFactory =
XPCOMUtils.generateNSGetFactory([DuckDuckGoProtocolHandler]);
在bootstrapped / restartless附加组件(包括SDK附加组件)和Scratchpad中,由于chrome.manifest
注册不可用,因此需要手动注册组件。
可以注册NSGetFactory(classID)
的结果,但这里有一些代码手动创建工厂并注册它。
function Factory(component) {
this.createInstance = function(outer, iid) {
if (outer) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return new component();
};
this.register = function() {
Cm.registerFactory(component.prototype.classID,
component.prototype.classDescription,
component.prototype.contractID,
this);
};
this.unregister = function() {
Cm.unregisterFactory(component.prototype.classID, this);
}
Object.freeze(this);
this.register();
}
var factory = new Factory(DuckDuckGoProtocolHandler);
请注意,在无重启的附加组件中,您还需要取消注册 再次关机!
factory.unregister();
将组件代码和手动注册代码复制到暂存器中,将环境设置为浏览器,然后运行它。然后在标签中打开ddg:some search terms
;)
答案 1 :(得分:1)
我完全理解从MDN中删除。
我写了这个例子,它有一个问题,它改变了URL。我会阅读你的解决方案并与我的相比。
btw我从about:addons-memory插件中解除了这个。在此示例中,如果您输入somecustomblah:noitidart
。它会带你去twitter.com/noitidart。问题是,网址从somecustomblah:noitidart
更改为twitter.com/Noitidart/
,我尝试修复,我认为您的解决方案可能有@nmaier的答案。这种方式不需要chrome.manifest
,您也可以使用reigsterComponents
进行注册,并使用unregisterComponents
取消注册。
确保根据您的协议生成自己的UUID:http://www.famkruithof.net/uuid/uuidgen
aDefaultPort
的第三个参数允许您执行moz central正在执行的SMTP操作。您可以省略它,或者如果您不希望在使用端口时执行SMTP操作,则将其设置为null或undefined。
var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components; //can make this const if not in scratchpad
Cm.QueryInterface(Ci.nsIComponentRegistrar);
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/XPCOMUtils.jsm');
var nsIProtocolHandler = Ci.nsIProtocolHandler; //const
var unloaders = [];
function makeProtocolHandler(aProtocol, aClassID, aDefaultPort) {
var obj = {
classID: Components.ID(aClassID),
classDescription: 'blah blah blah',
contractID: '@mozilla.org/network/protocol;1?name=' + aProtocol,
QueryInterface: XPCOMUtils.generateQI([nsIProtocolHandler]),
scheme: aProtocol,
defaultPort: aDefaultPort,
protocolFlags: nsIProtocolHandler.URI_NORELATIVE | nsIProtocolHandler.URI_NOAUTH | nsIProtocolHandler.URI_LOADABLE_BY_ANYONE, //You must specify either URI_LOADABLE_BY_ANYONE, URI_DANGEROUS_TO_LOAD, URI_IS_UI_RESOURCE, or URI_IS_LOCAL_FILE in order for your protocol to work.
newURI: function(aSpec, aOriginCharset, aBaseURI) {
var uri = Cc['@mozilla.org/network/simple-uri;1'].createInstance(Ci.nsIURI);
uri.spec = aSpec;
console.log('uri=', uri);
return uri;
},
newChannel: function(aURI) {
//throw Cr.NS_ERROR_NOT_IMPLEMENTED;
/* Get twitterName from URL */
var postProtocolPath = aURI.spec.split(":")[1];
var uri = Services.io.newURI("http://twitter.com/" + postProtocolPath, null, null);
var channel = Services.io.newChannelFromURI(uri); //, null).QueryInterface(Ci.nsIHttpChannel); //i dont think i need to QI nsIHttpChannel
/* Determines whether the URL bar changes to the URL */
//channel.setRequestHeader("X-Moz-Is-Feed", "1", false);
channel.originalURI = aURI;
return channel;
},
getURIFlags: function(aURI) 0 // i dont think i need this? do I?
};
if (aDefaultPort == undefined || aDefaultPort == null) {
aDefaultPort = -1;
} else {
obj.allowPort = function(port, scheme) {
return port == aDefaultPort;
};
}
return obj;
}
var myComponents = [myCustomBlah];
function myCustomBlah() {}
myCustomBlah.prototype = makeProtocolHandler('mycustomblah', 'b14c2b67-8680-4c11-8d63-9403c7d4f757'); //this uuid (2nd argument) should be generated by you from here: http://www.famkruithof.net/uuid/uuidgen
//const NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
function registerComponents() {
for (let [y, cls] in Iterator(myComponents)) {
console.info('y: ', y, 'cls: ', cls);
try {
var factory = {
_cls: cls,
createInstance: function(outer, iid) {
if (outer) {
throw Cr.NS_ERROR_NO_AGGREGATION;
}
return new cls();
}
};
Cm.registerFactory(cls.prototype.classID, cls.prototype.classDescription, cls.prototype.contractID, factory);
unloaders.push(function() {
Cm.unregisterFactory(factory._cls.prototype.classID, factory);
});
} catch (ex) {
console.warn('failed to register module: ', cls.name, 'exception thrown: ', ex);
}
}
}
function unregisterComponents() {
for (var i = 0; i < unloaders.length; i++) {
unloaders[i]();
}
}
registerComponents(); //run this to make it work. once this is run follwoing examples above: typing "about:yabba" will take you to bings homepage
//unregisterComponents(); //do this to remove it //after running this typing about:yabba will take you to problem loading page