Merge pull request #9918 from alexstrat/add-extensions-loading-api
Introduce Chrome extensions management APIs independent of Dev Tools Extensions
This commit is contained in:
commit
ccdff72ee4
3 changed files with 96 additions and 18 deletions
|
@ -582,6 +582,34 @@ Returns `BrowserWindow` - The window that owns the given `webContents`.
|
||||||
|
|
||||||
Returns `BrowserWindow` - The window with the given `id`.
|
Returns `BrowserWindow` - The window with the given `id`.
|
||||||
|
|
||||||
|
#### `BrowserWindow.addExtension(path)`
|
||||||
|
|
||||||
|
* `path` String
|
||||||
|
|
||||||
|
Adds Chrome extension located at `path`, and returns extension's name.
|
||||||
|
|
||||||
|
The method will also not return if the extension's manifest is missing or incomplete.
|
||||||
|
|
||||||
|
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||||
|
is emitted.
|
||||||
|
|
||||||
|
#### `BrowserWindow.removeExtension(name)`
|
||||||
|
|
||||||
|
* `name` String
|
||||||
|
|
||||||
|
Remove a Chrome extension by name.
|
||||||
|
|
||||||
|
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||||
|
is emitted.
|
||||||
|
|
||||||
|
#### `BrowserWindow.getExtensions()`
|
||||||
|
|
||||||
|
Returns `Object` - The keys are the extension names and each value is
|
||||||
|
an Object containing `name` and `version` properties.
|
||||||
|
|
||||||
|
**Note:** This API cannot be called before the `ready` event of the `app` module
|
||||||
|
is emitted.
|
||||||
|
|
||||||
#### `BrowserWindow.addDevToolsExtension(path)`
|
#### `BrowserWindow.addDevToolsExtension(path)`
|
||||||
|
|
||||||
* `path` String
|
* `path` String
|
||||||
|
|
|
@ -15,6 +15,7 @@ const objectValues = function (object) {
|
||||||
// Mapping between extensionId(hostname) and manifest.
|
// Mapping between extensionId(hostname) and manifest.
|
||||||
const manifestMap = {} // extensionId => manifest
|
const manifestMap = {} // extensionId => manifest
|
||||||
const manifestNameMap = {} // name => manifest
|
const manifestNameMap = {} // name => manifest
|
||||||
|
const devToolsExtensionNames = new Set()
|
||||||
|
|
||||||
const generateExtensionIdFromName = function (name) {
|
const generateExtensionIdFromName = function (name) {
|
||||||
return name.replace(/[\W_]+/g, '-').toLowerCase()
|
return name.replace(/[\W_]+/g, '-').toLowerCase()
|
||||||
|
@ -64,6 +65,7 @@ const getManifestFromPath = function (srcDirectory) {
|
||||||
return manifest
|
return manifest
|
||||||
} else if (manifest && manifest.name) {
|
} else if (manifest && manifest.name) {
|
||||||
console.warn(`Attempted to load extension "${manifest.name}" that has already been loaded.`)
|
console.warn(`Attempted to load extension "${manifest.name}" that has already been loaded.`)
|
||||||
|
return manifest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,22 +331,21 @@ app.on('session-created', function (ses) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// The persistent path of "DevTools Extensions" preference file.
|
// The persistent path of "DevTools Extensions" preference file.
|
||||||
let loadedExtensionsPath = null
|
let loadedDevToolsExtensionsPath = null
|
||||||
|
|
||||||
app.on('will-quit', function () {
|
app.on('will-quit', function () {
|
||||||
try {
|
try {
|
||||||
const loadedExtensions = objectValues(manifestMap).map(function (manifest) {
|
const loadedDevToolsExtensions = Array.from(devToolsExtensionNames)
|
||||||
return manifest.srcDirectory
|
.map(name => manifestNameMap[name].srcDirectory)
|
||||||
})
|
if (loadedDevToolsExtensions.length > 0) {
|
||||||
if (loadedExtensions.length > 0) {
|
|
||||||
try {
|
try {
|
||||||
fs.mkdirSync(path.dirname(loadedExtensionsPath))
|
fs.mkdirSync(path.dirname(loadedDevToolsExtensionsPath))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
}
|
}
|
||||||
fs.writeFileSync(loadedExtensionsPath, JSON.stringify(loadedExtensions))
|
fs.writeFileSync(loadedDevToolsExtensionsPath, JSON.stringify(loadedDevToolsExtensions))
|
||||||
} else {
|
} else {
|
||||||
fs.unlinkSync(loadedExtensionsPath)
|
fs.unlinkSync(loadedDevToolsExtensionsPath)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore error
|
// Ignore error
|
||||||
|
@ -354,14 +355,13 @@ app.on('will-quit', function () {
|
||||||
// We can not use protocol or BrowserWindow until app is ready.
|
// We can not use protocol or BrowserWindow until app is ready.
|
||||||
app.once('ready', function () {
|
app.once('ready', function () {
|
||||||
// Load persisted extensions.
|
// Load persisted extensions.
|
||||||
loadedExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
|
loadedDevToolsExtensionsPath = path.join(app.getPath('userData'), 'DevTools Extensions')
|
||||||
try {
|
try {
|
||||||
const loadedExtensions = JSON.parse(fs.readFileSync(loadedExtensionsPath))
|
const loadedDevToolsExtensions = JSON.parse(fs.readFileSync(loadedDevToolsExtensionsPath))
|
||||||
if (Array.isArray(loadedExtensions)) {
|
if (Array.isArray(loadedDevToolsExtensions)) {
|
||||||
for (const srcDirectory of loadedExtensions) {
|
for (const srcDirectory of loadedDevToolsExtensions) {
|
||||||
// Start background pages and set content scripts.
|
// Start background pages and set content scripts.
|
||||||
const manifest = getManifestFromPath(srcDirectory)
|
BrowserWindow.addDevToolsExtension(srcDirectory)
|
||||||
loadExtension(manifest)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -369,7 +369,7 @@ app.once('ready', function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The public API to add/remove extensions.
|
// The public API to add/remove extensions.
|
||||||
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
BrowserWindow.addExtension = function (srcDirectory) {
|
||||||
const manifest = getManifestFromPath(srcDirectory)
|
const manifest = getManifestFromPath(srcDirectory)
|
||||||
if (manifest) {
|
if (manifest) {
|
||||||
loadExtension(manifest)
|
loadExtension(manifest)
|
||||||
|
@ -382,7 +382,7 @@ app.once('ready', function () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserWindow.removeDevToolsExtension = function (name) {
|
BrowserWindow.removeExtension = function (name) {
|
||||||
const manifest = manifestNameMap[name]
|
const manifest = manifestNameMap[name]
|
||||||
if (!manifest) return
|
if (!manifest) return
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ app.once('ready', function () {
|
||||||
delete manifestNameMap[name]
|
delete manifestNameMap[name]
|
||||||
}
|
}
|
||||||
|
|
||||||
BrowserWindow.getDevToolsExtensions = function () {
|
BrowserWindow.getExtensions = function () {
|
||||||
const extensions = {}
|
const extensions = {}
|
||||||
Object.keys(manifestNameMap).forEach(function (name) {
|
Object.keys(manifestNameMap).forEach(function (name) {
|
||||||
const manifest = manifestNameMap[name]
|
const manifest = manifestNameMap[name]
|
||||||
|
@ -400,4 +400,27 @@ app.once('ready', function () {
|
||||||
})
|
})
|
||||||
return extensions
|
return extensions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BrowserWindow.addDevToolsExtension = function (srcDirectory) {
|
||||||
|
const manifestName = BrowserWindow.addExtension(srcDirectory)
|
||||||
|
if (manifestName) {
|
||||||
|
devToolsExtensionNames.add(manifestName)
|
||||||
|
}
|
||||||
|
return manifestName
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserWindow.removeDevToolsExtension = function (name) {
|
||||||
|
BrowserWindow.removeExtension(name)
|
||||||
|
devToolsExtensionNames.delete(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
BrowserWindow.getDevToolsExtensions = function () {
|
||||||
|
const extensions = BrowserWindow.getExtensions()
|
||||||
|
const devExtensions = {}
|
||||||
|
Array.from(devToolsExtensionNames).forEach(function (name) {
|
||||||
|
if (!extensions[name]) return
|
||||||
|
devExtensions[name] = extensions[name]
|
||||||
|
})
|
||||||
|
return devExtensions
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -2373,7 +2373,7 @@ describe('BrowserWindow module', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('dev tool extensions', function () {
|
describe('extensions and dev tools extensions', function () {
|
||||||
let showPanelTimeoutId
|
let showPanelTimeoutId
|
||||||
|
|
||||||
const showLastDevToolsPanel = () => {
|
const showLastDevToolsPanel = () => {
|
||||||
|
@ -2506,6 +2506,33 @@ describe('BrowserWindow module', function () {
|
||||||
app.emit('will-quit')
|
app.emit('will-quit')
|
||||||
assert.equal(fs.existsSync(serializedPath), false)
|
assert.equal(fs.existsSync(serializedPath), false)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('BrowserWindow.addExtension', function () {
|
||||||
|
beforeEach(function () {
|
||||||
|
BrowserWindow.removeExtension('foo')
|
||||||
|
assert.equal(BrowserWindow.getExtensions().hasOwnProperty('foo'), false)
|
||||||
|
|
||||||
|
var extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo')
|
||||||
|
BrowserWindow.addExtension(extensionPath)
|
||||||
|
assert.equal(BrowserWindow.getExtensions().hasOwnProperty('foo'), true)
|
||||||
|
|
||||||
|
showLastDevToolsPanel()
|
||||||
|
|
||||||
|
w.loadURL('about:blank')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws errors for missing manifest.json files', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
BrowserWindow.addExtension(path.join(__dirname, 'does-not-exist'))
|
||||||
|
}, /ENOENT: no such file or directory/)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('throws errors for invalid manifest.json files', function () {
|
||||||
|
assert.throws(function () {
|
||||||
|
BrowserWindow.addExtension(path.join(__dirname, 'fixtures', 'devtools-extensions', 'bad-manifest'))
|
||||||
|
}, /Unexpected token }/)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('window.webContents.executeJavaScript', function () {
|
describe('window.webContents.executeJavaScript', function () {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue