Kiểm tra xem người dùng đã cài đặt tiện ích mở rộng Chrome chưa


96

Tôi đang trong quá trình xây dựng một tiện ích mở rộng của Chrome và để mọi thứ hoạt động theo cách tôi muốn, tôi cần một tập lệnh JavaScript bên ngoài để có thể phát hiện xem người dùng đã cài đặt tiện ích mở rộng của tôi hay chưa.

Ví dụ: Một người dùng cài đặt plugin của tôi, sau đó truy cập trang web có tập lệnh của tôi trên đó. Trang web phát hiện rằng tiện ích mở rộng của tôi đã được cài đặt và cập nhật trang cho phù hợp.

Điều này có khả thi không?


2
Có, bạn có thể phát hiện tiện ích mở rộng, miễn là bạn biết ID tiện ích mở rộng của mình (tôi chắc chắn bạn biết). Kiểm tra trang web này để biết thêm thông tin: blog.kotowicz.net/2012/02/intro-to-chrome-addons-hacking.html Bỏ qua phần 'Tìm từng phần bổ trợ của bạn'. Chúc may mắn!
Martin Hughes

Cách thích hợp để thực hiện điều này được mô tả bởi BJury dưới đây.
Rahatur

bài đăng này đã giúp: Ide.hey.network/post/5c3b6c7aa7af38479accc0c7
nab.

Câu trả lời:


46

Tôi chắc chắn có một cách trực tiếp (gọi trực tiếp các hàm trên tiện ích mở rộng của bạn hoặc bằng cách sử dụng các lớp JS cho tiện ích mở rộng), nhưng một phương pháp gián tiếp (cho đến khi có thứ gì đó tốt hơn):

Yêu cầu tiện ích mở rộng Chrome của bạn tìm kiếm một DIV cụ thể hoặc phần tử khác trên trang của bạn, với một ID rất cụ thể.

Ví dụ:

<div id="ExtensionCheck_JamesEggersAwesomeExtension"></div>

Thực hiện một getElementByIdvà đặt thành innerHTMLsố phiên bản của tiện ích mở rộng của bạn hoặc thứ gì đó. Sau đó, bạn có thể đọc nội dung của phía máy khách đó.

Tuy nhiên, một lần nữa, bạn nên sử dụng phương pháp trực tiếp nếu có.


CHỈNH SỬA: Tìm thấy phương pháp trực tiếp !!

Sử dụng các phương pháp kết nối có tại đây: https://developer.chrome.com/extensions/extension#global-events

Chưa được kiểm tra, nhưng bạn sẽ có thể làm ...

var myPort=chrome.extension.connect('yourextensionid_qwerqweroijwefoijwef', some_object_to_send_on_connect);

2
hmmm chrome.extension.connect dường như chỉ hoạt động khi được thực thi từ bên trong tiện ích mở rộng (hoặc bất kỳ tiện ích mở rộng nào). Tôi cần nó hoạt động từ bất kỳ tập lệnh js ngẫu nhiên nào. Bất kỳ ý tưởng?

Thật kỳ lạ, tài liệu nói rằng nó sẽ hoạt động. "Không giống như chrome khác. * API, các bộ phận của chrome.extension có thể được sử dụng bởi các kịch bản nội dung" và nó danh sách sendRequest(), onRequest, connect(), onRequest, và getURL().
Brad

@James bạn có đang thực thi tập lệnh sử dụng .connect () từ một tập lệnh được lưu trữ không? Tôi biết Chrome sẽ cố gắng không làm nhiều thứ chỉ với các tệp cục bộ không được lưu trữ vì mục đích bảo mật. - Kiểm tra thôi.
JamesEggers Ngày

@James tập lệnh mà tôi đang thực thi .connect () từ nằm trên cùng một máy chủ nếu đó là ý bạn?

23
Phương thức cuối cùng không còn hợp lệ , vì connecthàm đã được chuyển đến chrome.runtimekhông gian tên. Xem câu trả lời của BJury (và nhận xét) để có phiên bản cập nhật hơn
Xan

115

Chrome hiện có khả năng gửi tin nhắn từ trang web tới tiện ích mở rộng.

Vì vậy, trong phần mở rộng background.js (content.js sẽ không hoạt động), hãy thêm một số thứ như:

chrome.runtime.onMessageExternal.addListener(
    function(request, sender, sendResponse) {
        if (request) {
            if (request.message) {
                if (request.message == "version") {
                    sendResponse({version: 1.0});
                }
            }
        }
        return true;
    });

Sau đó, điều này sẽ cho phép bạn thực hiện cuộc gọi từ trang web:

var hasExtension = false;

chrome.runtime.sendMessage(extensionId, { message: "version" },
    function (reply) {
        if (reply) {
            if (reply.version) {
                if (reply.version >= requiredVersion) {
                    hasExtension = true;
                }
            }
        }
        else {
          hasExtension = false;
        }
    });

Sau đó, bạn có thể kiểm tra biến hasExtension. Hạn chế duy nhất là cuộc gọi không đồng bộ, vì vậy bạn phải làm việc đó bằng cách nào đó.

Chỉnh sửa: Như đã đề cập bên dưới, bạn sẽ cần thêm một mục vào tệpkhai.json liệt kê các tên miền có thể nhắn tin cho tiện ích của bạn. Ví dụ:

"externally_connectable": {
    "matches": ["*://localhost/*", "*://your.domain.com/*"]
},

2
Công việc này như một cái duyên vậy. Một nhược điểm khác tất nhiên là bạn phải kiểm soát tiện ích mở rộng - bạn không thể sử dụng điều này để xem liệu tiện ích mở rộng của bên thứ ba có được cài đặt hay không.
Eric P

2
@EricP Câu hỏi ban đầu nói rằng họ đang viết phần mở rộng, vì vậy vấn đề đang được tranh luận.
BJury

11
Bạn cũng sẽ phải thêm thông tin sau vào tệp kê khai.json của mình: "externally_connectable": {"match": [" : // .yourdomain.com / *"]}
noname

3
Nó phải là {version: '1.0'} chứ không phải {version: 1.0}, nếu không bạn sẽ nhận được 'Uncaught SyntaxError: Số không mong muốn' trong tiện ích Kiểm tra bảng điều khiển chế độ xem.
ET-CS

1
Về phía "kiểm tra" (trang web đang cố gắng kiểm tra tính khả dụng của một tiện ích mở rộng nhất định), chrome.runtime là không xác định, chrome 36 trên linux.
truenice

22

Một phương pháp khác là hiển thị tài nguyên có thể truy cập web , mặc dù điều này sẽ cho phép bất kỳ trang web nào kiểm tra xem tiện ích mở rộng của bạn đã được cài đặt chưa.

Giả sử ID của tiện ích mở rộng của bạn là aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaavà bạn thêm một tệp (giả sử, một hình ảnh pixel trong suốt) như test.pngtrong các tệp của tiện ích mở rộng của bạn.

Sau đó, bạn hiển thị tệp này trên các trang web có web_accessible_resourceskhóa kê khai:

  "web_accessible_resources": [
    "test.png"
  ],

Trong trang web của mình, bạn có thể cố gắng tải tệp này bằng URL đầy đủ của nó (trong <img>thẻ, qua XHR hoặc theo bất kỳ cách nào khác):

chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/test.png

Nếu tệp tải, thì tiện ích mở rộng đã được cài đặt. Nếu có lỗi khi tải tệp này, thì tiện ích mở rộng chưa được cài đặt.

// Code from https://groups.google.com/a/chromium.org/d/msg/chromium-extensions/8ArcsWMBaM4/2GKwVOZm1qMJ
function detectExtension(extensionId, callback) { 
  var img; 
  img = new Image(); 
  img.src = "chrome-extension://" + extensionId + "/test.png"; 
  img.onload = function() { 
    callback(true); 
  }; 
  img.onerror = function() { 
    callback(false); 
  };
}

Lưu ý: nếu có lỗi xảy ra khi tải tệp này, lỗi ngăn xếp mạng đã nói sẽ xuất hiện trong bảng điều khiển và không có khả năng tắt tiếng nó. Khi Chromecast sử dụng phương pháp này, nó đã gây ra khá nhiều tranh cãi vì điều này; với giải pháp cuối cùng rất tệ hại là chỉ đưa vào danh sách đen các lỗi rất cụ thể từ Công cụ dành cho nhà phát triển bởi nhóm Chrome.


