Россия, Звенигород |
Система распространения и установки - XPInstall
17.2.1.3. Скрипты
Чтобы автоматизировать распространение приложения, необходимо написать два скрипта.
Первый скрипт выполняется на обычной web-странице или документе XUL. Для его написания не нужно заботиться о вопросах, связанных с безопасностью. Он выполняется, только если страница или приложение просматривается с помощью технологий самой Mozilla. Остаток страницы приглашает пользователя установить приложение. Второй скрипт, называющийся install.js, выполняется внутри системы XPInstall, где он изолирован и от web, и от XPCOM.
Оба скрипта используют JavaScript-объекты хоста. Объекты, упоминаемые в данной лекции, описываются подробно в разделе "Технологии установки".
Первый скрипт называется "триггер-скрипт". С него дистрибуция приложения начинается. JavaScript использует два существующих объекта, а третий должен быть создан. Существующие объекты - это window.InstallTrigger и InstallVersion, который также доступен как window.InstallVersion.
Объект InstallTrigger содержит диагностические методы, а также метод install(), который начинает загрузку файлов XPI и, вероятно, вызывает одну или более копий второго скрипта, install.js. Диагностические методы используются для базовой проверки номеров версий и для проверки того, что система XPInstall имеется в наличии и доступна.
Объект InstallVersion существует для удобства работы, он может сравнить два номера версий приложения и определить, какой из них больше и какие именно из четырех частей номера версии отличаются и чем.
Третий объект, который программист приложения должен создать, имеет следующую форму:
var xpi_container = { "Test app part 1" : "URL1", "Test app part 2" : "URL2", ... }
Этот объект представляет все файлы XPI, которые в совокупности образуют приложение и передаются методу InstallTrigger.install(). Объект в приведенном примере содержит два свойства, и, таким образом, представляет два файла. Возможно любое число свойств, большее нуля. Поскольку оба имени обоих свойств есть просто строки, они могут быть доступны только как элементы массива:
var url = xpi_container["Test app part 1"];
Каждое имя свойства - текстовое имя компонента приложения, и пользователь будет это имя видеть. Каждое значение свойства - это (относительный или абсолютный) URL, который должен соответствовать файлу XPI. URL может иметь дополнительную строку параметров. Строка параметров начинается со знака вопроса, "?", это тот же формат, что и в строке запроса HTTP GET. Остаток строки также может следовать синтаксису HTTP GET, но может иметь и произвольную форму (хотя это неудачный вариант). Пример URL:
/downloads/apps/mozilla/shopcart/main.xpi?java=yes;flash=no
Это относительный URL, так что Mozilla добавит http: и имя домена. В данном примере код триггера обнаружит наличие Java и отсутствие плагина Flash и передаст эту информацию второму скрипту, install.js в параметрах java и flash. Подстрока параметров передается второму скрипту install.js без дополнительной обработки.
Все эти объекты передаются в функцию, которая обычно вызывается обработчиком onclick, привязанным к линку или кнопке.
В Листинге 17.1 приведен пример скелета такой функции, демонстрирующий большинство возможностей, которые она может включать.
function deploy() { if ( !is_moz_browser() ) { return false; } if ( !window.InstallTrigger.enabled() { return false; } if ( !is_target() ) { return false; } if ( !is_app_version_ok() } { return false; } var error_flag = false; function error_handler(url, err) { error_flag = true; }; calculate_params(); var xpi_container = { ... }; with (window.InstallTrigger) install(xpi_container, error_handler); return !error_flag; }Листинг 17.1. Пример полнофункционального триггер-скрипта XPInstall.
Большинство функций, использованных в скрипте, нужно написать для каждого приложения. Начальная серия проверок остановит процесс установки, если что-то не так с компьютером пользователя или уже установленными приложениями. Функция error_handler() может быть настолько сложной, насколько это необходимо в каждом конкретном случае. Функция calculate_params() подготавливает те параметры, которые будут переданы второму скрипту. Эта информация используется при создании объекта xpi_container. Наконец, вызывается функция install(), реально выполняющая всю работу. Конечно, ничего не произойдет, если отключен JavaScript, или свойство xpinstall.enabled имеет значение false.
Протестировать пользовательский компьютер на предмет соответствия условиям установки - достойная задача. Браузер ограничен в своих возможностях из соображений безопасности, а система XPInstall не имеет доступа к стандартным компонентам XPCOM. Тестирование должно опираться на обе эти части. Если требуется сложное тестирование, напишите специальное приложение для этой цели и попросите пользователя вначале установить его. Затем это приложение может быть использовано в триггер-скрипте.
Второй необходимый скрипт всегда называется install.js. Каждый архив XPI должен содержать такой скрипт. Он отвечает за размещение каждого файла в архиве. Копирование файлов не выполняется самим скриптом. Вместо этого скрипт снабжает систему XPInstall набором инструкций по размещению файлов. Когда все инструкции получены, XPInstall приступает к копированию. XPInstall выполняет инструкции, обрабатывает возникающие ошибки и ведет логи установки. Информация об установке сохраняется для последующего удаления приложения. В любое время до того, как XPInstall начинает свою работу, скрипт install.js может прервать инсталляцию.
Окружение, в котором работает скрипт install.js, существенно ограничивает его возможности. Он работает в контексте отдельного интерпретатора JavaScript и имеет собственный глобальный объект, который не является объектом HTML или XUL окна. Есть всего несколько объектов, с которыми этот скрипт может работать. Вот эти объекты:
Install InstallVersion File FileSpecObject WinProfile WinReg
Объект Install - глобальный, поэтому его методы доступны непосредственно, как если бы они были функциями. Это центральный объект, имеющий набор методов, с помощью которых можно создавать объекты других типов.
Объект Install имеет полезные свойства. Свойство platform означает операционную систему. Свойство arguments содержит любые параметры, а свойство url содержит полный XPI URL.
Объект Install также имеет полезные методы: initInstall(), инициирующий XPInstall, чтобы тот был готов получить инструкции; cancelInstall(), который полностью останавливает работу; performInstall(), выполняющий инсталляцию согласно полученным инструкциям; и uninstall(), удаляющий приложение. Он также имеет полезные диагностические методы.
Объекты File и FileSpecObject не имеют никакого отношения к файловым объектам XPCOM - это независимая реализация похожих функций. Их можно использовать для работы с файлами в любом месте локального компьютера. Доступны некоторые специальные имена, чтобы это можно было делать на разных платформах. Объект File может выполнять также некоторые тесты и другие вспомогательные задачи.
Объекты WinProfile и WinReg специфичны для Microsoft Windows. WinProfile обеспечивает доступ на чтение и запись к конфигурационным .INI файлам, а WinReg - к Windows Registry.
В зависимости от своего содержания скрипт install.js может потребовать, чтобы платформа была перезагружена; также может понадобиться, чтобы платформа перечитала содержание chrome и плагинов при рестарте. На выполнение скрипта эти побочные эффекты не влияют. Как и триггер-скрипт, скрипт install.js имеет стандартную форму. Она приведена в листинге 17.2.
var TEXT_NAME = "Test Application Release 3.2"; var REG_NAME = "/Test Company/Test Application"; var VERSION = "3.2.0.1999"; var params; var rv = SUCCESS; function prepare() { if ( !(params = parse_args())) return INVALID_ARGUMENTS; if ( is_target() != SUCCESS ) return getLastError(); initInstall(TEXT_NAME, REG_NAME, VERSION); /* -- as many functions like this as required -- */ if ( schedule_folders()!= SUCCESS) return getLastError(); if ( schedule_files() != SUCCESS ) return getLastError(); if ( modify_os() != SUCCESS ) return getLastError(); if ( run_any_programs() != SUCCESS)return getLastError(); if ( register_chrome() != SUCCESS) return getLastError(); return SUCCESS; } rv = prepare(); (rv == SUCCESS) ? performInstall() : cancelInstall(rv);Листинг 17.2. Пример полнофункционального XPInstall скрипта install.js.
Этот скрипт полагается на сообщения об ошибках, которые вырабатывает и возвращает объект Install, если что-то идет неправильно. Первый шаг - удостовериться, что аргументы, переданные триггер-скриптом, следуют в нужном порядке, и пользовательский компьютер подходит для установки приложения. Если тут все OK, метод initInstall() готовит XPInstall к получению инструкций по установке. Каждая из последующих функций выполняет часть работы по подготовке установки. Наконец, если все идет хорошо, метод performInstall() выполняет все требуемые действия разом. Не показан процесс сохранения информации о процессе установки с помощью метода logComment(), и сообщения о процессе выполнения, посылаемые пользователю с помощью методов alert() или confirm(). Метод prompt() как метод здесь недоступен.
Простейшая версия этого скрипта, полезная для целей тестирования, приведена в листинге 17.3.
var TEXT_NAME = "Test Application Release 3.2"; var REG_NAME = "/Test Company/Test Application"; var VERSION = "3.2.0.1999"; var rv = SUCCESS; function schedule_folders() { var tree = getFolder("Chrome"); // Special keyword setPackageFolder(tree); addDirectory("chrome"); // topmost directory } function prepare() { initInstall(TEXT_NAME, REG_NAME, VERSION); if ( schedule_folders()!= SUCCESS) return getLastError(); return SUCCESS; } rv = prepare(); (rv == SUCCESS) ? performInstall() : cancelInstall(rv);Листинг 17.3. Полная версия install.js для простого приложения в chrome.
В этом примере функция prepare() обрезана до простейшего состояния и содержит лишь функцию schedule_folders(). Эта функция реализует критически важный шаг сравнения иерархии директорий в файле XPI и локальной файловой системы.
Этот процесс имеет следующую механику. Специальное слово Chrome, одно из немногих ключевых слов, используется, чтобы обозначить директорию chrome в зоне установки платформы. Это ключевое слово не зависит от операционной системы, но остальные слова – платформо-зависимы. Chrome - целевая директория, куда копируется иерархия файлов из файла XPI.
В Листинге 17.3 все фалы в комплекте XPI (кроме install.js) имеют в качестве корневой директории директорию с именем chrome. Эта часть может быть заменена словом "X" или Part или любой иной строкой, потому что это просто "затычка". Все будет работать корректно, если метод addDirectory() заменит ее на то, что нужно в данном конкретном случае.
Если файл XPI имеет в качестве "затычки" слово "chrome", то неплохой выбор для имен файлов внутри нее следующий:
chrome/content/TestApp/TestApp.xul chrome/locale/en-US/TestApp/master.dtd chrome/skin/classic/TestApp/global.css
Папки в файловой системе сравниваются с папками в комплекте XPI, и этот процесс может повторяться несколько раз в процессе установки. Комплект XPI может иметь несколько деревьев файлов с разными корневыми директориями. Например, если XPI имеет три дерева файлов, каждому дереву ищется соответствующее ему место в локальной файловой системе. Файл XPI может содержать
install.js subtree1/file1 subtree1/file2 subtree2/file3 subtree2/file4 subtree3/file5 subtree3/file6
Каждое поддерево из двух файлов может быть помещено в различные места одним инсталляционным скриптом.
Наконец, если приложение должно быть удалено, может быть использован метод uninstall() между initInstall() и performInstall(). Он удалит приложение, основываясь на информации об истории установки, хранящейся в регистре Mozilla.
17.2.1.4. Файлы XPI
Файл XPI имеет формат обычного ZIP-файла. Используйте WinZip, pkzip, или подобные им программы на платформе Microsoft Windows; импользуйте zip(1), но не gzip(1), на платформе UNIX. Имена путей в zip-файлах всегда являются относительными.
Есть одно требование к содержанию данного файла: он должен содержать в своем корне файл install.js. Обычной практикой является то, что все остальное в этом файле соответствует структуре директорий в зоне установки платформы. Если структура директорий файла XPI не соответствует реальной файловой структуре, скрипт install.js будет посложнее.
Можно создать цифровую подпись файла XPI. Цифровая подпись выполняется утилитой Netscape SignTool, как и для всех файлов с цифровой подписью в Mozilla, но есть одно ограничение. Цифровая подпись должна быть первым элементом в ZIP-файле XPI. Цифровая подпись - это файл с именем пути META-INF/{signature}, где {signature} - это имя файла с зашифрованной подписью того типа, который поддерживает Mozilla. Удостоверьтесь в том, что утилиты, подобные WinZip, применяют сортировку "original order" или используйте unzip(1) или pkunzip. Подробнее о цифровых подписях и утилите SignTool см.: http://devedge.netscape.com.
На рисунке 17.1 показано содержание комплекта XPI Chatzilla - клиента быстрой связи (instant messaging client). Это ZIP-файл. Данное приложение обычно устанавливается, когда устанавливается комплект приложений Mozilla. Установка выполняется локально, с использованием системы установки Mozilla. Этот файл мог бы быть установлен и удаленно, с использованием механизма удаленной инсталляции.
Корневая директория, в данном случае называемая bin, собирает все необходимые файлы вместе, в одно поддерево. Для каждой платформы в файле XPI есть некоторые особенности, например, в UNIX-версии файлы .ICO заменятся файлами .XBM. Но на всех платформах внутри комплекта есть архив chatzilla.jar, содержащий все chrome-файлы для приложения Chatzilla. Это JAR-файл можно обнаружить в директории chrome на любой машине с установленным набором приложений Mozilla. Файл chatzilla-service.js - новый XPCOM компонент, поставляемый вместе с приложением.
Данный компонент добавляет платформе с установленной Chatzilla новые свойства: опцию командной строки ( -chat ) и схему URL ( irc:// ).
17.2.1.5. Сокращенный скрипт для файла XPI, не содержащего контента.
Если файл XPI реализует только скин или локаль, скриптинг может быть укорочен. В этом случае не требуется скрипт install.js. В триггер-скрипте вместо install() вызывается installChrome(). Поскольку установка скина или локали не может закончиться неудачей (за исключением того случая, когда на диске не окажется места), триггер- скрипт сводится к одной строчке.
В этом случае файлы, содержащиеся в файле XPI, просто копируются в директорию chrome. Они должны быть JAR-файлами.
17.2.1.6. Сокращенный скрипт для типов MIME
Если файл XPI распространяется web-сервером, он имеет тип MIME
application/x-xpinstall
В этом случае система XPInstall обрабатывает этот файл автоматически. В таком случае нет необходимости в скрипте, привязанном к обработчику события в коде приложения. Любой скрипт install.js из файла XPI будет запущен автоматически.
Программист приложения может вообще избежать использования системы XPInstall. Теги XUL, описываемые в разделе "Технологии установки" позволяют легко создавать диалоговые окна, которые ведут себя как мастер установки.