Повторное использование кода и совместимость под различные платформы в наше время довольно актуальный вопрос. Кроме того MSFT в последнее время старается угодить разработчикам различных платформ и языков программирования. Именно поэтому, вероятно, возможности универсальной платформы Windows позволяют использовать не один тип библиотек. Под катом о том, какие библиотеки, как и зачем можно использовать в приложениях UWP.

Библиотека классов — Class Library для приложений Windows Store


.Net библиотека с классами и методами, доступными для приложений Windows Store apps. Может быть использована только UWP приложениями, написанными на языках .Net. То есть, JavaScript, например, отпадает.

Заметьте, что обычные .Net библиотеки классов UWP приложение само собой использовать не может.
Список отличий и изменений, которые необходимо сделать при конвертации кода .Net в .Net для приложений Windows Store вы можете найти по ссылке: .NET for Windows Store apps overview

Изменений и различий довольно много, хотя наблюдается и определенное сходство. Зачастую отличаются только пространства имен, а методы и свойства остаются прежними. Это сделано для удобства портирования существующего кода. Разумеется, не весь функционал .Net доступен в приложениях Windows Store. Отчасти из соображений безопасности или же из-за того, что его концептуально не захотели дублировать в UWP.

Библиотека классов переносимая — PCL (Portable Class Library)


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



Эти целевые платформы можно изменить в любой момент в свойствах проекта.
Так как код будет один для нескольких платформ, то все типы и члены должны присутствовать в выбранных платформах и не должны иметь никакой специфики платформы. Также они не должны быть deprecated или помеченными на исключение.

Компонент среды выполнения Windows -Windows Runtime Component


Компонент, который может использоваться с любым из языков платформы WinRT. Расширение у компонента оканчивается на .winmd. Но пускай вас это не путает, компонент очень часто все-таки используется как библиотека, а метаданные, которые он содержит позволяют ему работать со всеми языками WinRT. Это и является основным плюсом.

Для примера могу показать вам как в созданном проекте Class Library через свойства можно выбрать Runtime Component в качестве результата построения:



Но в этом случае вы потеряете кросс-языковую совместимость и сможете работать с такой библиотекой только из C# и VB.

Runtime Component основан на COM. Выходит, что имеется возможность написать нативный Windows Runtime компонент на managed языке.
Во всех языках WinRT используются свои типы данных. Но в Runtime компоненте данные должны быть унифицированы.
Примитивные типы более-менее сходны во всех языках. Отличается большей частью только JavaScript.
Таблицу сопоставления можно найти по ссылкам:
Windows Runtime base data types
.NET Framework mappings of Windows Runtime types

Языки WinRT различаются и поэтому иногда необходимо приходить к какому-то общему знаменателю. Например, в .Net и JavaScript приложениях строки неизменяемые (immutable), а в C++ они mutable. В компоненте Windows Runtime строки immutable.

Ограничения/правила:
  • Публичные элементы должны быть обязательно запечатаны (sealed).
  • Публичные классы или интерфейсы не могут быть generic или реализовывать не WinRT интерфейс.
  • Публичные классы не могут быть производными от WinRT типов.
  • Все поля, параметры и возвращаемые значения публичных членов должны быть типа Windows Runtime.
  • Коренное пространство имен должно соответствовать названию сборки и не может начинаться с «Windows».
  • WRC не поддерживает полиморфизм
  • Методы в Windows Runtime могут быть перегружены, но в случае одинакового количества параметров они должны быть помечены атрибутом. Официальный пример:

public string OverloadExample(string s)
        {
            return s;
        }
        [Windows.Foundation.Metadata.DefaultOverload()] 
        public int OverloadExample(int x)
        {
            return x;
        }

В Class Library для приложений Windows Store меньше всего ограничений, поэтому если у вас приложение на .Net языках, то лучше выбирать эту библиотеку.

Практический пример:


Если ваше UWP приложение использует WebView для отображения веб-сайтов, то у вас есть возможность использовать в приложении класс, который будет доступен из JavaScript-а загруженных веб страниц.
И вот этот класс должен находится внутри компонента Windows Runtime. Вот где необходима кросс-языковая совместимость.

Создается компонент, и из основного проекта, содержащего страницу WebView на него делается ссылка. Внутри компонента публичный класс или классы могут быть помечены атрибутом [AllowForWeb]. Все публичные методы таких классов будут доступны из JavaScript загруженной в WebView страницы. Необходимо только при начале навигации на страницу добавлять этот класс с помощью метода AddWebAllowedObject.