Lưu ý quan trọng: phương pháp này sẽ không hoạt động trong Firefox WebExtensions. Các tài nguyên có thể truy cập web vốn đã để tiện ích mở rộng lấy dấu vân tay, vì URL có thể dự đoán được bằng cách biết ID. Firefox đã quyết định đóng lỗ hổng đó bằng cách gán một URL ngẫu nhiên cho từng trường hợp cụ thể cho các tài nguyên có thể truy cập web:

Các tệp sau đó sẽ có sẵn bằng cách sử dụng URL như:

moz-extension://<random-UUID>/<path/to/resource>

UUID này được tạo ngẫu nhiên cho mọi phiên bản trình duyệt và không phải là ID của tiện ích mở rộng của bạn. Điều này ngăn các trang web lưu dấu lại các tiện ích mở rộng mà người dùng đã cài đặt.

Tuy nhiên, trong khi tiện ích mở rộng có thể sử dụng runtime.getURL()để lấy địa chỉ này, bạn không thể mã hóa nó trong trang web của mình.


Mặc dù câu trả lời này nhận được "nước ép" từ stackoverflow.com/a/9216924/1504300 , IMHO bổ sung một số thông tin khá quan trọng như hiển thị tài nguyên trong tiện ích mở rộng và thực tế là bạn có thể sử dụng yêu cầu ajax để kiểm tra sự tồn tại (Đối tượng hình ảnh dường như chỉ khả dụng trên HTML5 nếu tôi không nhầm goo.gl/HBeI1i ). Với thông tin trong câu trả lời này, tôi đã có thể giải quyết vấn đề, tôi thấy nó giống như một giải pháp "nằm ngoài hộp"
đẹp

@niconic Câu trả lời đó (dù sao cũng chỉ là liên kết) đề cập đến tình huống trước khi tệp kê khai phiên bản 2 có hiệu lực. Trước đây, người ta không cần khai báo tài nguyên có thể truy cập web.
Xan

19

Tôi nghĩ tôi sẽ chia sẻ nghiên cứu của tôi về điều này. Tôi cần có thể phát hiện xem một phần mở rộng cụ thể đã được cài đặt cho một số tệp: /// liên kết hoạt động hay không. Tôi đã xem qua bài viết này ở đây Bài viết này giải thích một phương pháp lấy tệp kê khai.json của một tiện ích mở rộng.

Tôi đã điều chỉnh mã một chút và nghĩ ra:

function Ext_Detect_NotInstalled(ExtName, ExtID) {
  console.log(ExtName + ' Not Installed');
  if (divAnnounce.innerHTML != '')
    divAnnounce.innerHTML = divAnnounce.innerHTML + "<BR>"

  divAnnounce.innerHTML = divAnnounce.innerHTML + 'Page needs ' + ExtName + ' Extension -- to intall the LocalLinks extension click <a href="https://chrome.google.com/webstore/detail/locallinks/' + ExtID + '">here</a>';
}

function Ext_Detect_Installed(ExtName, ExtID) {
  console.log(ExtName + ' Installed');
}

var Ext_Detect = function (ExtName, ExtID) {
  var s = document.createElement('script');
  s.onload = function () { Ext_Detect_Installed(ExtName, ExtID); };
  s.onerror = function () { Ext_Detect_NotInstalled(ExtName, ExtID); };
  s.src = 'chrome-extension://' + ExtID + '/manifest.json';
  document.body.appendChild(s);
}

var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;

if (is_chrome == true) {
  window.onload = function () { Ext_Detect('LocalLinks', 'jllpkdkcdjndhggodimiphkghogcpida'); };
}

Với điều này, bạn sẽ có thể sử dụng Ext_Detect (ExtensionName, ExtensionID) để phát hiện việc cài đặt bất kỳ số lượng tiện ích mở rộng nào.


2
Có vẻ như Google đã làm mọi thứ an toàn hơn, tôi gặp lỗi sau khi chạy Ext_Detect (): Từ chối tải chrome-extension: // [my_extension_id] /manifest.json. Các tài nguyên phải được liệt kê trong khóa kê khai web_accessible_resources để được tải bởi các trang bên ngoài tiện ích.
Lounge 9

Tôi có thể làm cho điều này hoạt động với Phiên bản 32.0.1700.107 m của Chrome kể từ
JE Carter II

1
như @ Lounge9 đã nói. Tài nguyên bên trong các gói sử dụng tệp kê khai 2 (hoặc cao hơn) bị chặn theo mặc định và phải được đưa vào danh sách trắng để sử dụng qua thuộc tính này bằng cách thêm vào tệp kê khai.json: "web_accessible_resources": ["tệp kê khai..json"],
ET-CS

Sử dụng câu trả lời @BJury, bạn cũng có thể chuyển dữ liệu dễ dàng từ tiện ích mở rộng sang tập lệnh (ví dụ: phiên bản tiện ích mở rộng) và bạn không cần để lộ bất kỳ tệp nào từ tiện ích mở rộng.
ET-CS

1
Điều này phù hợp nhất với tôi vì tiện ích mở rộng của chúng tôi sẽ được sử dụng trên nhiều miền và không thể được xác định trước khi các miền mới được thêm thường xuyên. Thay vì truy cập vào tệp kê khai.json, tôi đã tạo một tệp tin version.json mới và đặt số phiên bản vào bên trong. Điều này hoạt động giống nhau.
Paul Haggo

7

Một giải pháp khả thi khác nếu bạn sở hữu trang web là sử dụng cài đặt nội tuyến .

if (chrome.app.isInstalled) {
  // extension is installed.
}

Tôi biết đây là một câu hỏi cũ nhưng cách này đã được giới thiệu trong Chrome 15 và vì vậy tôi nghĩ rằng Id liệt kê nó chỉ dành cho bất kỳ ai bây giờ đang tìm kiếm câu trả lời.


12
Điều này hoạt động tốt cho Ứng dụng Chrome , nhưng không phù hợp với Tiện ích mở rộng của Chrome AFAIK
Eran Medan

Đúng vậy, trang web đó cho bạn biết cách cài đặt nội tuyến một tiện ích mở rộng, nhưng dường như khuyến nghị "Tiện ích mở rộng có thể giao tiếp với trang nhúng thông qua tập lệnh nội dung để cho nó biết rằng chúng đã được cài đặt." thay vì có thể sử dụng chrome.app.isInstalled. Làm tôi bối rối quá ...
rogerdpack


4

Tôi đã sử dụng phương pháp cookie:

Trong tệp kê khai.js của tôi, tôi đã bao gồm một tập lệnh nội dung chỉ chạy trên trang web của tôi:

 "content_scripts": [
        {
        "matches": [
            "*://*.mysite.co/*"
            ],
        "js": ["js/mysite.js"],
        "run_at": "document_idle"
        }
    ], 

trong js / mysite.js của tôi, tôi có một dòng:

document.cookie = "extension_downloaded=True";

và trong trang index.html của tôi, tôi tìm cookie đó.

if (document.cookie.indexOf('extension_downloaded') != -1){
    document.getElementById('install-btn').style.display = 'none';
}

Tôi đã thử tất cả các giải pháp ở trên nhưng không hoạt động, sau đó tôi thấy câu trả lời của bạn, đây là những gì tôi đang tìm kiếm!
John Doe

Điều này thêm chi phí cho mọi yêu cầu HTTP kể từ đó.
mlissner

3

Bạn có thể đặt tiện ích mở rộng một cookie và yêu cầu JavaScript trang web của bạn kiểm tra xem cookie đó có xuất hiện hay không và cập nhật cho phù hợp. Điều này và có lẽ là hầu hết các phương pháp khác được đề cập ở đây tất nhiên có thể được người dùng phát hiện, trừ khi bạn thử và để tiện ích mở rộng tạo cookie tùy chỉnh tùy thuộc vào dấu thời gian, v.v. và yêu cầu ứng dụng của bạn phân tích chúng phía máy chủ để xem liệu đó có thực sự là người dùng với tiện ích mở rộng hoặc ai đó giả vờ có nó bằng cách sửa đổi cookie của mình.


5
vấn đề duy nhất là nếu người dùng xóa tiện ích mở rộng của bạn. Cookie có thể sẽ vẫn được thiết lập.
Chase Roberts vào

3

Có một phương pháp khác được hiển thị tại bài đăng trên Google Groups này . Tóm lại, bạn có thể thử phát hiện xem biểu tượng tiện ích mở rộng có tải thành công hay không. Điều này có thể hữu ích nếu tiện ích mở rộng bạn đang kiểm tra không phải của riêng bạn.


1
Đồng ý. Làm cách nào để kiểm tra xem biểu tượng tiện ích mở rộng có tồn tại hay không?
Michael Rogers

3

Trang web tương tác với tiện ích mở rộng thông qua tập lệnh nền.

manifest.json:

"background": {
    "scripts": ["background.js"],
    "persistent": true
},
"externally_connectable": {
    "matches": ["*://(domain.ext)/*"]
},

background.js:
chrome.runtime.onMessageExternal.addListener(function(msg, sender, sendResponse) {
    if ((msg.action == "id") && (msg.value == id))
    {
        sendResponse({id : id});
    }
});

page.html:

<script>
var id = "some_ext_id";
chrome.runtime.sendMessage(id, {action: "id", value : id}, function(response) {
    if(response && (response.id == id)) //extension installed
    {
        console.log(response);
    }
    else //extension not installed
    {
        console.log("Please consider installig extension");
    }

});
</script>

Không hoạt động trên Firefox WebExtensions, nơi không hỗ trợ externally_connectable.
mlissner

3

Tiện ích của bạn có thể tương tác với trang web (ví dụ: thay đổi các biến) và trang web của bạn có thể phát hiện ra điều này.

Nhưng cần có một cách tốt hơn để làm điều này. Tôi tự hỏi Google đang làm điều đó như thế nào trên thư viện tiện ích mở rộng của họ (các ứng dụng đã được cài đặt được đánh dấu).

Biên tập:

Thư viện sử dụng chức năng chrome.management.get . Thí dụ:

chrome.management.get("mblbciejcodpealifnhfjbdlkedplodp", function(a){console.log(a);});

Nhưng bạn chỉ có thể truy cập phương pháp từ các trang có quyền phù hợp.


1
ngươi mà sẽ đòi hỏi mở rộng để tương tác với tất cả các trang web trên mỗi tab đó sẽ là chậm / khó thực hiện và buggy: - /

Vấn đề là không thể liên lạc theo hướng khác (từ trang đến phần mở rộng), do mô hình bảo mật của chrome. Nếu bạn không muốn đi theo cách 'tương tác', hãy sử dụng cách cookie.
Fox32

2
Kính gửi @ Fox32, chrome.management.get ..., trả lại lỗi này:Uncaught TypeError: Cannot read property 'get' of undefined
Hosein Aqajani

3

Rất nhiều câu trả lời ở đây cho đến nay là chỉ dành cho Chrome hoặc phải chịu hình phạt phí HTTP. Giải pháp mà chúng tôi đang sử dụng hơi khác một chút:

1. Thêm một đối tượng mới vào danh sách content_scripts của tệp kê khai như sau:

{
  "matches": ["https://www.yoursite.com/*"],
  "js": [
    "install_notifier.js"
  ],
  "run_at": "document_idle"
}

Điều này sẽ cho phép mã trong install_notifier.js chạy trên trang web đó (nếu bạn chưa có quyền ở đó).

2. Gửi tin nhắn đến mọi trang web trong khóa kê khai ở trên.

Thêm một cái gì đó như thế này vào install_notifier.js (lưu ý rằng điều này đang sử dụng một bao đóng để giữ cho các biến khỏi toàn cục, nhưng điều đó không hoàn toàn cần thiết):

// Dispatch a message to every URL that's in the manifest to say that the extension is
// installed.  This allows webpages to take action based on the presence of the
// extension and its version. This is only allowed for a small whitelist of
// domains defined in the manifest.
(function () {
  let currentVersion = chrome.runtime.getManifest().version;
  window.postMessage({
    sender: "my-extension",
    message_name: "version",
    message: currentVersion
  }, "*");
})();

Tin nhắn của bạn có thể nói bất cứ điều gì, nhưng sẽ hữu ích khi gửi phiên bản để bạn biết mình đang giải quyết vấn đề gì. Sau đó...

3. Trên trang web của bạn, hãy lắng nghe thông điệp đó.

Thêm cái này vào trang web của bạn ở đâu đó:

window.addEventListener("message", function (event) {
  if (event.source == window &&
    event.data.sender &&
    event.data.sender === "my-extension" &&
    event.data.message_name &&
    event.data.message_name === "version") {
    console.log("Got the message");
  }
});

Tính năng này hoạt động trên Firefox và Chrome và không phát sinh chi phí HTTP hoặc thao tác trang.


0

Nếu bạn có quyền kiểm soát tiện ích mở rộng Chrome, bạn có thể thử những gì tôi đã làm:

// Inside Chrome extension
var div = document.createElement('div');
div.setAttribute('id', 'myapp-extension-installed-div');
document.getElementsByTagName('body')[0].appendChild(div);

Và sau đó:

// On web page that needs to detect extension
if ($('#myapp-extension-installed-div').length) {

}

Có vẻ hơi khó hiểu, nhưng tôi không thể làm cho các phương pháp khác hoạt động và tôi lo lắng về việc Chrome sẽ thay đổi API của nó ở đây. Có thể nghi ngờ rằng phương pháp này sẽ sớm ngừng hoạt động.


như đã đề cập ở trên- Tôi đã thử nghiệm điều này nhưng thứ tự hoạt động có vẻ lạ- tập lệnh nào được chạy trước, v.v.?
Brady Moritz

0

Bạn cũng có thể sử dụng phương pháp trình duyệt chéo mà tôi đã sử dụng. Sử dụng khái niệm thêm một div.

trong tập lệnh nội dung của bạn (bất cứ khi nào tập lệnh tải, nó sẽ thực hiện việc này)

if ((window.location.href).includes('*myurl/urlregex*')) {
        $('html').addClass('ifextension');
        }

trong trang web của bạn, bạn khẳng định điều gì đó như,

if (!($('html').hasClass('ifextension')){}

Và ném thông điệp thích hợp.


Tôi đã thử nghiệm điều này nhưng thứ tự hoạt động có vẻ lạ - tập lệnh nào được chạy trước, v.v.?
Brady Moritz

@BradyMoritz thứ tự tương tự như trong câu trả lời. Thêm lớp đầu tiên và sau đó khẳng định.
Prakash Palnati

Có vẻ như kịch bản nội dung của tôi không nhất thiết phải chạy trước tập lệnh trong trang của tôi?
Brady Moritz

Điều đó, tôi nghĩ là dễ sửa chữa. Bạn có thể đảm bảo rằng tập lệnh nội dung của mình sẽ chạy ngay sau khi truy cập URL / tuyến đường được yêu cầu bằng cách sử dụng regex. Bạn đã thử chưa?
Prakash Palnati

0

Nếu bạn đang cố gắng phát hiện bất kỳ tiện ích mở rộng nào từ bất kỳ trang web nào, thì bài đăng này đã giúp: https://ide.hey.network/post/5c3b6c7aa7af38479accc0c7

Về cơ bản, giải pháp sẽ chỉ là cố gắng lấy một tệp cụ thể (tệp kê khai.json hoặc hình ảnh) từ tiện ích mở rộng bằng cách chỉ định đường dẫn của nó. Đây là những gì tôi đã sử dụng. Chắc chắn làm việc:

const imgExists = function(_f, _cb) {
    const __i = new Image();
    __i.onload = function() {
        if (typeof _cb === 'function') {
            _cb(true);
        }
    }
    __i.onerror = function() {
        if (typeof _cb === 'function') {
            _cb(false);
        }
    }
    __i.src = _f;
    __i = null;
});

try {
    imgExists("chrome-extension://${CHROME_XT_ID}/xt_content/assets/logo.png", function(_test) {
        console.log(_test ? 'chrome extension installed !' : 'chrome extension not installed..');
        ifrm.xt_chrome = _test;
        // use that information
    });
} catch (e) {
    console.log('ERROR', e)
}

0

Đây là một cách tiếp cận hiện đại khác:

const checkExtension = (id, src, callback) => {
    let e = new Image()
    e.src = 'chrome-extension://'+ id +'/'+ src
    e.onload = () => callback(1), e.onerror = () => callback(0)
}

// "src" must be included to "web_accessible_resources" in manifest.json
checkExtension('gighmmpiobklfepjocnamgkkbiglidom', 'icons/icon24.png', (ok) => {
    console.log('AdBlock: %s', ok ? 'installed' : 'not installed')
})
checkExtension('bhlhnicpbhignbdhedgjhgdocnmhomnp', 'images/checkmark-icon.png', (ok) => {
    console.log('ColorZilla: %s', ok ? 'installed' : 'not installed')
})
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.