Использование библиотек C/C++ с помощью XamarinUse C/C++ libraries with Xamarin

ОбзорOverview

Xamarin позволяет разработчикам для создания кроссплатформенных собственных мобильных приложений с помощью Visual Studio.Xamarin enables developers to create cross-platform native mobile apps with Visual Studio. Как правило C# привязки используются для предоставления существующие компоненты платформы для разработчиков.Generally, C# bindings are used to expose existing platform components to developers. Однако бывают случаи, когда потребности приложения Xamarin для работы с существующими базы кода.However, there are times when Xamarin apps need to work with existing codebases. Иногда команды просто нет времени, бюджета и ресурсы к порту a больших, тщательно протестированного и высокой степенью оптимизации базы кода для C#.Sometimes teams simply don't have the time, budget, or resources to port a large, well-tested, and highly optimized codebase to C#.

Visual C++ для кросс платформенной мобильной разработки позволяет C/C++ и C# кода для сборки в качестве части этого же решения, предлагает множество преимуществ, включая унифицированный процесс отладки.Visual C++ for cross-platform mobile development enables the C/C++ and C# code to be built as part of the same solution, offering many advantages including a unified debugging experience. Корпорация Microsoft использовала C/C++ и Xamarin таким образом для разработки приложений, таких как Hyperlapse Mobile и камеры Pix.Microsoft has used C/C++ and Xamarin in this way to deliver apps such as Hyperlapse Mobile and Pix Camera.

Тем не менее в некоторых случаях имеется желание (или требование) чтобы сохранить существующие средства C/C++ и процессов на месте и библиотеки кода, отделены от приложения, рассматривая библиотеки, как если бы аналогичную сторонних компонентов.However, in some cases there is a desire (or requirement) to keep existing C/C++ tools and processes in place and to keep the library code decoupled from the application, treating the library as if it were similar to a third-party component. В этих случаях задача не только предоставляет нужные элементы для C# , но Управление библиотекой как зависимость.In these situations, the challenge is not only exposing the relevant members to C# but managing the library as a dependency. И, само собой, автоматизация как большая часть этого процесса можно.And, of course, automating as much of this process as possible.

Здесь описаны более общий подход, в этом сценарии и рассматривается простой пример.This post outlines a high-level approach for this scenario and walks through a simple example.

ФонBackground

C/C++ считается кросс платформенных язык, но необходимо соблюдать осторожность в убедитесь, что исходный код действительно платформах, используя только C/C++ поддерживает все компиляторы целевой и содержащее незначительной или нулевой платформу условно включены или код, специфичные для компилятора.C/C++ is considered a cross-platform language, but great care must be taken to ensure that the source code is indeed cross-platform, using only C/C++ supported by all target compilers and containing little or no conditionally-included platform or compiler-specific code.

В конечном счете код необходимо скомпилировать и успешно выполнена на всех целевых платформах, поэтому это сводится к общность разных платформах (и компиляторы) целевой платформы.Ultimately the code must compile and run successfully on all target platforms therefore this boils down to the commonality across the platforms (and compilers) being targeted. Проблемы по-прежнему могут быть вызваны незначительные отличия между компиляторы и поэтому тщательное тестирование (предпочтительно автоматизированное) на каждой целевой платформы становится все более важным.Issues may still arise from minor differences between compilers and so thorough testing (preferably automated) on each target platform becomes increasingly important.

Общий подходHigh-level approach

На приведенном ниже рисунке представляет четыре этапа подход, используемый для преобразования исходного кода C/C++ в кросс платформенной библиотекой Xamarin, которые являются общими с помощью NuGet и затем используется в приложении Xamarin.Forms.The illustration below represents the four-stage approach used to transform C/C++ source code into a cross-platform Xamarin library that is shared via NuGet and then is consumed in a Xamarin.Forms app.

Общий случай использования C/C++ с помощью Xamarin

Ниже приведены четыре этапа:The 4 stages are:

  1. Компиляция исходного кода C/C++ в собственные библиотеки для конкретных платформ.Compiling the C/C++ source code into platform-specific native libraries.
  2. Упаковки собственные библиотеки с помощью решения Visual Studio.Wrapping the native libraries with a Visual Studio solution.
  3. Упаковка и отправка пакета NuGet для оболочки .NET.Packing and pushing a NuGet package for the .NET wrapper.
  4. Использование пакета NuGet из приложения Xamarin.Consuming the NuGet package from a Xamarin app.

Этап 1. Компиляция исходного кода C/C++ в собственные библиотеки для конкретных платформStage 1: Compiling the C/C++ source code into platform-specific native libraries

Цель этого этапа — для создания собственных библиотек, которые могут быть вызваны C# программы-оболочки.The goal of this stage is to create native libraries that can be called by the C# wrapper. Это может или не могут быть необходимы в зависимости от конкретной ситуации.This may or may not be relevant depending on your situation. Многие средства и процессы, которые можно включить в этом распространенном сценарии необходимо выходят за рамки этой статьи.The many tools and processes that can be brought to bear in this common scenario are beyond the scope of this article. Основные рекомендации, C/C++ codebase синхронизирован с любой собственный код оболочки, достаточно модульное тестирование, хранение и автоматизации сборки.Key considerations are keeping the C/C++ codebase in sync with any native wrapper code, sufficient unit testing, and build automation.

Библиотеки в пошаговой инструкции были созданы с помощью Visual Studio Code с сопутствующей сценарий оболочки.The libraries in the walk-through were created using Visual Studio Code with an accompanying shell script. Расширенная версия этого пошагового руководства можно найти в репозиторий Mobile CAT GitHub , посвященной этой части примера более подробно.An extended version of this walk-through can be found in the Mobile CAT GitHub repository that discusses this part of the sample in greater depth. Собственные библиотеки которые обрабатываются как зависимость стороннего в этом случае Однако на этом этапе проиллюстрирован для контекста.The native libraries are being treated as a third-party dependency in this case however this stage is illustrated for context.

Для простоты пошагового руководства предназначено только подмножество архитектур.For simplicity, the walkthrough targets only a subset of architectures. Для iOS для создания единого fat двоичных из отдельных двоичных файлов конкретной архитектуры используется программа lipo.For iOS, it uses the lipo utility to create a single fat binary from the individual architecture-specific binaries. Android будет использовать динамический двоичные файлы с расширением .so и операций ввода-вывода будет использовать статический fat двоичных с расширением .a.Android will use dynamic binaries with a .so extension and iOS will use a static fat binary with a .a extension.

Этап 2. Упаковки собственные библиотеки с помощью решения Visual StudioStage 2: Wrapping the native libraries with a Visual Studio solution

Следующий этап заключается в том, программы-оболочки собственные библиотеки, чтобы легко используются из .NET.The next stage is to wrap the native libraries so that they are easily used from .NET. Это делается с помощью решения Visual Studio с четырьмя проектами.This is done with a Visual Studio solution with four projects. Общий проект содержит общий код.A shared project contains the common code. Проекты, предназначенные для каждого из Xamarin.Android, Xamarin.iOS и .NET Standard позволяют библиотеки должно быть указано в виде независимых от платформы.Projects targeting each of Xamarin.Android, Xamarin.iOS, and .NET Standard allow the library to be referenced in a platform-agnostic manner.

