Статьи

Интеграция HTML5 и Javascript с Windows Phone 7


Сегодня повсюду все говорят о HTML5. Я сам недавно выступал на
Датской конференции разработчиков 2012 года по Windows Phone и HTML5 . Я понял суть и вижу мощь и красоту HTML5. Но, насколько я вижу, HTML5 пока еще не совсем готов, а что касается мобильных приложений, я бы всегда выбрал написание собственного приложения, которое в полной мере использует преимущества платформы, а не только приложения, запускаемого в браузере, даже если Компонент браузера размещается в собственном приложении. Я думаю, что разработчики действительно должны научиться ценить платформу больше.

В этой статье я хотел бы объяснить, как интегрировать HTML5 + Javascript в приложение Windows Phone, а также продемонстрировать, как вызывать метод .NET из Javascript и как вызывать метод Javascript из .NET.

Итак, вот что нам нужно сделать, чтобы начать:

  1. Создайте приложение Windows Phone Silverlight
  2. Добавить компонент WebBrowser на главной странице
  3. Установите для свойства IsScriptEnabled компонента WebBrowser значение true
  4. Добавьте обработчик события в событие ScriptNotify компонента WebBrowser
  5. Создайте в проекте папку с именем HTML и добавьте в нее ресурсы HTML, Javascript и Stylesheet.
  6. Напишите код для копирования ресурсов, связанных с HTML, в IsolatedStorage
  7. Установите источник компонента WebBrowser на главную страницу HTML

Просто не так ли?

Как это работает

Шаги, описанные выше, действительно кажутся довольно простыми, и да, это действительно так. Для вызова Javascript на хосте элемента управления WebBrowser мы можем использовать метод
window.external.notify ()  . Это тот же самый подход для выполнения кода Javascript кода в хост-приложении на других платформах. Метод
window.external.notify ()  принимает строку, которая может содержать метаданные, описывающие, что вы хотите, чтобы хост делал. А для кода .NET для выполнения кода Javascript мы используем метод
InvokeScript ()  элемента управления WebBrowser.
InvokeScript () Метод принимает строковый параметр, который описывает метод Javascript для выполнения, и коллекцию строк, которые описывают аргументы, которые должны быть переданы методу Javascript для выполнения. Если метод, который будет вызывать функцию javascript с хоста, выполняется в потоке, не являющемся пользовательским интерфейсом (рабочий поток), тогда лучшим подходом к использованию этого метода является вызов
InvokeScript («eval», «methodName (args1, args2, args3) «)  вместо передачи имени метода, который будет вызван в качестве первого аргумента метода.

Вот схема, которую я использовал в DDC 2012, которая иллюстрирует процесс, упомянутый выше:

В этом примере у нас будет приложение, в котором размещена страница HTML5, отображающая информацию о памяти устройства (как показано на снимке экрана ниже).

И вот код …

Default.html (HTML5 + Javascript)

Приведенный ниже код будет использоваться как локальный HTML-файл, который нужно скопировать в изолированное хранилище. Давайте поместим это в папку с именем HTML

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=480, height=800, user-scalable=no" />
    <meta name="MobileOptimized" content="width" />
    <meta name="HandheldFriendly" content="true" />
    <title>HTML5 and Windows Phone 7</title>
    <style>
        body
        {
            color: White;
            background-color: Black;
            font-family: 'Segoe WP Semibold';
            text-align: left;
        }
        h3
        {
            font-size: 20pt;
        }
        input
        {
            color: #ffffff;
            background-color: #000000;
            border: 2px solid white;
            vertical-align: baseline;
            font-size: 17pt;
            min-width: 40px;
            min-height: 40px;
            margin: 5;
        }
    </style>
