Содержание
Платформа .NET MAUI, прежде всего, предназначена для разработки кроссплатформенных приложений, работающих в различных операционных системах со своими особенностями реализации. Вызов кода платформы — одна из особенностей проектов .NET MAUI. Нам необходимо обеспечить работу сервиса на нескольких платформах и, при этом, сервис может учитывать какие-либо возможности конкретной платформы.
Например, создадим новую реализацию сервиса ILogger
так, чтобы в Android и Windows в лог записывались разные строки. На данный момент структура проекта выглядит следующим образом:
Допустим, мы захотим, чтобы в каждой строке лога прописывалось название операционной системы в которой запущено приложение. Сделать это можно двумя способами:
- использовать условную компиляцию
- использовать разделяемые классы и методы
Рассмотрим оба этих способа.
Вызов кода платформы с использованием разделяемых классов и методов
Как мы уже знем, проект .NET MAUI использует мультинацеливание и под каждую платформу в папке Platforms располагаются папки с названием поддерживаемой платформы. В этих папках мы и размещаем весь код специфичный для определенной платформы. Мультинацеливание можно объединить с разделяемыми классами и методами для вызова кода платформы. Рассмотрим как реализовать этот способ в нашем приложении
Определение сервиса
На данный момент, в нашем приложении уже определен сервис ILogger
, который располагается в корне проекта и выглядит следующим образом:
public interface ILogger { public void WriteLine(string message); }
Вообще, общепринято размещать сервисы в папке Services проекта, но это не обязательное условие. Теперь создадим разделяемый класс, который будет определять сигнатуру метода WriteLine()
:
public partial class FileLoggerCrossPlatform : ILogger { const string FILE_NAME = "Log.txt"; private readonly DateTime _currentTime; private string fileName; public string FileName { get { return fileName; } set { fileName = value; } } private readonly string _newLine = Environment.NewLine; public partial void WriteLine(string message); }
Здесь мы также определили те поля и свойства, которые будут иметь одно и то же значение во всех платформах. Теперь наша задача заключается в том, чтобы создать разделяемые классы, реализующие метод WriteLine()
для каждой платформы.
Одно из важных условий реализации заключается в том, чтобы все классы располагались в одном пространстве имен. Например, сейчас класс FileLoggerCrossPlatform
расположен в пространстве имен MauiApp23
, следовательно и все другие разделяемые классы должны располагаться в этом пространстве имен.
Реализация сервиса для Windows
Создадим в папке Platform/Windows класс:
namespace MauiApp23 { public partial class FileLoggerCrossPlatform { public FileLoggerCrossPlatform() { fileName = FILE_NAME; } public partial void WriteLine(string message) { File.AppendAllText(fileName, $"[Windows][{_currentTime}] - {message}{_newLine}"); } } }
Теперь можно зарегистрировать реализацию сервиса, запустить приложение в Windows и убедиться, что лог всё также продолжает записываться:
[Windows][01.01.0001 0:00:00] - Clicked 1 time
Перейдем к аналогичной реализации сервиса в Android.
Реализация сервиса для Android
Также добавляем разделяемый класс в папку Platforms/Android:
namespace MauiApp23 { public partial class FileLoggerCrossPlatform { public FileLoggerCrossPlatform() { fileName = Path.Combine(FileSystem.CacheDirectory, FILE_NAME); } public partial void WriteLine(string message) { File.AppendAllText(fileName, $"[Android][{_currentTime}] - {message}{_newLine}"); } } }
Обратите внимание на то, что у разделяемого класса в Android немного изменился конструктор — лог приложения будет храниться в папке кэша приложения. Теперь можно запустить приложение на любом поддерживаемом устройстве Android и убедиться, что оно работает без ошибок.
Когда использовать способ реализации сервиса на основе разделяемых классов и методов
Такой способ имеет смысл использовать в том случае, если код платформы может занимать достаточно большой объем в исходном коде реализации сервиса. В этом случае, разделяемые классы позволяют сделать ваш код более удобным для чтения и понимания. Что касается нашего случая, то здесь использования разделяемых классов можно было бы избежать (меняется всего одна строка кода) и воспользоваться вторым способом вызова кода платформы — использованием условной компиляции.
Вызов кода платформы с использованием условной компиляции
Для управления условной компиляцией используются четыре директивы препроцессора.
#if
: открывает условную компиляцию, где код компилируется, только если определен указанный символ.#elif
: закрывает предыдущую условную компиляцию и открывает новую на основе того, определен ли указанный символ.#else
: закрывает предыдущую условную компиляцию и открывает новую, если указанный символ не определен.#endif
: закрывает предыдущую условную компиляцию.
Для управления условной компиляцией в .NET MAUI уже определены символы, соответствующие определенной операционной системе. Перепишем нашу реализацию сервиса, используя символы условной компиляции. Для этого удалите разделяемые классы из папок Platform/Windows и Platform/Android, а класс FileLoggerCrossPlatform
в корне проекта перепишите следующим образом:
namespace MauiApp23 { public class FileLoggerCrossPlatform : ILogger { const string FILE_NAME = "Log.txt"; private readonly DateTime _currentTime; private string fileName; public string FileName { get { return fileName; } set { fileName = value; } } private readonly string _newLine = Environment.NewLine; public FileLoggerCrossPlatform() { #if ANDROID fileName = Path.Combine(FileSystem.CacheDirectory, FILE_NAME); #else fileName = FILE_NAME; #endif } public void WriteLine(string message) { #if ANDROID File.AppendAllText(fileName, $"[Android][{_currentTime}] - {message}{_newLine}"); #else File.AppendAllText(fileName, $"[Windows][{_currentTime}] - {message}{_newLine}"); #endif } } }
Здесь мы использовали условную компиляцию для определения значения поля fileName
и при записи строки в лог. Можно снова запустить приложение в разных операционных системах и убедиться в его работоспособности.
Когда использовать способ реализации сервиса с использованием условной компиляции
Этот способ хорошо подходит в случае, если код, специфичный для конкретной платформы, небольшой по объему. Например, как в нашем случае. В этом случае код проекта остается вполне читаемым и удобным в использовании.
Итого
Вызов кода платформы в .NET MAUI можно осуществить двумя способами — с использованием условной компиляции и с использованием разделяемых классов и методов. Каждый из этих способов имеет свои преимущества использования в конкретных случаях.