В программы-оболочки используетсяфокус с подменой, "описываемого Betts пол.The wrapper uses 'the bait and switch trick,' described by Paul Betts. Это не единственный способ, но он упрощает ссылку на эту библиотеку и позволяет избежать необходимости явно управлять реализации платформы в рамках самого приложения.This is not the only way, but it makes it easy to reference the library and it avoids the need to explicitly manage platform-specific implementations within the consuming application itself. Фокус по сути является обеспечение, что целевые объекты (.NET Standard, Android, iOS) совместно используют одно пространство имен, имя сборки и структуру класса.The trick is essentially ensuring that the targets (.NET Standard, Android, iOS) share the same namespace, assembly name, and class structure. Так как NuGet всегда будет предпочитать библиотеку платформы, версии .NET Standard никогда не используется во время выполнения.Since NuGet will always prefer a platform-specific library, the .NET Standard version is never used at runtime.

Большая часть работы на этом этапе основное внимание уделяется с помощью P/Invoke для вызова методов собственной библиотеки и управление ссылками на базовые объекты.Most of the work in this step will focus on using P/Invoke to call the native library methods and managing the references to the underlying objects. Целью является для предоставления функциональных возможностей библиотеки потребителю абстрагируясь out любой сложности.The goal is to expose the library’s functionality to the consumer while abstracting out any complexity. Разработчикам Xamarin.Forms не обязательно должны иметь практические знания о внутреннем устройстве неуправляемые библиотеки.The Xamarin.Forms developers do not need to have working knowledge on the inner workings of the unmanaged library. Все должно быть, как они используют любые другие управляемые C# библиотеки.It should feel like they are using any other managed C# library.

В конечном счете выходные данные этого этапа — это набор библиотек .NET, по одному на целевой объект, а также nuspec документ, который содержит сведения, необходимые для создания пакета на следующем шаге.Ultimately, the output of this stage is a set of .NET libraries, one per target, along with a nuspec document that contains the information required in order to build the package in the next step.

Этап 3. Упаковка и передача пакета NuGet для оболочки .NETStage 3: Packing and pushing a NuGet package for the .NET wrapper

Третий этап создание пакета NuGet с помощью артефактов сборки из предыдущего шага.The third stage is creating a NuGet package using the build artifacts from the previous step. Результат с этого шага — пакет NuGet, который может использоваться из приложения Xamarin.The outcome from this step is a NuGet package that can be consumed from a Xamarin app. Пошаговое руководство использует локальный каталог для использования в качестве веб-канал NuGet.The walkthrough uses a local directory to serve as the NuGet feed. В рабочей среде этот шаг следует опубликовать пакет с открытым или частных NuGet веб-канала и должен быть полностью автоматизирован.In production, this step should publish a package to a public or private NuGet feed and should be fully automated.

Этап 4. Использование пакета NuGet из приложения Xamarin.FormsStage 4: Consuming the NuGet package from a Xamarin.Forms app

Последним шагом является ссылаться и использовать пакет NuGet из приложения Xamarin.Forms.The final step is to reference and use the NuGet package from a Xamarin.Forms app. Этот сценарий требует настройки NuGet веб-канала в Visual Studio для использования веб-канал, определенный на предыдущем шаге.This requires configuring the NuGet feed in Visual Studio to use the feed defined in the previous step.

После настройки веб-канала пакета необходимо ссылаться на каждый проект в приложении Xamarin.Forms между различными платформами.Once the feed is configured, the package needs to be referenced from each project in the cross-platform Xamarin.Forms app. «Фокус заманить и подменить» предоставляет одинаковые интерфейсы, функциональные возможности собственной библиотеки можно вызывать с помощью кода, определенные в одном месте.‘The bait-and-switch trick’ provides identical interfaces, so the native library functionality can be called using code defined in a single location.

Репозиторий исходного кода содержит список Дополнительные материалы , включены статьи о настройке частного NuGet, веб-канала в DevOps в Azure и отправки пакета канала.The source code repository contains a list of further reading that includes articles on how to set up a private NuGet feed on Azure DevOps and how to push the package to that feed. При этом немного больше времени установки, чем локальный каталог, в среде командной разработки лучше такого рода веб-канала.While requiring a little more setup time than a local directory, this type of feed is better in a team development environment.

Пошаговое руководствоWalk-through

Инструкции относятся к Visual Studio для Mac, но структура работает Visual Studio 2017 также.The steps provided are specific to Visual Studio for Mac, but the structure works in Visual Studio 2017 as well.

Предварительные требованияPrerequisites

Для выполнения этой процедуры требуется разработчика:In order to follow along, the developer will need:

Примечание

Активный учетной записи разработчика Apple необходим для развертывания приложений на iPhone.An active Apple Developer Account is required in order to deploy apps to an iPhone.

Создание собственных библиотек (этап 1)Creating the native libraries (Stage 1)

Функциональные возможности собственной библиотеки основан на примере из Пошаговое руководство: Создание и использование статической библиотеки (C++).The native library functionality is based on the example from Walkthrough: Creating and Using a Static Library (C++).

В этом пошаговом руководстве пропускает первого этапа создания собственные библиотеки, поскольку библиотеке предоставляется как зависимость независимых производителей в этом сценарии.This walkthrough skips the first stage, building the native libraries, since the library is provided as a third-party dependency in this scenario. Предварительно скомпилированные библиотеки собственного включены вместе с пример кода или может быть загрузки напрямую.The precompiled native libraries are included alongside the sample code or can be downloaded directly.

Работа с собственной библиотекиWorking with the native library

Исходный MathFuncsLib пример включает один класс с именем MyMathFuncs со следующим определением:The original MathFuncsLib example includes a single class called MyMathFuncs with the following definition:

namespace MathFuncs
{
    class MyMathFuncs
    {
    public:
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Multiply(double a, double b);
        double Divide(double a, double b);
    };
}

Дополнительный класс определяет функции-оболочки, позволяющие получателя .NET для создания, удаления и взаимодействия с собственный MyMathFuncs класса.An additional class defines wrapper functions that allow a .NET consumer to create, dispose, and interact with the underlying native MyMathFuncs class.

#include "MyMathFuncs.h"
using namespace MathFuncs;

extern "C" {
    MyMathFuncs* CreateMyMathFuncsClass();
    void DisposeMyMathFuncsClass(MyMathFuncs* ptr);
    double MyMathFuncsAdd(MyMathFuncs *ptr, double a, double b);
    double MyMathFuncsSubtract(MyMathFuncs *ptr, double a, double b);
    double MyMathFuncsMultiply(MyMathFuncs *ptr, double a, double b);
    double MyMathFuncsDivide(MyMathFuncs *ptr, double a, double b);
}

Он будет эти функции-оболочки, которые используются на Xamarin стороне.It will be these wrapper functions that are used on the Xamarin side.

Перенос собственной библиотеки (этап 2)Wrapping the native library (Stage 2)