</head>
<body onload="onLoad()">
    <div>
        <h3>
            Current memory usage:</h3>
        <input id="memoryUsage" type="text" value="0" />
        <h3>
            Memory usage limit:</h3>
        <input id="memoryUsageLimit" type="text" value="0" />
        <h3>
            Peak memory usage:</h3>
        <input id="peakMemoryUsage" type="text" value="0" />
        <h3>
            Total memory:</h3>
        <input id="totalMemory" type="text" value="0" />
    </div>
    <script type="text/javascript">
        function onLoad() {
            window.external.notify("getMemoryUsage");
        }

        function getMemoryUsageCallback(memoryUsage, memoryUsageLimit, peakMemoryUsage, totalMemory) {
            document.getElementById("memoryUsage").value = memoryUsage;
            document.getElementById("memoryUsageLimit").value = memoryUsageLimit;
            document.getElementById("peakMemoryUsage").value = peakMemoryUsage;
            document.getElementById("totalMemory").value = totalMemory;
        }
    </script>
</body>
</html>

MainPage.xaml

Приведенный ниже код является главной страницей приложения Silverlight, в котором будет размещен контент HTML.

<phone:PhoneApplicationPage x:Class="PhoneApp.MainPage"
                           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                           xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
                           xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
                           xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                           mc:Ignorable="d"
                           d:DesignWidth="480"
                           d:DesignHeight="768"
                           FontFamily="{StaticResource PhoneFontFamilyNormal}"
                           FontSize="{StaticResource PhoneFontSizeNormal}"
                           Foreground="{StaticResource PhoneForegroundBrush}"
                           SupportedOrientations="Portrait"
                           Orientation="Portrait"
                           shell:SystemTray.IsVisible="True"
                           Loaded="PhoneApplicationPage_Loaded">

    <Grid x:Name="LayoutRoot"
         Background="Transparent">
        <phone:WebBrowser Name="browser"
                         IsScriptEnabled="True"
                         Source="HTML/Default.html"
                         ScriptNotify="browser_ScriptNotify" />
    </Grid>

</phone:PhoneApplicationPage>

MainPage.xaml.cs

А вот код файла xaml

public partial class MainPage : PhoneApplicationPage
{
    public MainPage()
    {
        InitializeComponent();
    }

    private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
    {
        using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            if (!store.DirectoryExists("HTML")) store.CreateDirectory("HTML");
            CopyToIsolatedStorage("HTML\\Default.html", store);
        }
    }

    private static void CopyToIsolatedStorage(string file, IsolatedStorageFile store, bool overwrite = true)
    {
        if (store.FileExists(file) && !overwrite)
            return;

        using (Stream resourceStream = Application.GetResourceStream(new Uri(file, UriKind.Relative)).Stream)
        using (IsolatedStorageFileStream fileStream = store.OpenFile(file, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite))
        {
            int bytesRead;
            var buffer = new byte[resourceStream.Length];
            while ((bytesRead = resourceStream.Read(buffer, 0, buffer.Length)) > 0)
                fileStream.Write(buffer, 0, bytesRead);
        }
    }

    private void browser_ScriptNotify(object sender, NotifyEventArgs e)
    {
        var response = new object[]
                       {
                           DeviceStatus.ApplicationCurrentMemoryUsage,
                           DeviceStatus.ApplicationMemoryUsageLimit,
                           DeviceStatus.ApplicationPeakMemoryUsage,
                           DeviceStatus.DeviceTotalMemory
                       };
        browser.InvokeScript("getMemoryUsageCallback", response.Select(c => c.ToString()).ToArray());
    }
}

В приведенном выше коде происходит то, что при загрузке главной страницы html-ресурсы копируются в изолированное хранилище и загружаются в компонент веб-браузера в виде локального файла. Когда
запускается ScriptNotify , приложение Silverlight получает информацию о памяти, используя
класс
DeviceStatus, и передает эту информацию обратно компоненту WebBrowser, вызывая метод getMemoryUsageCallback () с помощью метода
InvokeScript () компонента WebBrowser.

Приведенный выше пример является очень простым и наивным. но он демонстрирует что-то, что может обеспечить бесконечные возможности взаимодействия платформы. Я надеюсь, что вы нашли это полезным.

Вы можете получить полный исходный код, приведенный выше, здесь: