جافاسكريبت - اكتشف ما إذا كانت وحدة تحكم كروم مفتوحة


أنا أستخدم هذا السكربت الصغير لمعرفة ما إذا كان Firebug مفتوحًا:

if (window.console && window.console.firebug) {
    //is open
};

ويعمل بشكل جيد. الآن كنت أبحث لمدة نصف ساعة لأجد طريقة لاكتشاف ما إذا كان وحدة تحكم مطوري الويب المدمجة في جوجل كروم مفتوحة، لكنني لم أتمكن من العثور على أي دليل.

هذا :

if (window.console && window.console.chrome) {
    //is open
};

لا يعمل.

تحرير :

يبدو أنه من غير الممكن اكتشاف ما إذا كانت وحدة تحكم Chrome مفتوحة. لكن هناك "خدعة" تعمل، مع بعض العيوب:

  • لن يعمل عندما تكون وحدة التحكم مفصولة
  • لن يعمل عندما تكون وحدة التحكم مفتوحة عند تحميل الصفحة

لذلك، سأختار الآن إجابة Unsigned، ولكن إذا جاء شخص ما بفكرة رائعة، فهو مرحب به للإجابة وسأغير الإجابة المختارة! شكراً!

الإجابة رقم 1

ترك الإجابات السابقة أدناه للسياق التاريخي.

مصحح الأخطاء (2022)

على الرغم من أنه ليس مضمونًا تمامًا، إلا أن هذا النهج القائم على المُصحح في إجابة أخرى يبدو أنه لا يزال يعمل.

requestAnimationFrame (أواخر 2019)

يعمل نهج محمد عمر حاليًا على متصفح كروم 78، مع الميزة الإضافية لاكتشاف كل من أحداث الإغلاق والفتح.

دالة toString (2019)

الفضل لتعليق Overcl9ck على هذا الجواب. استبدال التعابير النمطية /./ بكائن دالة فارغ لا يزال يعمل.

var devtools = function() {};
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

تعابير نمطية toString (2017-2018)

نظرًا لأن الشخص الذي طرح السؤال الأصلي يبدو أنه لم يعد متواجدًا بعد الآن، وهذا ما زال الجواب المقبول، فإن إضافة هذا الحل لزيادة الرؤية. الفضل يعود لتعليق أنتونين هيلديبراند على إجابة zswang. يستفيد هذا الحل من حقيقة أن toString() لا يتم استدعاؤه على الكائنات المسجلة إلا إذا كان الكونسول مفتوحًا.

var devtools = /./;
devtools.toString = function() {
  if (!this.opened) {
    alert("Opened");
  }
  this.opened = true;
}

console.log('%c', devtools);
// devtools.opened will become true if/when the console is opened

console.profiles (2013)

تحديث: console.profiles تم إزالته من Chrome. هذا الحل لم يعد يعمل.

شكراً لبول إيريش لإشارته إلى هذا الحل من Discover DevTools، باستخدام المُحلل:

function isInspectOpen() {
  console.profile();
  console.profileEnd();
  if (console.clear) {
    console.clear();
  }
  return console.profiles.length > 0;
}
function showIfInspectIsOpen() {
  alert(isInspectOpen());
}
<button onClick="showIfInspectIsOpen()">Is it open?</button>

window.innerHeight (2011)

يمكن لهذا الخيار الآخر اكتشاف فاحص العناصر المثبت عند فتحه، بعد تحميل الصفحة، لكنه لن يكون قادرًا على اكتشاف فاحص العناصر غير المثبت، أو إذا كان الفاحص مفتوحًا بالفعل عند تحميل الصفحة. هناك أيضًا احتمال لوجود نتائج إيجابية خاطئة.

window.onresize = function() {
  if ((window.outerHeight - window.innerHeight) > 100) {
    alert('Docked inspector was opened');
  }
}

الإجابة رقم 2

كروم 65+ (2018)

    r = /./
    r.toString = function () {
        document.title = '1'
    }
    console.log('%c', r);

عرض تجريبي: https://jsbin.com/cecuzeb/edit?output (تم التحديث في 2018-03-16)

الحزمة: https://github.com/zswang/jdetects


عند طباعة "العنصر" ستقوم أدوات مطوري كروم بالحصول على معرفه

    var checkStatus;
    
    var element = document.createElement('any');
    element.__defineGetter__('id', function() {
        checkStatus = 'on';
    });
    
    setInterval(function() {
        checkStatus = 'off';
        console.log(element);
        console.clear();
    }, 1000);

نسخة أخرى (من التعليقات)

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function () {
    /* TODO */
    alert('囧');
  }
});
console.log('%cHello', element);

اطبع متغيرًا عاديًا:

    var r = /./;
    r.toString = function() {
      document.title = 'on';
    };
    console.log(r);