На этом этапе требуется предварительно скомпилированные библиотеки описано в разделе выше.This stage requires the precompiled libraries described in the previous section.

Создание решения Visual StudioCreating the Visual Studio solution

  1. В Visual Studio для Mac, нажмите кнопку новый проект (из страницу приветствия) или новое решение (из файл меню).In Visual Studio for Mac, click New Project (from the Welcome Page) or New Solution (from the File menu).

  2. Из новый проект окно, выберите общий проект (изнутри Многоплатформенность > библиотеки) и нажмите кнопку Далее.From the New Project window, choose Shared Project (from within Multiplatform > Library) and then click Next.

  3. Обновите следующие поля, а затем нажмите кнопку создать:Update the following fields then click Create:

    • Имя проекта: MathFuncs.SharedProject Name: MathFuncs.Shared
    • Имя решения: MathFuncsSolution Name: MathFuncs
    • Расположение: Используйте значение по умолчанию расположение сохранения (или выбора вместо)Location: Use the default save location (or pick an alternative)
    • Создание проекта в каталоге решения: Присвойте этому параметру проверкиCreate a project within the solution directory: Set this to checked
  4. Из обозревателе решений, дважды щелкните MathFuncs.Shared проекта и перейдите к основные параметры.From Solution Explorer, double-click on the MathFuncs.Shared project and navigate to Main Settings.

  5. Удалить . Общие из пространство имен по умолчанию , ему будет присвоено MathFuncs , затем выберите ОК.Remove .Shared from the Default Namespace so it is set to MathFuncs only, then click OK.

  6. Откройте MyClass.cs (созданного с помощью шаблона), затем переименуйте класс и имя файла для MyMathFuncsWrapper и изменить пространство имен для MathFuncs.Open MyClass.cs (created by the template), then rename both the class and the filename to MyMathFuncsWrapper and change the namespace to MathFuncs.

  7. ЩЕЛКНУТЬ при нажатой клавише УПРАВЛЕНИЯ решение MathFuncs, затем выберите Добавление нового проекта... из добавить меню.CONTROL + CLICK on the solution MathFuncs, then choose Add New Project... from the Add menu.

  8. Из новый проект окно, выберите библиотеки .NET Standard (изнутри Многоплатформенность > библиотеки) и нажмите кнопку Далее.From the New Project window, choose .NET Standard Library (from within Multiplatform > Library) and then click Next.

  9. Выберите .NET Standard 2.0 и нажмите кнопку Далее.Choose .NET Standard 2.0 and then click Next.

  10. Обновите следующие поля, а затем нажмите кнопку создать:Update the following fields then click Create:

    • Имя проекта: MathFuncs.StandardProject Name: MathFuncs.Standard
    • Расположение: Используйте тот же сохранить расположении, что общий проектLocation: Use the same save location as the shared project
  11. Из обозревателе решений, дважды щелкните MathFuncs.Standard проекта.From Solution Explorer, double-click on the MathFuncs.Standard project.

  12. Перейдите к основные параметры, затем обновите пространство имен по умолчанию для MathFuncs.Navigate to Main Settings, then update Default Namespace to MathFuncs.

  13. Перейдите к вывода параметры, затем обновите имя сборки для MathFuncs.Navigate to the Output settings, then update Assembly name to MathFuncs.

  14. Перейдите к компилятора изменить параметры, конфигурации для выпуска, задание отладочная информация для Символы только щелкните ОК.Navigate to the Compiler settings, change the Configuration to Release, setting Debug information to Symbols Only then click OK.

  15. Удалить Class1.cs/Getting работы из проекта (если один из них была частью шаблона).Delete Class1.cs/Getting Started from the project (if one of these has been included as part of the template).

  16. ЩЕЛКНУТЬ при нажатой клавише УПРАВЛЕНИЯ в проекте зависимости/референты папку, нажмите кнопку изменить ссылки.CONTROL + CLICK on the project Dependencies/References folder, then choose Edit References.

  17. Выберите MathFuncs.Shared из проекты , а затем нажмите кнопку ОК.Select MathFuncs.Shared from the Projects tab, then click OK.

  18. Повторите шаги с 7-17 (игнорирование шаг 9) с помощью следующих конфигураций:Repeat steps 7-17 (ignoring step 9) using the following configurations:

    ИМЯ ПРОЕКТАPROJECT NAME ИМЯ ШАБЛОНАTEMPLATE NAME МЕНЮ "НОВЫЙ ПРОЕКТ"NEW PROJECT MENU
    MathFuncs.AndroidMathFuncs.Android Библиотека классовClass Library Android > библиотекиAndroid > Library
    MathFuncs.iOSMathFuncs.iOS Привязка библиотекиBinding Library iOS > библиотекиiOS > Library
  19. Из обозревателе решений, дважды щелкните MathFuncs.Android проекта, а затем перейдите к компилятора параметры.From Solution Explorer, double-click on the MathFuncs.Android project, then navigate to the Compiler settings.

  20. С помощью конфигурации присвоено Отладка, изменить определить символы для включения Android;.With the Configuration set to Debug, edit Define Symbols to include Android;.

  21. Изменение конфигурации для выпуска, затем измените определить символы для включения Android;.Change the Configuration to Release, then edit Define Symbols to also include Android;.

  22. Повторите шаги с 19 – 20 для MathFuncs.iOS, редактирования определить символы для включения iOS; вместо Android; в обоих случаях.Repeat steps 19-20 for MathFuncs.iOS, editing Define Symbols to include iOS; instead of Android; in both cases.

  23. Построение решения выпуска конфигурации (УПРАВЛЕНИЯ + COMMAND + B) и проверьте, что все три выходных данных сборки (Android, iOS, .NET Standard) (в папке bin соответствующего проекта) одного и того же имя MathFuncs.dll.Build the solution in Release configuration (CONTROL + COMMAND + B) and validate that all three output assemblies (Android, iOS, .NET Standard) (in the respective project bin folders) share the same name MathFuncs.dll.

На этом этапе решения должны иметь три целевых объектов, каждый для Android, iOS и .NET Standard и общий проект, на который ссылается каждый из трех целевых объектов.At this stage, the solution should have three targets, one apiece for Android, iOS and .NET Standard, and a shared project that is referenced by each of the three targets. Они должны использовать те же по умолчанию пространство имен и выходные данные сборки с тем же именем.These should be configured to use the same default namespace and output assemblies with the same name. Это необходимо для подхода «с подменой», упомянутых ранее.This is necessary for the 'bait and switch' approach mentioned previously.

Добавление собственных библиотекAdding the native libraries

Процесс добавления собственных библиотек в решение оболочки немного отличается, Android и iOS.The process of adding the native libraries to the wrapper solution varies slightly between Android and iOS.

