Быстрый старт
О, подождите, манифест!
Сейчас вы уже могли испытать тот код, который приведен выше, и столкнуться с исключением "Доступ запрещен" при попытке вызова getGeoPositionAsync. Почему это так? Исключение говорит о том, что мы не указали возможность Расположение (Location) в манифесте. Без включения этой возможности, вызов вроде этого, зависящий от возможности, вернет исключение.
Если вы запускаете пример в отладчике, это исключение покажет диалоговое окно. Если вы запускаете его вне отладчика - с плитки на Начальном экране - вы увидите, что приложение просто прекратило работать, не показав ничего, кроме экрана-заставки. Это - обычное поведение для необработанных исключений. Для того, чтобы предотвратить подобное поведение, добавим функцию для обработки ошибок в качестве второго параметра метода done асинхронного promise-объекта:
gl.getGeopositionAsync().done(function (position) { //... }, function(error) { console.log("Unable to get location."); });
Функция console.log записывает строку в окно Консоли JavaScript (JavaScript Console) в Visual Studio, а это, очевидно, хорошая идея. Сейчас запустите приложение вне отладчика, и вы увидите, что оно запустилось, так как исключение теперь признано "обработанным". В отладчике установите точку останова на строку console.log и точка останова сработает после того, как появится исключение и вы нажмете Далее (Continue). (Пока это всё, что мы делаем с появляющимися ошибками; в "Жизненный путь приложений для Магазина Windows: Характеристики платформы Windows 8" курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript" мы добавим более подходящее сообщение и команду повтора действия).
Если диалоговое окно исключения вам надоело, вы можете управлять тем, информацию о каких исключениях показывать во всплывающих окнах с помощью диалогового окна Отладка > Исключения (Debug > Exceptions), показанного на Рис. 2.16, в разделе Исключения JavaScript времени выполнения (JavaScript Runtime Exceptions). Если вы снимете флажки в колонке Необработанное пользовательским кодом (User-unhandled), вы не увидите диалоговое окно, когда происходит то или иное исключение.
увеличить изображение
Рис. 2.16. Исключения JavaScript времени выполнения в диалоговом окне Отладка > Исключения (Debug > Exceptions) в Visual Studio
Вернемся к возможностям: для того, чтобы это приложение правильно себя вело, откройте package.appmanifest вашего проекта, выберите закладку Возможности (Capabilities) и включите Расположение (Location), как показано на Рис. 2.17.
Рис. 2.17. Установка возможности Расположение (Location) в редакторе манифеста Visual Studio. (Обратите внимание на то, что Blend поддерживает правку манифеста лишь в качестве XML-файла)
Теперь, даже если мы объявили возможность, геолокация всё еще требует разрешения пользователя, как было указано в "Жизненный путь приложений для Магазина Windows: Характеристики платформы Windows 8" . При первом запуске приложения с установленной возможность вы увидите всплывающее окно, похожее на то, что изображено на Рис. 2.18. Если пользователь запретит доступ в этом окне, обработчик ошибки снова будет запущен, так как API снова выдаст исключение запрета доступа.
увеличить изображение
Рис. 2.18. Типичное окно, позволяющее узнать мнение пользователя, отражающее пользовательскую цветовую схему, которое появляется при первой попытке приложения вызвать API, доступ к которому осуществляется через брокера (в данном случае - геолокационное API). Если пользователь запретит доступ, API выдаст ошибку, но позже пользователь может изменить решение в панели Параметры > Разрешения (Settings > Permissions).
Врезка: как сбросить информацию о решении пользователя для целей тестирования?
При отладке вы можете заметить, что данное всплывающее окно появляется лишь однажды, даже при выполнении следующих отладочных сессий. Для того, чтобы очистить данное состояние, откройте средства чудо-кнопки Параметры (Settings) в выполняющемся приложении и выберите Разрешения (Permissions). Вы увидите переключатели для соответствующих возможностей. Если по каким-то причинам вы не можете запустить приложение, перейдите на Начальный экран и деинсталлируйте приложение, воспользовавшись его плиткой. После этого вы увидите запрос о разрешении при следующем запуске приложения.
Обратите внимание на то, что когда пользователь изменяет настройки разрешений, приложение никак не оповещается об этом. Приложение может обнаружить это изменение, лишь попытавшись использовать API снова. Мы вернемся к этому в "Быстрый старт" курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".
Получение фотографии с камеры
Хоть это и необычно, я надеюсь, что идея добавить описание получений фотографий с камеры в раздел "быстрый старт", заставит вас сомневаться во вменяемости автора. Не потребуется ли для этого огромного количества кода? Да, так было, но в Windows 8 это не так. Все сложные особенности захвата данных с камеры отлично инкапсулированы внутри API Windows.Media.Capture, так что, в итоге, мы можем добавить в приложение эту возможность с помощью нескольких строк кода. Это хороший пример того, как небольшой динамичный код, наподобие JavaScript комбинируется с отлично спроектированными компонентами WinRT - и то и другое в системе, и тем и другим вы можете пользоваться - создавая мощный союз.
Для того, чтобы реализовать эту возможность, сначала нам нужно вспомнить, что камера, как и GPS-приёмник, относится к устройствам, от которых может пострадать приватность пользователя, поэтому возможность, связанную с ней, так же нужно объявлять в манифесте, Рис. 2.19.
При первом использовании камеры во время выполнения приложения, вы увидите еще одно диалоговое окно, запрашивающее разрешение пользователя, Рис. 2.20.
увеличить изображение
Рис. 2.20. Всплывающее окно для получения разрешения пользователя на применение камеры. Вы можете в любой момент изменить эту настройку в панели Параметры > Разрешения (Settings > Permissions)
Теперь нам нужно настроить элемент img для того, чтобы он мог реагировать на жест прикосновения. Для этого нам нужно просто добавить прослушиватель события click, который срабатывает для любых способов ввода (сенсорный интерфейс, мышь, перо), как мы увидим в "Анатомия приложения и навигация по страницам" курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript".
var image = document.getElementById("photo"); image.addEventListener("click", capturePhoto.bind(image));
Здесь мы указываем capturePhoto в качестве обработчика события и используем функциональность объектного метода bind для того, чтобы объект this внутри capturePhoto был напрямую связан с элементом img. В результате, этот обработчик может быть использован для любого количества элементов, так как он не ссылается на DOM.
//Расположите это под var lastPosition = null; var lastCapture = null; //Расположите это после callFrameScript function capturePhoto() { //В соответствии с вызовом .bind() в addEventListener, "this" будет элементом image, //но нам нужна копия для асинхронно завершившегося обработчика ниже. var that = this; var captureUI = new Windows.Media.Capture.CameraCaptureUI(); //Показывает, что мы хотим получить PNG-изображение не больше, чем целевой элемент - //пользовательский интерфейс автоматически обрежет изображение под этот размер captureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png; captureUI.photoSettings.croppedSizeInPixels = { width: this.clientWidth, height: this.clientHeight }; captureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo) .done(function (capturedFile) { //Убедитесь, что проверили, подходит ли вам возвращенный элемент: он может содержать null, если //пользователь отменил действие. if (capturedFile) { lastCapture = capturedFile; //Сохраняем для целей Общего доступа (Share) that.src = URL.createObjectURL(capturedFile, {oneTimeOnly: true}); } }, function (error) { console.log("Unable to invoke capture UI."); }); }
Нам необходимо создать локальную копию this внутри обработчика click, так как, как только мы оказываемся внутри функции завершения асинхронного запроса (посмотрите функцию внутри captureFileAsync.done) мы оказываемся в новой области видимости и объект this изменяется. Принято такую копию this называть that. Берем это?
Для того чтобы запустить интерфейс камеры, нам лишь нужно создать экземпляр Windows.Media.Capture.CameraCaptureUI с ключевым словом new (обычный способ создания экземпляров динамических объектов WinRT), настроить его на желаемый формат и размер изображения (это одни из многих других возможных параметров, которые обсуждаются в "Элементы управления, их стилизация и привязка данных" курса "Пользовательский интерфейс приложений для Windows 8, созданных с использованием HTML, CSS и JavaScript") и вызвать captureFileAsync. Здесь будет произведена проверка манифеста, и, если необходимо, будет запрошено разрешение пользователя.
Это асинхронный вызов, поэтому мы используем .done в конце с обработчиком завершения, который в данном случае принимает объект Windows.Storage.Storagefile. Посредством данного объекта вы можете получить любые исходные данные изображения, которые вам нужны, но для наших целей мы просто хотим отобразить изображение в элементе img. Это очень просто! Мы можем передать объект StorageFile методу URL.createObjectURL и получить URI, который можно напрямую присвоить свойству img.src. Сделанная фотография появится там, где нужно8Параметр {oneTimeOnly: true} показывает, что URI не подлежит повторному использованию и должен быть аннулирован с помощью URL.revokeObjectURL, когда он больше не используется, как в случае, когда мы заменяем img.src на новое изображение. Без использования данного подхода мы столкнёмся с утечкой памяти при отображении каждого нового изображения. Если ранее вы использовали URL.createObjectURL, вы увидите, что второй параметр теперь представляет собой неупорядоченный набор свойств (property bag), что объединяет его с наиболее свежими спецификациями W3C!
Обратите внимание на то, что captureFileAsync вызовет обработчик завершения, если пользовательский интерфейс был успешно отображен, но пользователь нажал кнопку Назад и фото не было сделано. Именно поэтому присутствует дополнительная проверка правильности captureFile. Обработчик ошибки в promise-объекте, в свою очередь, сначала перехватит ошибки запуска пользовательского интерфейса, но обратите внимание на то, что при отсутствии разрешения пользователя на работу с камерой, сообщение об этом появится непосредственно в пользовательском интерфейсе камеры (Рис. 2.21), поэтому нет необходимости иметь обработчик ошибки для этих целей в данном API. В большинстве случаев, однако, вам понадобится соответствующий обработчик ошибок для асинхронных вызовов.
увеличить изображение
Рис. 2.21. Сообщение в пользовательском интерфейсе камеры, когда пользователь не разрешил доступ к ней (слева); вы можете изменить разрешения посредством панели Разрешения чудо-кнопки Параметры (Settings) (справа)