我的团队拥有一个Chrome扩展,另一个团队也有类似的扩展,但很快就会被弃用,所以我们将接管他们所有的现有用户。问题来了——有没有一种方法可以将用户从他们的扩展无缝迁移到我们的扩展?也就是说,有没有办法从用户端自动升级到我们的扩展?
没有无缝的方法,因为明显的安全原因,扩展无法安装其他扩展(即使有"management"
权限),但这里有一个可能的升级路径。
我将调用"旧"扩展名A,并假定其ID为"extension_a_id"
;调用"新"扩展名B,并假定它的ID为`extension_B_ID"。
-
确保扩展可以相互通信。除非您在清单中明确定义了
"externally_connectable"
,否则默认情况下应该是这样;如果这样做,请确保扩展名B包含"extension_a_id"
ID,反之亦然。 -
在以下所有步骤中,更新扩展B以包含对来自A的请求作出响应的代码。在您合理确定大多数安装库都有这个版本之前(可能要等一周左右),不要继续。
//// Extension B (background code) //// chrome.runtime.onMessageExternal.addListener( function(message, sender, sendResponse) { if(sender.id && sender.id == "extension_A_id") { /* ..processing code.. */ } } );
-
在扩展插件A中,添加一个检查插件B是否已安装。通过ping它来完成:
//// Extension A //// chrome.runtime.onStartup.addListener(function() { isNewInstalled(function(response) { if(response) { transferPreferences(response.versionB); // See step 5 } else { // Nag user to install, see step 4 } }); }); function isNewInstalled(callback) { chrome.runtime.sendMessage( "extension_B_id", {areYouThere: true}, passResponseOrFalse(callback) ); } function passResponseOrFalse(callback) { return function(response) { // It's important to evaluate chrome.runtime.lastError // to prevent uncatchable exception, see http://stackoverflow.com/q/28431505 if(chrome.runtime.lastError || !response) { callback(false); } else { callback(response); } } } //// Extension B (processing code) //// // Send version number just in case if(message.areYouThere) sendResponse({ versionB: chrome.runtime.getManifest().version });
-
如果在步骤3中没有安装扩展B,请催促用户安装:显示一个页面,解释为什么需要升级并链接到CWS列表。此步骤需要用户输入。
-
如果在步骤3中已经安装了扩展B,则转移用户选项并自行卸载:
//// Extension A //// function transferPreferences(versionB) { /* ..validate version of B.. */ var prefs = {}; /* ..fill prefs with data that needs to be transfered (JSON-encodable).. */ chrome.runtime.sendMessage( "extension_B_id", { versionA: chrome.runtime.getManifest().version, preferences: prefs }, passResponseOrFalse(goodbyeCruelWorld) ); } function goodbyeCruelWorld(response) { if(response.processed) { // Does not require management permission chrome.management.uninstallSelf(); } else { console.warn("It is not my time to die yet."); } } //// Extension B, processing code //// if(message.preferences) { /* ..validate message.versionA and process message.preferences.. */ sendResponse({processed: true}); }
-
当安装了扩展B时,向(可能安装的)扩展A发送消息,表示传输可以立即开始:
//// Extension B, background code //// chrome.runtime.onInstalled.addListener(function(details) { /* ..maybe check details.reason and new version.. */ chrome.runtime.sendMessage( "extension_A_id", {iAmHere: true, versionB: chrome.runtime.getManifest().version}, ignoreResponse ); }); function ignoreResponse(response) { // Again, evaluate to avoid exceptions; // if needed, this is the place to check if A is still installed return chrome.runtime.lastError; } //// Extension A, background code //// chrome.runtime.onMessageExternal.addListener( function(message, sender, sendResponse) { if(sender.id && sender.id == "extension_B_id") { if(message.iAmHere) { sendResponse({ versionA: chrome.runtime.getManifest().version }); transferPreferences(message.versionB); } } } );
-
将更新发布到具有以上所有内容的扩展名B。
结果:
- 安装了B的用户不会注意到任何事情,因为
ignoreResponse
会吞噬消息错误 - 同时安装了这两个软件的用户将在B更新后立即启动传输,并将悄悄完成
- 只有A的用户在每次重新启动扩展时都会被提示安装B,然后传输将自动启动
最后一个问题是不要用A的偏好来破坏B的偏好;留给读者练习(也取决于实现)。