Собственные ссылки для MathFuncs.AndroidNative references for MathFuncs.Android

  1. CONTROL + ЩЕЛКНИТЕ на MathFuncs.Android проекта, а затем выберите новую папку из добавить меню, назовите его libs.CONTROL + CLICK on the MathFuncs.Android project, then choose New Folder from the Add menu naming it libs.

  2. Для каждого ABI (двоичный интерфейс приложений), УПРАВЛЕНИЯ + ЩЕЛЧОК на libs папку, нажмите кнопку новую папку из Добавить меню, назовите его после этого соответствующие ABI.For each ABI (Application Binary Interface), CONTROL + CLICK on the libs folder, then choose New Folder from the Add menu, naming it after that respective ABI. В этом случае:In this case:

    • arm64-v8aarm64-v8a
    • armeabi-v7a;armeabi-v7a
    • x86x86
    • x86_64x86_64

    Примечание

    Более подробные сведения см. в разделе ЦП и архитектуры раздел из NDK руководство разработчика, в частности раздел об адресации машинного кода в пакеты приложений .For a more detailed overview, see the Architectures and CPUs topic from the NDK developer guide, specifically the section on addressing native code in app packages.

  3. Проверьте структуру папок:Verify the folder structure:

    - lib
        - arm64-v8a
        - armeabi-v7a
        - x86
        - x86_64
    
  4. Добавить соответствующие .so библиотеки для каждого из ABI папок, основываясь на сопоставлении, следующие:Add the corresponding .so libraries to each of the ABI folders based on the following mapping:

    arm64-v8a: libs/Android/arm64arm64-v8a: libs/Android/arm64

    armeabi-v7a: libs/Android/armarmeabi-v7a: libs/Android/arm

    x86: libs/Android/x86x86: libs/Android/x86

    x86_64: libs/Android/x86_64x86_64: libs/Android/x86_64

    Примечание

    Для добавления файлов, УПРАВЛЕНИЯ + ЩЕЛЧОК на папку, представляющую соответствующих ABI, затем выберите добавить файлы... из добавить меню.To add files, CONTROL + CLICK on the folder representing the respective ABI, then choose Add Files... from the Add menu. Выберите соответствующую библиотеку (из PrecompiledLibs directory) нажмите кнопку откройте и нажмите кнопку ОК оставить параметр по умолчанию, чтобы копирования файл в каталог.Choose the appropriate library (from the PrecompiledLibs directory) then click Open and then click OK leaving the default option to Copy the file to the directory.

  5. Для каждого из .so файлы, УПРАВЛЕНИЯ + ЩЕЛЧОК выберите EmbeddedNativeLibrary вариант действие при построении меню.For each of the .so files, CONTROL + CLICK then choose the EmbeddedNativeLibrary option from the Build Action menu.

Теперь libs папки должен выглядеть следующим образом:Now the libs folder should appear as follows:

- lib
    - arm64-v8a
        - libMathFuncs.so
    - armeabi-v7a
        - libMathFuncs.so
    - x86
        - libMathFuncs.so
    - x86_64
        - libMathFuncs.so

