Pull to refresh

Расширения для Opera: Обмен сообщениями

Reading time8 min
Views2.7K
Original author: Shwetank Dixit

Вступление


С помощью расширений вы можете создавать и добавлять новую впечатляющую функциональность в браузер Opera. Как было упомянуто в других статьях, расширения для Opera содержат фоновый скрипт, внедряемый скрипт и, иногда, всплывающее окно. В этой статье мы рассмотрим, как обеспечить обмен данными между тремя этими компонентами.

Прежде чем продолжить, вы должны скачать три расширения и установить их в браузер Opera 11 alpha. Мы будем рассматривать тему с помощью кода этих расширений.
  1. Пример расширения, демонстрирующего обмен данными между фоновым и внедряемым скриптами
  2. Пример расширения, демонстрирующего обмен данными между фоновым скриптом и всплывающим окном
  3. Пример расширения, демонстрирующего обмен данными между всплывающим окном и внедряемым скриптом (с небольшой помощью фонового скрипта)

Обмен данными между фоновым и внедряемым скриптами


Opera использует метод postMessage() для отправки сообщения. Если вы хотите отправить данные из фонового скрипта во внедряемый скрипт, то нужно написать следующий код в фоновом скрипте:

opera.extension.broadcastMessage("Hello there");

После того, как вы послали сообщение, внедряемый скрипт должен принять его, что может быть сделано следующим образом:

var thecatch;
  opera.extension.onmessage = function(event) {
    thecatch = event.data; // event.data в данном случае будет содержать строку "Hello there"
  }
}

Вот так всё просто. В указанном выше коде, фоновый скрипт отправляет данные внедряемому скрипту, используя метод broadcastMessage, и внедряемый скрипт принимает их. После получения данных, он сохраняет их в переменной thecatch. Необходимо помнить, что используя метод broadcastMessage, вы посылаете сообщение всем внедряемым скриптам и всплывающим окнам, поэтому необходимо использовать этот метод экономно. Обычно, вам необходимо связаться лишь с одним всплывающим окном или внедрённым скриптом (тем, который содержится именно в вашем расширении) используя метод postMessage или каналы сообщений.

Продемонстрируем это с помощью нашего первого тестового примера.

Фоновый скрипт имеет перехватчик события load, который вызывает функцию setupConnection. Вы можете наблюдать вывод метода opera.postError в Error Console (Tools > Advanced > Error Console).

window.addEventListener("load", setupConnection, false);

function setupConnection()
{
   // Когда внедряемый скрипт активируется, он связывается с фоновым скриптом
   opera.extension.onconnect = function(event) {
        // Отправляем сообщение источнику, который связывается с нами (в данном случае это внедряемый скрипт)
 	event.source.postMessage("something"); 
        // Отправляем уведомление в Error Console
	opera.postError("sent message to injected script");
   }

   // Перехватываем сообщения                
   opera.extension.onmessage = function(event){
       	// Отправляем уведомление (которое содержит полученное сообщение) в Error Console
       opera.postError("This is what I got from injected script: "+event.data);
   }
}

Обратим внимание на следующий код:

opera.extension.onconnect = function(event) {
   event.source.postMessage("something");
   opera.postError("sent message to injected script");
}

Метод onconnect выполняется в момент, когда внедряемый скрипт расширения активируется в документе, соединяя его с фоновым скриптом. То есть, как только внедряемый скрипт загружается, метод onconnect выполняется.

Обработчик onconnect в фоновом скрипте получает обратную ссылку на внедряемый скрипт через объект event.source. Этот порт сообщений может быть использован для прямой связи с внедряемым скриптом, что демонстрируется отправкой строки «something» с помощью метода event.source.postMessage(). Попутно мы шлём небольшое уведомление в Error Console для отслеживания происходящего.

Оставим фоновый скрипт на время и обратим своё внимание на внедряемый скрипт:

opera.extension.onmessage = function(event){
  // Получаем содержимое входящего сообщения.
  var message  = event.data;
  opera.postError("Background script sent: " + message);

  //  Шлём обратный ответ.
  var reply = "Background script's message only had " + (message ? message.length : 0) + " characters.";
  event.source.postMessage(reply); 
};

Метод onmessage вызывается в момент получения внедряемым скриптом сообщения. Мы сохраняем содержимое сообщения в переменной message. Затем мы используем метод opera.postError для отправки уведомления в Error Console.

Чтобы подтвердить получение сообщения, мы шлём обратный ответ фоновому скрипту, используя объект event.source. Запомните: event.source всегда указывает на источник сообщения.

Итак, теперь мы увидели, как сообщения принимаются внедряемым скриптом и как может быть отправлен ответ фоновому скрипту.