Да, конечно, есть вариант использовать window.external.notify в коде JS, но имеются определенные ограничения безопасности, которые разрешают выполнение этих вызовов только с доверенных https сайтов.

Немного повторюсь и продублирую пример с MSDN. В класс WinRT компонента добавим метод SomeValueFromJS

using Windows.Foundation.Metadata;

namespace MyRuntimeComponent
{
    [AllowForWeb]
    public sealed class MyNativeClass
    {
        public void SomeValueFromJS(string value)
        {
            
        }
    }
} 

В XAML добавим WebView

<WebView x:Name="webView" Source="https:// www.contoso.com/script.htm"
         NavigationStarting="webView_NavigationStarting"/>

И при начале навигации внедрим наш класс в JavaScript

private void webView_NavigationStarting(WebView sender, WebViewNavigationStartingEventArgs args) 
{ 
    if (args.Uri.Host == "www.contoso.com")  
    { 
        webView.AddWebAllowedObject("csharpclass", new MyNativeClass()); 
    } 
}

Теперь из кода JS можно вызвать этот метод так:

csharpclass.nativeMethod("hello!");

Казалось бы все нормально, но вот незадача, зачастую может возникать необходимость передавать данные на страницу с WebView. Проект с WebView уже ссылается на WinRT компонент и поэтому обратную ссылку нам не добавить из-за циклической зависимости. Ограничения WRC не позволяют нам использовать некоторые варианты. В качестве решения можно создать промежуточный слой в виде библиотеки Class Library для приложений Windows Store у которой ограничений гораздо меньше. Ссылку на эту библиотеку содержащую класс с названием BridgeClass можно сделать и из основного проекта и с проекта компонента Windows Runtime.



Возможности .Net позволят нам создать доступный ивент

public static event Action<string>

и подписаться на событие в основном проекте. Давайте рассмотрим в виде кода. Код класса BridgeClass:

    public class BridgeClass
{
    public static event Action<string> MessageReceived;

    public static void Broadcast(string message)
    {
        if (MessageReceived != null) MessageReceived(message);
    }
}

В основном проекте, в code-behind страницы с WebView подписываемся на событие:

BridgeClass.MessageReceived += ShowMessage;

И реализуем:

  void ShowMessage(string msg)
    {
    }

Теперь из метода, доступного для JS можем передать значение в C#:

  public void SomeValueFromJS(string value)
  {
      BridgeClass.Broadcast(value);
  }
Поделиться с друзьями
-->

Комментарии (4)


  1. Viacheslav01
    19.07.2016 15:31

    Несколько дополнений.

    В приложениях WRT нельзя использовать PCL в которых присутствуют ресурсы resx, а исползовать resw нельзя, т.к. они поддерживаются только в приложениях WRT. Это кстати одна из частых причин черного экрана по непонятной причине. Для меня это означало полный отказ от PCL.

    На самом деле классы WRT могут бчть открытыми и полиморфными, но при условии, что они наследуются от открытых типов фреймвока.
    Так же открытые классы WRT можно создать средствами C++ но не C++/CX.


  1. Kenya-West
    20.07.2016 11:43

    У меня вопрос: Майкрософты полностью забили на WinJS? Разрабы даже не обновили библиотеку к Anniversary Update, принимают лишь Issues и переименовали его дескрипшн в малопонятный «UI Toolkit for modern browsers», хотя изначально оно сделано для стилизации приложений на Windows 8/8.1.

    «Right now, Microsoft plans to maintain WinJS's existing features--this means responding to Issues and Pull Requests on a regular basis. We're committed to making sure that WinJS continues to run well. At this time, we don't have plans to invest in new features or feature requests; this also means that we're not planning a new feature release.»

    Коммунити умирает. Что делать?


    1. asommer
      20.07.2016 21:00

      Что делать? Не паниковать) Забили или нет не знаю. Может быть объединят с чем-нибудь (с web bridge for Hosted Web Apps?) или сделают новый прокет на основе WinJS. Давайте если через пол года глухо все будет, то вместе попаникуем.


      1. Kenya-West
        20.07.2016 23:24

        Блин, ну жалко, что потихоньку прикрывают очередной способ нативной разработки на Windows… Со временем C++ тоже отвалится, по ходу. Да и .NET не жалуют из-за личных взглядов руководителя по развитию WinRT. Ну ждем, буду время от времени попискивать в Issues.