الإجابة رقم 3

اختراق موثوق جدًا

بشكل أساسي، اضبط دالة getter على الخاصية وسجلها في وحدة التحكم. على ما يبدو، يتم الوصول إلى الشيء فقط عندما تكون وحدة التحكم مفتوحة.

https://jsfiddle.net/gcdfs3oo/44/

var checkStatus;
var indicator = document.querySelector('#devtool-status');

var element = new Image();
Object.defineProperty(element, 'id', {
  get: function() {
    checkStatus='on';
    throw new Error("Dev tools checker");
  }
});

requestAnimationFrame(function check() {
  checkStatus = 'off';
  console.dir(element);
  indicator.className  = checkStatus;
  requestAnimationFrame(check);
});
.on{
  color:limegreen;
}

.off{
  color:red;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.7.1/css/all.css" integrity="sha256-DVK12s61Wqwmj3XI0zZ9MFFmnNH8puF/eRHTB4ftKwk=" crossorigin="anonymous" />

<p>
  <ul>
    <li>
      dev toolbar open: icon is <span class="on">green</span>
    </li>
    <li>
      dev toolbar closed: icon is <span class="off">red</span>
    </li>
  </ul>
</p>
<div id="devtool-status"><i class="fas fa-7x fa-power-off"></i></div>
<br/>
<p><b>Now press F12 to see if this works for your browser!</b></p>

الإجابة رقم 4

لقد أنشأت devtools-detect الذي يكتشف متى تكون أدوات المطور مفتوحة:

console.log('is DevTools open?', window.devtools.open);

يمكنك أيضًا الاستماع إلى حدث:

window.addEventListener('devtoolschange', function (e) {
    console.log('is DevTools open?', e.detail.open);
});

لا يعمل عندما تكون أدوات المطور مفصولة. ومع ذلك، يعمل مع أدوات مطور Chrome/Safari/Firefox وFirebug.

الإجابة رقم 5

console.log(Object.defineProperties(new Error, {
  message: {get() {alert('Chrome/Firefox')}},
  toString: {value() {(new Error).stack.includes('toString@')&&alert('Safari')}}
}));

عرض توضيحي: https://jsbin.com/cateqeyono/edit?html,output

الإجابة رقم 6


------ تحديث: ------

هذا سؤال قديم مع العديد من الإجابات الرائعة التي كانت تعمل لفترة من الوقت. أفضل إجابة حالية حتى 5 سبتمبر 2022 هي من @starball https://stackoverflow.com/a/68494829/275333

بالمناسبة، جوابي لا يزال يعمل بنفس الطريقة منذ أن نشرته، من الصعب فقط أن يكون دائمًا دقيقًا. انقر على رابط "القياس اليدوي" في العرض التجريبي الخاص بي مع إغلاق/فتح وحدة التحكم لتفهم ما أعنيه - هناك دائمًا فرق كبير.

----------------------

وجدت طريقة لمعرفة ما إذا كانت وحدة تحكم كروم مفتوحة أم لا. لا تزال خدعة لكنها أكثر دقة بكثير وستعمل سواء كانت وحدة التحكم مفصولة أم لا.

بشكل أساسي، تشغيل هذا الكود مع إغلاق وحدة التحكم يستغرق حوالي ~100 ميكروثانية، بينما عند فتح وحدة التحكم يستغرق حوالي ضعف ذلك ~200 ميكروثانية.

console.log(1);
console.clear();

(1 ملي ثانية=1000 ميكرو ثانية)

لقد كتبت المزيد عنه هنا.

العرض التوضيحي هنا.

الإجابة رقم 7

يبدو أن هناك بعض الفئات الشائعة من الحلول:

  • اعتمد على اكتشاف تغيير حجم الشاشة عند ظهور أدوات المطور (هذا لا يعمل عندما يتم فتح أدوات المطور/الكونسول في نافذة منفصلة)
  • اعترض بعض إجراءات المستخدم التي يمكن أن تفتح أدوات المطور/وحدة التحكم مثل قائمة النقر بزر الماوس الأيمن، F12، Ctrl+Shift+C، إلخ. لا يمكن لهذا أن يغطي آليات واجهة المستخدم الموجودة في شريط المتصفح والتي لا يمكن للصفحة اكتشافها.
  • سجّل شيء في وحدة التحكم واعتمد على سلوك المتصفح المحدد للطباعة الكسولة والفاخرة. تاريخيًا، يبدو أن هذه الطريقة ليست موثوقة جدًا، لكنها لطيفة وبسيطة. إذا كنت تريد أن تعمل مرارًا وتكرارًا في نفس جلسة التصفح، فربما سيتعين عليك قبول بعض الرسائل المزعجة في وحدة التحكم. هذا لا يعمل عندما يقوم المستخدم بتعطيل جميع مستويات التسجيل في وحدة تحكم أدوات المطور لديه ثم يقوم بالتحديث، وبالنسبة لسياقات التنفيذ الخاصة بالأول، يمكن أن يتم إحباط ذلك عن طريق إعادة تعريف وظائف وحدة التحكم في برنامج المستخدم (بالنسبة لسياقات تنفيذ البرامج النصية الخاصة بأطراف ثالثة، لم أكتشف بعد كيفية القيام بذلك باستخدام برنامج المستخدم).
  • استخدم تقييمات التوقيت مع عبارة debugger. الجزء الصعب هو إيجاد طريقة بحيث لا تتأثر المؤقتات بالمهام الطويلة في قائمة انتظار حلقة الحدث، وحقيقة أن عبارة debugger توقف تنفيذ الخيط الذي تعمل عليه. هناك أيضًا تحدٍ يتمثل في أن عبارات debugger العادية يمكن تعطيلها من قبل المستخدم على أساس كل حالة على حدة أو على أساس تعطيل الكل.

ما يلي هو حلي للمشكلات المحددة المتعلقة بأسلوب debugger. أي تجنب النتائج الإيجابية الخاطئة عندما يقوم الخيط الرئيسي بتنفيذ مهمة طويلة بين مؤقت استدلالي، وتجنب أن يقوم بيان debugger بحظر الخيط الرئيسي، ومنع تعطيل بيان debugger. ملاحظة: لا أعتقد أن هناك طريقة لمنع المستخدم من تعطيل جميع نقاط توقف debugger، وربما هذا هو الأفضل.

كيف يعمل

يدخل متصفح كروم وضع التصحيح عندما تكون أدوات المطور مفتوحة وتواجه إحدى الخيوط بيان تصحيح.

  1. الخيط الرئيسي يرسل رسالة إلى خيط عامل الويب.
  2. ترد خيط العمل بنبضة قلب افتتاحية.
  3. يتفاعل الخيط الرئيسي ببدء مؤقت لتوقع إغلاق إشارة النبض.
  4. يتعامل معالج رسائل خيط العامل مع بيان مصحح الأخطاء (يمكن أن يكون ملفوفًا اختياريًا ببيان eval لمنع المستخدم من تعطيله).
  5. إذا تم إغلاق أدوات المطورين، فسيرسل العامل على الفور تأكيدًا إلى الخيط الرئيسي، وسيستنتج الخيط الرئيسي أن أدوات المطورين مغلقة.
  6. إذا تم فتح أدوات المطورين، سيدخل العامل في جلسة تصحيح الأخطاء، وسيتلاحظ الخيط الرئيسي أن العامل لم يستجب بسرعة كافية، مما يؤدي إلى استنتاج أن مصحح الأخطاء يجب أن يكون مفتوحًا. لن يتم حظر الخيط الرئيسي بواسطة جلسة تصحيح الأخطاء للعامل، لكن استجابة مهلة الوقت الخاصة به سيتم حظرها بواسطة أي معالجة كثيفة في الخيط الرئيسي قبلها في قائمة أحداث الانتظار.

لقد نشرت تنفيذًا مرجعيًا (بقلمي) هنا على GitHub، وعرضًا توضيحيًا هنا.

إيجابيات

  • على عكس أساليب كشف تغيير حجم الشاشة، يعمل هذا عندما تكون وحدة التحكم في نافذة منفصلة.
  • على عكس أساليب اعتراض إجراءات المستخدم، يعمل هذا بغض النظر عن الإجراء الذي يقوم به المستخدم لفتح وحدة التحكم.
  • على عكس أساليب console.log، يمكن لهذا أن يعمل لعدة فتحات وإغلاقات للكونسول دون إغراق الكونسول بالرسائل.
  • على عكس أساليب المؤقت-المصحح الأساسية، يجب ألا يؤدي الكشف أبدًا إلى إيجابيات كاذبة بسبب الخيوط المشغولة (الخيط الرئيسي، أو العمال الآخرين)، بيان المصحح موجود في العامل بدلاً من الخيط الرئيسي، لذلك لن يتم حظر الخيط الرئيسي، وبيان eval-debugger يمنع تعطيل هذا البيان المحدد للمصحح.

سلبيات

  • يمكن للمستخدم تعطيل جميع نقاط التوقف، مما سيعطل هذه الطريقة من الكشف.
  • لن تعمل عبارة المُصحح المغلفة بـ eval على المواقع التي تعطل eval عبر سياسة أمان المحتوى الخاصة بها، وفي هذه الحالة يمكن استخدام عبارة المُصحح العادية فقط.