Следующий шаг это приём сообщения фоновым скриптом и его обработка. Вернёмся снова к фоновому скрипту и посмотрим на другой участок кода:

// Перехватываем сообщения                
   opera.extension.onmessage = function(event){
       	// Отправляем запись (которая содержит полученное сообщение) в Error Console
       opera.postError("This is what I got from injected script: "+event.data);
   }

Здесь, в момент получения сообщения, скрипт отсылает в Error Console уведомление о его получении вместе с содержимым сообщения.

Итого, вот что происходит в расширении:
  • Фоновый скрипт шлёт сообщение внедряемому скрипту
  • Внедряемый скрипт получает сообщение и отправляет уведомление с содержимым сообщения в Error Console
  • Внедряемый скрипт шлёт обратный ответ
  • Фоновый скрипт получает ответ и отправляет уведомление с содержимым ответа в Error Console

Если вы установили расширение (обновите страницу, чтобы внедряемый скрипт применился), то отправляйтесь в Error Console. Вы должны увидеть сообщения, показанные на Рис. 1:
image
Рисунок 1: Error Console и уведомления, посланные в неё из расширения.

Мы рассмотрели, как фоновый и внедряемый скрипты могут принимать и отправлять сообщения. Теперь разберём, как можно сделать это со всплывающим окном.

Обмен сообщениями между всплывающим окном и фоновым скриптом


Мы будем использовать второй пример расширения для этой главы. Обратите внимание, что в нём нет папки includes и внедряемого скрипта — это лишь фоновый скрипт, html-файлы, config.xml и иконка.

Из предыдущих статей вы уже знаете, как создать UI-элемент, например кнопку, так что мы не будет заострять на этом наше внимание. Давайте посмотрим на следующий код в background.js:

opera.extension.onconnect = function(event){
  event.source.postMessage("sending something");
  opera.postError("sent message to popup");
}

Как мы знаем из предыдущего примера, этот код будет выполнен, когда что-нибудь свяжется с фоновым скриптом, в данном случае это всплывающее окно. Функция шлёт сообщение «sending something» всплывающему окну и уведомление «Sent message to popup» в Error Console.

Теперь посмотрим на страницу всплывающего окна:

<script>
    window.addEventListener("load", function(){
    opera.extension.onmessage = function(event){
    	event.source.postMessage("do whatever you want with this message");
    	opera.postError("sent from popup to background script");
    	}
    }, false);
</script>

Здесь мы перехватываем входящее сообщение и шлём обратный ответ источнику. Так же мы, как обычно, отправляем уведомление в Error Console. Теперь всплывающее окно принимает сообщение и шлёт ответ фоновому скрипту. Осталось только получить этот ответ в фоновом скрипте.

Снова отправляемся в background.js и смотрим код:

opera.extension.onmessage = function(event){
   opera.postError("This is what I got from injected script: " + event.data);
}

Здесь фоновый скрипт перехватывает сообщение и отправляет в Error Console уведомление с содержимым сообщения. Как видите, мы можем использовать тот же код, что и для внедряемого скрипта.

Итого, вот что происходит в расширении:
  • Фоновый скрипт шлёт сообщение всплывающему окну
  • Всплывающее окно получает сообщение и отправляет уведомление с содержимым сообщения в Error Console
  • Всплывающее окно шлёт обратный ответ
  • Фоновый скрипт получает ответ и отправляет уведомление с содержимым ответа в Error Console

Всё происходит точно также, как и в предыдущем примере, лишь с той разницей, что у нас нет внедряемого скрипта, и мы связываемся со всплывающим окном.

Если вы установили расширение, то нажмите на его кнопку на панели браузера чтобы запустить обмен сообщениями и откройте Error Console, чтобы увидеть показанное на Рис. 2:
image
Рисунок 2: Error Console и уведомления, посланные в неё из расширения.

Обмен сообщениями между всплывающим окном и внедряемым скриптом


Теперь давайте разберём, как обмениваться данными между всплывающим окном и внедряемым скриптом. Фоновый скрипт будет использован только для инициализации соединения, затем всплывающее окно и внедряемый скрипт будут общаться напрямую.

Мы можем достичь этого, создав канал связи. Вы можете узнать больше о каналах связи в спецификации кросс-документного обмена сообщениями в HTML5, на которой основывается обмен сообщениями в расширениях.

Мы рассмотрим это с помощью третьего примера расширения, так что запускайте свой текстовый редактор и посмотрим на код. В первый очередь, взглянем на фоновый скрипт. Вы заметите знакомые элементы, например добавление кнопки и всплывающего окна. Опустимся к более интересному участку.