Собственные ссылки для MathFuncs.iOSNative references for MathFuncs.iOS

  1. CONTROL + ЩЕЛКНИТЕ на MathFuncs.iOS проекта, а затем выберите добавить собственную ссылку из добавить меню.CONTROL + CLICK on the MathFuncs.iOS project, then choose Add Native Reference from the Add menu.

  2. Выберите libMathFuncs.a библиотеки (из библиотек или ios, в разделе PrecompiledLibs directory) нажмите кнопку OpenChoose the libMathFuncs.a library (from libs/ios under the PrecompiledLibs directory) then click Open

  3. CONTROL + ЩЕЛКНИТЕ на libMathFuncs файла (в собственные ссылки папку, нажмите кнопку свойства из менюCONTROL + CLICK on the libMathFuncs file (within the Native References folder, then choose the Properties option from the menu

  4. Настройка собственную ссылку таким образом, чтобы они проверяются (отображается значок тактов) в свойства панели:Configure the Native Reference properties so they are checked (showing a tick icon) in the Properties Pad:

    • Принудительная загрузкаForce Load
    • Is C++Is C++
    • Интеллектуальная связьSmart Link

    Примечание

    С помощью типа проекта библиотеки привязки вместе с собственную ссылку внедряет статическую библиотеку и позволяет ей быть автоматически связываются с приложением Xamarin.iOS, которое ссылается на нее (даже когда он включается с помощью пакета NuGet).Using a binding library project type along with a native reference embeds the static library and enables it to be automatically linked with the Xamarin.iOS app that references it (even when it is included via a NuGet package).

  5. Откройте ApiDefinition.cs, удаление шаблонную закомментированном коде (останется только MathFuncs пространство имен), затем выполните этот шаг для Structs.csOpen ApiDefinition.cs, deleting the templated commented code (leaving only the MathFuncs namespace), then perform the same step for Structs.cs

    Примечание

    Проект библиотеки привязки требуются эти файлы (с ObjCBindingApiDefinition и ObjCBindingCoreSource действия при сборке) для сборки.A Binding library project requires these files (with the ObjCBindingApiDefinition and ObjCBindingCoreSource build actions) in order to build. Тем не менее мы напишем код, для вызова нашей собственной библиотеки вне эти файлы в виде, могут совместно использоваться цели библиотеки iOS и Android с помощью стандартных P/Invoke.However, we will write the code, to call our native library, outside of these files in a way that can be shared between both Android and iOS library targets using standard P/Invoke.

Написание кода управляемой библиотекиWriting the managed library code

Теперь запишите C# код для вызова собственной библиотеки.Now, write the C# code to call the native library. Цель — скрыть любой сложности.The goal is to hide any underlying complexity. Потребитель не нужен любой опыт работы внутренних компонентов собственной библиотеки или концепций P/Invoke.The consumer should not need any working knowledge of the native library internals or of P/Invoke concepts.

Создание SafeHandleCreating a SafeHandle

  1. CONTROL + ЩЕЛКНИТЕ на MathFuncs.Shared проекта, а затем выберите Add File... из добавить меню.CONTROL + CLICK on the MathFuncs.Shared project, then choose Add File... from the Add menu.

  2. Выберите пустой класс из новый файл окна, назовите его MyMathFuncsSafeHandle и нажмите кнопку NewChoose Empty Class from the New File window, name it MyMathFuncsSafeHandle and then click New

  3. Реализуйте MyMathFuncsSafeHandle класса:Implement the MyMathFuncsSafeHandle class:

    using System;
    using Microsoft.Win32.SafeHandles;
    
    namespace MathFuncs
    {
        internal class MyMathFuncsSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
        {
            public MyMathFuncsSafeHandle() : base(true) { }
    
            public IntPtr Ptr => this.handle;
    
            protected override bool ReleaseHandle()
            {
                // TODO: Release the handle here
                return true;
            }
        }
    }
    

    Примечание

    Объект SafeHandle является более предпочтительным для работы с неуправляемыми ресурсами в управляемом коде.A SafeHandle is the preferred way to work with unmanaged resources in managed code. Это упрощает массу стереотипного кода, связанные с жизненным циклом критические завершения и объекта.This abstracts away a lot of boilerplate code related to critical finalization and object lifecycle. Владелец этого дескриптора впоследствии можно расценивать это как любой другой управляемый ресурс и не получат реализации полного шаблон уничтожаемых объектов.The owner of this handle can subsequently treat it like any other managed resource and will not have to implement the full Disposable pattern.

Создание внутренний класс-оболочкаCreating the internal wrapper class

  1. Откройте MyMathFuncsWrapper.cs, заменить его на внутренний статический классOpen MyMathFuncsWrapper.cs, changing it to an internal static class

    namespace MathFuncs
    {
        internal static class MyMathFuncsWrapper
        {
        }
    }
    
  2. В этом же файле добавьте в класс следующий условный оператор:In the same file, add the following conditional statement to the class:

    #if Android
        const string DllName = "libMathFuncs.so";
    #else
        const string DllName = "__Internal";
    #endif
    

    Примечание

    Этот параметр задает DllName постоянное значение, основанное на ли сборки библиотеки для Android или iOS.This sets the DllName constant value based on whether the library is being built for Android or iOS. Это позволяет устранить различные соглашения об именовании, используемые каждой соответствующей платформы, но и тип библиотеки, в этом случае использовать.This is to address the different naming conventions used by each respective platform but also the type of library being used in this case. Android использует динамической библиотеки и поэтому ожидает, что имя файла, включая расширение.Android is using a dynamic library and so expects a filename including extension. Для iOS "__Internal" является обязательным, так как мы используем статической библиотеки.For iOS, '__Internal' is required since we are using a static library.

  3. Добавьте ссылку на System.Runtime.InteropServices в верхней части MyMathFuncsWrapper.cs файлаAdd a reference to System.Runtime.InteropServices at the top of the MyMathFuncsWrapper.cs file

    using System.Runtime.InteropServices;
    
  4. Добавьте методы создания оболочки для создания и реализации MyMathFuncs класса:Add the wrapper methods to handle the creation and disposal of the MyMathFuncs class:

    [DllImport(DllName, EntryPoint = "CreateMyMathFuncsClass")]
    internal static extern MyMathFuncsSafeHandle CreateMyMathFuncs();
    
    [DllImport(DllName, EntryPoint = "DisposeMyMathFuncsClass")]
    internal static extern void DisposeMyMathFuncs(MyMathFuncsSafeHandle ptr);
    

    Примечание

    Мы передаем наш константа DllName для DllImport атрибута вместе с EntryPoint явно которой среда выполнения .NET имя вызываемой функции в этой библиотеке.We are passing in our constant DllName to the DllImport attribute along with the EntryPoint which explicitly tells the .NET runtime the name of the function to call within that library. С технической точки зрения, нам не нужно предоставить EntryPoint значение, если были идентична неуправляемый наших имен управляемого метода.Technically, we do not need to provide the EntryPoint value if our managed method names were identical to the unmanaged one. Если значение не указано, будет использоваться имя управляемого метода как EntryPoint вместо этого.If one is not provided, the managed method name would be used as the EntryPoint instead. Тем не менее лучше указывать явно.However, it is better to be explicit.

  5. Добавьте методы программы-оболочки, чтобы мы могли работать с MyMathFuncs класса, используя следующий код:Add the wrapper methods to enable us to work with the MyMathFuncs class using the following code:

    [DllImport(DllName, EntryPoint = "MyMathFuncsAdd")]
    internal static extern double Add(MyMathFuncsSafeHandle ptr, double a, double b);
    
    [DllImport(DllName, EntryPoint = "MyMathFuncsSubtract")]
    internal static extern double Subtract(MyMathFuncsSafeHandle ptr, double a, double b);
    
    [DllImport(DllName, EntryPoint = "MyMathFuncsMultiply")]
    internal static extern double Multiply(MyMathFuncsSafeHandle ptr, double a, double b);
    
    [DllImport(DllName, EntryPoint = "MyMathFuncsDivide")]
    internal static extern double Divide(MyMathFuncsSafeHandle ptr, double a, double b);
    

    Примечание

    Для параметров в этом примере мы используем простые типы.We're using simple types for the parameters in this example. Поскольку маршалинга является побитовое копирование-в этом случае он не требует дополнительных действий с нашей стороны.Since marshalling is a bitwise-copy in this case it requires no additional work on our part. Также Обратите внимание на использование MyMathFuncsSafeHandle класса вместо стандартного IntPtr.Also notice the use of the MyMathFuncsSafeHandle class instead of the standard IntPtr. IntPtr автоматически сопоставляется с SafeHandle в рамках процесса маршалинга.The IntPtr is automatically mapped to the SafeHandle as part of the marshalling process.

  6. Убедитесь, что готовый MyMathFuncsWrapper класс отображается как ниже:Verify that the finished MyMathFuncsWrapper class appears as below:

    using System.Runtime.InteropServices;
    
    namespace MathFuncs
    {
        internal static class MyMathFuncsWrapper
        {
            #if Android
                const string DllName = "libMathFuncs.so";
            #else
                const string DllName = "__Internal";
            #endif
    
            [DllImport(DllName, EntryPoint = "CreateMyMathFuncsClass")]
            internal static extern MyMathFuncsSafeHandle CreateMyMathFuncs();
    
            [DllImport(DllName, EntryPoint = "DisposeMyMathFuncsClass")]
            internal static extern void DisposeMyMathFuncs(MyMathFuncsSafeHandle ptr);
    
            [DllImport(DllName, EntryPoint = "MyMathFuncsAdd")]
            internal static extern double Add(MyMathFuncsSafeHandle ptr, double a, double b);
    
            [DllImport(DllName, EntryPoint = "MyMathFuncsSubtract")]
            internal static extern double Subtract(MyMathFuncsSafeHandle ptr, double a, double b);
    
            [DllImport(DllName, EntryPoint = "MyMathFuncsMultiply")]
            internal static extern double Multiply(MyMathFuncsSafeHandle ptr, double a, double b);
    
            [DllImport(DllName, EntryPoint = "MyMathFuncsDivide")]
            internal static extern double Divide(MyMathFuncsSafeHandle ptr, double a, double b);
        }
    }
    

Завершение работы MyMathFuncsSafeHandle-классCompleting the MyMathFuncsSafeHandle class

  1. Откройте MyMathFuncsSafeHandle класса, перейдите к заполнитель TODO комментарий в ReleaseHandle метод:Open the MyMathFuncsSafeHandle class, navigate to the placeholder TODO comment within the ReleaseHandle method:

    // TODO: Release the handle here
    
  2. Замените TODO строки:Replace the TODO line:

    MyMathFuncsWrapper.DisposeMyMathFuncs(this);
    

Класс MyMathFuncsWriting the MyMathFuncs class

Теперь, когда завершена оболочки, создайте класс MyMathFuncs, который будет управлять ссылку на неуправляемый объект C++ MyMathFuncs.Now that the wrapper is complete, create a MyMathFuncs class that will manage the reference to the unmanaged C++ MyMathFuncs object.

  1. CONTROL + ЩЕЛКНИТЕ на MathFuncs.Shared проекта, а затем выберите Add File... из добавить меню.CONTROL + CLICK on the MathFuncs.Shared project, then choose Add File... from the Add menu.

  2. Выберите пустой класс из новый файл окна, назовите его MyMathFuncs и нажмите кнопку NewChoose Empty Class from the New File window, name it MyMathFuncs and then click New

  3. Добавьте следующие члены для MyMathFuncs класса:Add the following members to the MyMathFuncs class:

    readonly MyMathFuncsSafeHandle handle;
    
  4. Реализуйте конструктор для класса, поэтому он создает и сохраняет дескриптор для собственного MyMathFuncs объекта при создании экземпляра класса:Implement the constructor for the class so it creates and stores a handle to the native MyMathFuncs object when the class is instantiated:

    public MyMathFuncs()
    {
        handle = MyMathFuncsWrapper.CreateMyMathFuncs();
    }
    
  5. Реализуйте IDisposable интерфейс, используя следующий код:Implement the IDisposable interface using the following code:

    public class MyMathFuncs : IDisposable
    {
        ...
    
        protected virtual void Dispose(bool disposing)
        {
            if (handle != null && !handle.IsInvalid)
                handle.Dispose();
        }
    
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    
        // ...
    }
    
  6. Реализуйте MyMathFuncs методов с помощью MyMathFuncsWrapper классом для выполнения реальной работы за кулисами, передавая указатель, мы сохранили на базовый неуправляемый объект.Implement the MyMathFuncs methods using the MyMathFuncsWrapper class to perform the real work under the hood by passing in the pointer we have stored to the underlying unmanaged object. Код должен иметь следующий вид:The code should be as follows:

    public double Add(double a, double b)
    {
        return MyMathFuncsWrapper.Add(handle, a, b);
    }
    
    public double Subtract(double a, double b)
    {
        return MyMathFuncsWrapper.Subtract(handle, a, b);
    }
    
    public double Multiply(double a, double b)
    {
        return MyMathFuncsWrapper.Multiply(handle, a, b);
    }
    
    public double Divide(double a, double b)
    {
        return MyMathFuncsWrapper.Divide(handle, a, b);
    }
    

Создание метаданных nuspecCreating the nuspec

Чтобы получить библиотеку комплектуется и распространяется через NuGet, решение должно nuspec файла.In order to have the library packaged and distributed via NuGet, the solution needs a nuspec file. Это определит, какие из полученные сборки будут включены для каждой поддерживаемой платформы.This will identify which of the resulting assemblies will be included for each supported platform.

  1. ЩЕЛКНУТЬ при нажатой клавише УПРАВЛЕНИЯ решение MathFuncs, затем выберите добавить папку решения из добавить меню, назовите его SolutionItems.CONTROL + CLICK on the solution MathFuncs, then choose Add Solution Folder from the Add menu naming it SolutionItems.

  2. ЩЕЛКНУТЬ при нажатой клавише УПРАВЛЕНИЯ на SolutionItems папку, затем выберите новый файл... из добавить меню.CONTROL + CLICK on the SolutionItems folder, then choose New File... from the Add menu.

  3. Выберите пустой XML-файл из новый файл окна, назовите его MathFuncs.nuspec и нажмите кнопку New.Choose Empty XML File from the New File window, name it MathFuncs.nuspec and then click New.

  4. Обновление MathFuncs.nuspec с метаданными основного пакета, которое будет отображаться для NuGet потребителя.Update MathFuncs.nuspec with the basic package metadata to be displayed to the NuGet consumer. Пример:For example:

    <?xml version="1.0"?>
    <package>
        <metadata>
            <id>MathFuncs</id>
            <version>$version$</version>
            <authors>Microsoft Mobile Customer Advisory Team</authors>
            <description>Sample C++ Wrapper Library</description>
            <requireLicenseAcceptance>false</requireLicenseAcceptance>
            <copyright>Copyright 2018</copyright>
        </metadata>
    </package>
    

    Примечание

    См. в разделе Справочник по файлу nuspec документ более подробные данные в схему, используемую для этого манифеста.See the nuspec reference document for further detail on the schema used for this manifest.

  5. Добавить <files> как дочерний элемент элемента <package> элемент (непосредственно под <metadata>), указывая каждый файл с отдельным <file> элемент:Add a <files> element as a child of the <package> element (just below <metadata>), identifying each file with a separate <file> element:

    <files>
    
        <!-- Android -->
    
        <!-- iOS -->
    
        <!-- netstandard2.0 -->
    
    </files>
    

    Примечание

    При установке пакета в проект, а там, где несколько сборок с тем же именем, указанным, NuGet будет эффективно выберите сборки, наиболее подходящую для данной платформы.When a package is installed into a project, and where there are multiple assemblies specified by the same name, NuGet will effectively choose the assembly that is most specific to the given platform.

  6. Добавить <file> элементы для Android сборки:Add the <file> elements for the Android assemblies:

    <file src="MathFuncs.Android/bin/Release/MathFuncs.dll" target="lib/MonoAndroid81/MathFuncs.dll" />
    <file src="MathFuncs.Android/bin/Release/MathFuncs.pdb" target="lib/MonoAndroid81/MathFuncs.pdb" />
    
  7. Добавить <file> элементы для iOS сборки:Add the <file> elements for the iOS assemblies:

    <file src="MathFuncs.iOS/bin/Release/MathFuncs.dll" target="lib/Xamarin.iOS10/MathFuncs.dll" />
    <file src="MathFuncs.iOS/bin/Release/MathFuncs.pdb" target="lib/Xamarin.iOS10/MathFuncs.pdb" />
    
  8. Добавить <file> элементы для netstandard2.0 сборки:Add the <file> elements for the netstandard2.0 assemblies:

    <file src="MathFuncs.Standard/bin/Release/netstandard2.0/MathFuncs.dll" target="lib/netstandard2.0/MathFuncs.dll" />
    <file src="MathFuncs.Standard/bin/Release/netstandard2.0/MathFuncs.pdb" target="lib/netstandard2.0/MathFuncs.pdb" />
    
  9. Проверьте nuspec манифеста:Verify the nuspec manifest:

    <?xml version="1.0"?>
    <package>
    <metadata>
        <id>MathFuncs</id>
        <version>$version$</version>
        <authors>Microsoft Mobile Customer Advisory Team</authors>
        <description>Sample C++ Wrapper Library</description>
        <requireLicenseAcceptance>false</requireLicenseAcceptance>
        <copyright>Copyright 2018</copyright>
    </metadata>
    <files>
    
        <!-- Android -->
        <file src="MathFuncs.Android/bin/Release/MathFuncs.dll" target="lib/MonoAndroid81/MathFuncs.dll" />
        <file src="MathFuncs.Android/bin/Release/MathFuncs.pdb" target="lib/MonoAndroid81/MathFuncs.pdb" />
    
        <!-- iOS -->
        <file src="MathFuncs.iOS/bin/Release/MathFuncs.dll" target="lib/Xamarin.iOS10/MathFuncs.dll" />
        <file src="MathFuncs.iOS/bin/Release/MathFuncs.pdb" target="lib/Xamarin.iOS10/MathFuncs.pdb" />
    
        <!-- netstandard2.0 -->
        <file src="MathFuncs.Standard/bin/Release/netstandard2.0/MathFuncs.dll" target="lib/netstandard2.0/MathFuncs.dll" />
        <file src="MathFuncs.Standard/bin/Release/netstandard2.0/MathFuncs.pdb" target="lib/netstandard2.0/MathFuncs.pdb" />
    
    </files>
    </package>
    

    Примечание

    Этот файл указывает пути вывода сборки из выпуска сборки, поэтому убедитесь, что решение создать, используя эту конфигурацию.This file specifies the assembly output paths from a Release build, so be sure to build the solution using that configuration.

На этом этапе решение содержит 3 сборок .NET и вспомогательного nuspec манифеста.At this point, the solution contains 3 .NET assemblies and a supporting nuspec manifest.

Распространение оболочки .NET с помощью NuGetDistributing the .NET wrapper with NuGet

Следующим шагом является упаковки и распространения пакета NuGet, поэтому он может быть легко способности, используемый приложением и управляется как зависимость.The next step is to package and distribute the NuGet package so it may be easily consumed by the app and managed as a dependency. Упаковки и потребления может быть выполнено в одном решении, но распространение библиотеку с помощью средства NuGet в разделение и позволяет нам управлять их баз кода независимо друг от друга.The wrapping and consumption could all be done within a single solution, but distributing the library via NuGet aids in decoupling and enables us to manage these codebases independently.

Подготовка каталога локальные пакетыPreparing a local packages directory

Самая простая форма веб-канал NuGet это локальный каталог:The simplest form of NuGet feed is a local directory:

  1. В Finder, перейдите к удобной папке.In Finder, navigate to a convenient directory. Например /пользователи.For example, /Users.
  2. Выберите новую папку из файл меню, таких как указание понятного имени local канала nuget.Choose New Folder from the File menu, providing a meaningful name such as local-nuget-feed.

Создание пакетаCreating the package

  1. Задайте конфигурация сборки для выпускаи выполнить сборки с использованием COMMAND + B.Set the Build Configuration to Release, and execute a build using COMMAND + B.

  2. Откройте терминалов и укажите путь к папке, содержащей nuspec файла.Open Terminal and change directory to the folder containing the nuspec file.

  3. В терминалов, выполнение пакет nuget указания команды nuspec файл, версии (например, 1.0.0) и OutputDirectory с помощью папки, созданной на предыдущего шага, то есть local канала nuget.In Terminal, execute the nuget pack command specifying the nuspec file, the Version (for example, 1.0.0), and the OutputDirectory using the folder created in the previous step, that is, local-nuget-feed. Пример:For example:

    nuget pack MathFuncs.nuspec -Version 1.0.0 -OutputDirectory ~/local-nuget-feed
    
  4. Подтвердите , MathFuncs.1.0.0.nupkg будет создана в local канала nuget каталога.Confirm that MathFuncs.1.0.0.nupkg has been created in the local-nuget-feed directory.

[НЕОБЯЗАТЕЛЬНО] С помощью частной веб-канала NuGet с помощью DevOps в Azure[OPTIONAL] Using a private NuGet feed with Azure DevOps

Более надежный способ описан в приступить к работе с пакетами NuGet в Azure DevOps, который показывает, как для создания закрытого канала и отправки пакета (созданный на предыдущем шаге) для канала.A more robust technique is described in Get started with NuGet packages in Azure DevOps, which shows how to create a private feed and push the package (generated in the previous step) to that feed.

Это идеальный вариант для этого рабочего процесса, полностью автоматизирована, например с помощью конвейеры Azure.It is ideal to have this workflow fully automated, for example using Azure Pipelines. Дополнительные сведения см. в разделе приступить к работе с Azure конвейеры.For more information, see Get started with Azure Pipelines.

Использование оболочки .NET из приложения Xamarin.FormsConsuming the .NET wrapper from a Xamarin.Forms app

Для выполнения данного пошагового руководства, создайте Xamarin.Forms опубликованные приложения для использования пакета только в локальную NuGet веб-канала.To complete the walkthrough, create a Xamarin.Forms app to consume the package just published to the local NuGet feed.

Создание Xamarin.Forms проектаCreating the Xamarin.Forms project

  1. Откройте новый экземпляр класса Visual Studio для Mac.Open a new instance of Visual Studio for Mac. Это можно сделать из терминалов:This can be done from Terminal:

    open -n -a "Visual Studio"
    
  2. В Visual Studio для Mac, нажмите кнопку новый проект (из страницу приветствия) или новое решение (из файл меню).In Visual Studio for Mac, click New Project (from the Welcome Page) or New Solution (from the File menu).

  3. Из новый проект окно, выберите приложение с пустыми формами (изнутри Многоплатформенность > приложение) и нажмите кнопку Далее.From the New Project window, choose Blank Forms App (from within Multiplatform > App) and then click Next.

  4. Обновите следующие поля, а затем нажмите кнопку Далее:Update the following fields then click Next:

    • Имя приложения: MathFuncsApp.App Name: MathFuncsApp.
    • Идентификатор организации: Использовать обратное пространство имен, например, com. {your_org}.Organization Identifier: Use a reverse namespace, for example, com.{your_org}.
    • Целевые платформы: Используйте значение по умолчанию (Android и iOS целевые объекты).Target Platforms: Use the default (both Android and iOS targets).
    • Общий код: Установите .NET Standard (решение «Общая библиотека» становится возможной, но выходит за рамки этого пошагового руководства).Shared Code: Set this to .NET Standard (a “Shared Library” solution is possible, but beyond the scope of this walkthrough).
  5. Обновите следующие поля, а затем нажмите кнопку создать:Update the following fields then click Create:

    • Имя проекта: MathFuncsApp.Project Name: MathFuncsApp.
    • Имя решения: MathFuncsApp.Solution Name: MathFuncsApp.
    • Расположение: Используйте значение по умолчанию расположение сохранения (или выбора альтернативы).Location: Use the default save location (or pick an alternative).
  6. В обозревателе решений, УПРАВЛЕНИЯ + ЩЕЛЧОК на целевом объекте (MathFuncsApp.Android или MathFuncs.iOS) для начального тестирования, затем Выберите Назначить запускаемым проектом.In Solution Explorer, CONTROL + CLICK on the target (MathFuncsApp.Android or MathFuncs.iOS) for initial testing, then choose Set As Startup Project.

  7. Выберите предпочтительный устройства или симулятор/эмулятор.Choose the preferred device or Simulator/Emulator.

  8. Запустите решение (КОМАНДУ + ВОЗВРАЩАЕМОЕ) чтобы проверить, что шаблонную Xamarin.Forms выполнено построение проекта и работает нормально.Run the solution (COMMAND + RETURN) to validate that the templated Xamarin.Forms project builds and runs okay.

    Примечание

    iOS (в частности имитатор) обычно имеют минимальное время сборки/развертывания.iOS (specifically the simulator) tends to have the fastest build/deploy time.

Добавление пакета NuGet локального веб-канал NuGet конфигурацииAdding the local NuGet feed to the NuGet configuration

  1. В Visual Studio, выберите предпочтения (из Visual Studio меню).In Visual Studio, choose Preferences (from the Visual Studio menu).

  2. Выберите источников из NuGet раздела, а затем щелкните добавить.Choose Sources from under the NuGet section, then click Add.

  3. Обновите следующие поля, а затем нажмите кнопку добавить источник:Update the following fields then click Add Source:

    • Имя: Введите понятное имя, например, Local-пакеты.Name: Provide a meaningful name, for example, Local-Packages.
    • Расположение: Укажите local канала nuget папки, созданной на предыдущего шага.Location: Specify the local-nuget-feed folder created in the previous step.

    Примечание

    В этом случае нет необходимости для указания Username и пароль.In this case there is no need to specify a Username and Password.

  4. Нажмите кнопку ОК.Click OK.

Указание ссылок на пакетReferencing the package

Повторите перечисленные ниже шаги для каждого проекта (MathFuncsApp, MathFuncsApp.Android, и MathFuncsApp.iOS).Repeat the following steps for each project (MathFuncsApp, MathFuncsApp.Android, and MathFuncsApp.iOS).

  1. CONTROL + ЩЕЛКНИТЕ на проект, а затем выберите добавить пакеты NuGet... из добавить меню.CONTROL + CLICK on the project, then choose Add NuGet Packages... from the Add menu.
  2. Поиск MathFuncs.Search for MathFuncs.
  3. Проверьте версии пакета является 1.0.0 и другие сведения отображаются, такие как должным образом Title и описание, то есть , MathFuncs и образец библиотеки-оболочки C++.Verify the Version of the package is 1.0.0 and the other details appear as expected such as the Title and Description, that is, MathFuncs and Sample C++ Wrapper Library.
  4. Выберите MathFuncs пакета, а затем щелкните Add Package.Select the MathFuncs package, then click Add Package.

С помощью функции библиотекиUsing the library functions

Теперь, со ссылкой на MathFuncs пакет в каждый из проектов, эти функции доступны для C# кода.Now, with a reference to the MathFuncs package in each of the projects, the functions are available to the C# code.

  1. Откройте MainPage.xaml.cs изнутри MathFuncsApp распространенных Xamarin.Formsпроекта (ссылаются оба MathFuncsApp.Androidи MathFuncsApp.iOS).Open MainPage.xaml.cs from within the MathFuncsApp common Xamarin.Formsproject (referenced by both MathFuncsApp.Android and MathFuncsApp.iOS).

  2. Добавить с помощью инструкций для System.Diagnostics и MathFuncs в верхней части файла:Add using statements for System.Diagnostics and MathFuncs at the top of the file:

    using System.Diagnostics;
    using MathFuncs;
    
  3. Объявите экземпляр MyMathFuncs класс в верхней части MainPage класса:Declare an instance of the MyMathFuncs class at the top of the MainPage class:

    MyMathFuncs myMathFuncs;
    
  4. Переопределить OnAppearing и OnDisappearing методы из ContentPage базового класса:Override the OnAppearing and OnDisappearing methods from the ContentPage base class:

    protected override void OnAppearing()
    {
        base.OnAppearing();
    }
    
    protected override void OnDisappearing()
    {
        base.OnDisappearing();
    }
    
  5. Обновление OnAppearing метод для инициализации myMathFuncs переменная объявлена ранее:Update the OnAppearing method to initialize the myMathFuncs variable declared previously:

    protected override void OnAppearing()
    {
        base.OnAppearing();
        myMathFuncs = new MyMathFuncs();
    }
    
  6. Обновление OnDisappearing метод для вызова Dispose метод myMathFuncs:Update the OnDisappearing method to call the Dispose method on myMathFuncs:

    protected override void OnDisappearing()
    {
        base.OnAppearing();
        myMathFuncs.Dispose();
    }
    
  7. Реализовать частный метод, именуемый TestMathFuncs следующим образом:Implement a private method called TestMathFuncs as follows:

    private void TestMathFuncs()
    {
        var numberA = 1;
        var numberB = 2;
    
        // Test Add function
        var addResult = myMathFuncs.Add(numberA, numberB);
    
        // Test Subtract function
        var subtractResult = myMathFuncs.Subtract(numberA, numberB);
    
        // Test Multiply function
        var multiplyResult = myMathFuncs.Multiply(numberA, numberB);
    
        // Test Divide function
        var divideResult = myMathFuncs.Divide(numberA, numberB);
    
        // Output results
        Debug.WriteLine($"{numberA} + {numberB} = {addResult}");
        Debug.WriteLine($"{numberA} - {numberB} = {subtractResult}");
        Debug.WriteLine($"{numberA} * {numberB} = {multiplyResult}");
        Debug.WriteLine($"{numberA} / {numberB} = {divideResult}");
    }
    
  8. Наконец, вызовите TestMathFuncs в конце OnAppearing метод:Finally, call TestMathFuncs at the end of the OnAppearing method:

    TestMathFuncs();
    
  9. Запустите приложение для каждой целевой платформы и проверить выходные данные в выходные данные приложения панели выглядит следующим образом:Run the app on each target platform and validate the output in the Application Output Pad appears as follows:

    1 + 2 = 3
    1 - 2 = -1
    1 * 2 = 2
    1 / 2 = 0.5
    

    Примечание

    При возникновении "DLLNotFoundException" при тестирование на платформе Android или ошибку построения для iOS, не забудьте проверить, что архитектура ЦП/эмулятора или симулятора устройства при использовании совместим с подмножество, которое мы решили Поддержка.If you encounter a 'DLLNotFoundException' when testing on Android, or a build error on iOS, be sure to check that the CPU architecture of the device/emulator/simulator you are using is compatible with the subset that we chose to support.

СводкаSummary

В этой статье было рассмотрено, как создать приложение Xamarin.Forms, которое использует собственные библиотеки посредством общих оболочки .NET распространение с помощью пакета NuGet.This article explained how to create a Xamarin.Forms app that uses native libraries through a common .NET wrapper distributed via a NuGet package. Пример, приведенный в этом пошаговом руководстве намеренно очень упрощен, чтобы упростить демонстрируют подход.The example provided in this walkthrough is intentionally very simplistic to more easily demonstrate the approach. Реальное приложение будет иметь дело сложностей, таких как обработка исключений, обратные вызовы, маршалинг более сложных типов и связывание с другими библиотеками зависимостей.A real application will have to deal with complexities such as exception handling, callbacks, the marshalling of more complex types, and linking with other dependency libraries. Следует принимать во внимание — это процесс, который развития кода C++ координируемых и синхронизированы с помощью программы-оболочки и клиентских приложений.A key consideration is the process by which the evolution of the C++ code is coordinated and synced with the wrapper and client applications. Этот процесс может зависеть от одного или обоих этих угроз, являются ли ответственность за одной командой.This process may vary depending on whether one or both of those concerns are the responsibility of a single team. В любом случае автоматизации — это настоящее преимущество.Either way, automation is a real benefit. Ниже приведены некоторые ресурсы, предоставляя дополнительные материалы устраняет некоторые основные понятия, а также соответствующие файлы для загрузки.Below are some resources providing further reading around some of the key concepts along with the relevant downloads.

ЗагрузкиDownloads

ПримерыExamples

Дополнительные сведенияFurther Reading

Статьи, относящиеся к содержимому этой записиArticles relating to the content of this post