Простой, естественный вопрос: какие бывают библиотеки UWP?
Повторное использование кода и совместимость под различные платформы в наше время довольно актуальный вопрос. Кроме того 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
И при начале навигации внедрим наш класс в 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
и подписаться на событие в основном проекте. Давайте рассмотрим в виде кода. Код класса BridgeClass:
public class BridgeClass
{
public static event Action 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);
}