Вначале, мы определяем глобальную переменную port, которую будем использовать позже. Посмотрим на обработчик onconnect:

opera.extension.onconnect = function( event ){
  if( port )
    event.source.postMessage( "Respond to the port", [port] );
}

В момент подключения к фоновому скрипту, он отправит сообщение 'Respond to the port'. Мы указываем порт для отправки сообщения, но так как переменная port ещё не имеет значения, то сообщение будет отправлено как оно есть.

Теперь поглядим на внедряемый скрипт:

var channel = new MessageChannel();
opera.extension.postMessage( "Respond to this immediately", [channel.port2] );

Здесь мы создаём новый канал сообщений. Канал сообщений будет иметь два порта, и данные могут быть отправлены и получены через эти два порта. Здесь мы отправляем данные через второй порт и получаем через первый. Затем мы отправляем сообщение, используя метод postMessage(), через второй порт канала сообщений.

Вернёмся к фоновому скрипту:

opera.extension.onmessage = function( event ) {
if (event.ports)
  port = event.ports[0];
}

Фоновый скрипт принимает сообщение от внедряемого скрипта. Теперь ссылка на второй порт канала доступна через объект event.ports[0] и сохраняется в переменной port. Теперь фоновый скрипт готов для подключения всплывающего окна. Когда это произойдёт, метод onconnect вызывается вновь:

opera.extension.onconnect = function( event ){
  if( port ){
    event.source.postMessage( "Respond to the port", [port] );
  }
}

Теперь, значение переменной port не пусто. Оно содержит ссылку на порт канала сообщений.

Посмотрим на файл всплывающего окна:

opera.extension.onmessage = function( event ){
  if( event.ports ){
    opera.postError( "Responding to port" );
    event.ports[0].postMessage( "Hi from popups side!" );
  } 
}

Всплывающее окно принимает сообщение и если оно содержит ссылку на порт, то оно отсылает уведомление в Error Console, и что более важно, шлёт ответ через указанный порт. Теперь осталось лишь получить это сообщение во внедряемом скрипте. Во внедряемом скрипте мы имеем следующий код:

channel.port1.onmessage = function( event ){
  opera.postError("Here is what i got in the injected script for port1: " + event.data);
}

Внедряемый скрипт слушает port1 канала сообщений. При получении сообщения на него, он посылает уведомление в Error Console с содержимым полученного от всплывающего окна сообщения.

Итого, вот что происходит в расширении:
  • Внедряемый скрипт загружается.
  • Метод onconnect выполняется в фоновом скрипте и отсылает сообщение внедряемому скрипту.
  • Внедряемый скрипт получает сообщение и создаёт канал сообщений.
  • Внедряемый скрипт отсылает сообщение фоновому скрипту вместе с ссылкой на второй порт.
  • Фоновый скрипт принимает сообщение и сохраняет ссылку на порт.
  • Всплывающее окно соединяется с фоновым скриптом.
  • Метод onconnect выполняется опять, но в этот раз отсылает обратное сообщение вместе с ссылкой на порт внедряемого скрипта.
  • Всплывающее окно принимает сообщение, проверяет в нём наличие ссылки на порт. Если таковая имеется, оно шлёт обратное сообщение на этот порт (это port2 канала связи).
  • Внедряемый скрипт получает сообщение. После этого он шлёт уведомление в Error Console с текстом, полученным от всплывающего окна.

В этом сценарии фоновый скрипт выступает в роли свахи. Сначала, она связывается с первым участником (внедряемый скрипт). Участник даёт своё номер (второй порт) свахе, который сваха сохраняет. Другой участник (всплывающее окно) связывается со свахой. Как только это происходит, сваха отсылает номер первого участника (внедряемого скрипта) второму участнику (всплывающему окну). Теперь всё дальнейшее общение происходит напрямую между двумя участниками, убирая сваху из уравнения.

Подводим итоги


Обмен данными между различными частями расширения довольно прост после того, как вы узнаете как использовать метод postMessage вместе с обработчиками onconnect и onmessage. Вы также можете использовать каналы сообщений для передачи данных, и этот подход необходим, когда данные передаются между всплывающим окном и внедряемым скриптом. Эта статья проливает немного света на передачу данных в трёх сценариях: между фоновым и внедряемым скриптами, межу фоновым скриптом и всплывающим окном, между всплывающим окном и внедряемым скриптом.

Ссылки на API


Методы, относящиеся к фоновому скрипту
Методы, относящиеся к внедряемому скрипту
Методы, относящиеся к всплывающим окнам
Tags:
Hubs:
Total votes 50: ↑38 and ↓12+26
Comments4

Articles