Поделиться через


Пошаговое руководство. Привязка библиотеки Swift для iOS

Внимание

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

Xamarin позволяет разработчикам мобильных устройств создавать кроссплатформенные собственные мобильные интерфейсы с помощью Visual Studio и C#. Компоненты пакета SDK для платформы iOS можно использовать из поля. Но во многих случаях вы также хотите использовать сторонние пакеты SDK, разработанные для этой платформы, которые Xamarin позволяет выполнять с помощью привязок. Чтобы включить стороннюю Objective-C платформу в приложение Xamarin.iOS, необходимо создать для него привязку Xamarin.iOS, прежде чем использовать ее в приложениях.

Платформа iOS, наряду с собственными языками и инструментами, постоянно развивается и Swift является одной из самых динамических областей в мире разработки iOS прямо сейчас. Существует ряд сторонних пакетов SDK, которые уже были перенесены с Objective-C Swift, и он представляет нам новые проблемы. Несмотря на то, что процесс привязки Swift аналогичен Objective-C, он требует дополнительных шагов и параметров конфигурации для успешной сборки и запуска приложения Xamarin.iOS, приемлемого для AppStore.

Цель этого документа — описать общий подход для подготовки такого сценария и предоставить подробные пошаговые инструкции с простым примером.

Общие сведения

Swift первоначально появился Apple в 2014 году и в настоящее время находится на версии 5.1 с внедрением сторонних платформ быстро растет. У вас есть несколько вариантов привязки платформы Swift, и этот документ описывает подход с помощью Objective-C созданного заголовка интерфейса. Заголовок автоматически создается средствами Xcode при создании платформы и используется в качестве способа обмена данными из управляемого мира в мир Swift.

Необходимые компоненты

Чтобы выполнить это пошаговое руководство, вам потребуется:

Сборка собственной библиотеки

Первым шагом является создание собственной платформы Swift Framework с Objective-C включенным заголовком. Платформа обычно предоставляется сторонним разработчиком и содержит заголовок, внедренный в пакет в следующем каталоге: FrameworkName.framework/Headers/<FrameworkName-Swift.h>>.<

Этот заголовок предоставляет общедоступные интерфейсы, которые будут использоваться для создания метаданных привязки Xamarin.iOS и создания классов C# для предоставления членам платформы Swift. Если заголовок не существует или имеет неполный открытый интерфейс (например, вы не видите классы и члены), у вас есть два варианта:

  • Обновите исходный код Swift, чтобы создать заголовок и пометить необходимые элементы атрибутом @objc
  • Создание прокси-платформы, в которой вы управляете общедоступным интерфейсом и прокси-сервером всех вызовов базовой платформы

В этом руководстве описан второй подход, так как он имеет меньше зависимостей от стороннего исходного кода, который не всегда доступен. Еще одна причина, по которой следует избегать первого подхода, — это дополнительные усилия, необходимые для поддержки будущих изменений платформы. После добавления изменений в сторонний исходный код вы несете ответственность за поддержку этих изменений и потенциально объединяя их с каждым будущим обновлением.

Например, в этом руководстве создается привязка для пакета SDK Gigya Swift:

  1. Откройте Xcode и создайте новую платформу Swift, которая будет прокси-сервером между кодом Xamarin.iOS и сторонней платформой Swift. Нажмите кнопку "Создать > проект" > и выполните действия мастера.

    xcode create framework project

    xcode name framework project

  2. Скачайте Gigya xcframework с веб-сайта разработчика и распакуйте его. На момент написания последней версии является пакет SDK Gigya Swift 1.5.3.

  3. Выберите SwiftFrameworkProxy из обозревателя файлов проекта, а затем перейдите на вкладку "Общие"

  4. Перетащите пакет Gigya.xcframework в список Xcode Frameworks и библиотек на вкладке "Общие", проверка элементы копирования при необходимости при добавлении платформы:

    xcode copy framework

    Убедитесь, что платформа Swift была добавлена в проект, в противном случае следующие параметры не будут доступны.

  5. Убедитесь, что выбран параметр Do Not Embed , который будет позже контролироваться вручную:

    xcode donotembed option

  6. Убедитесь, что параметр "Сборка Параметры Always Embed Standard", который включает библиотеки Swift с платформой, имеет значение No. Позже он будет контролироваться вручную, которые swift dylibs включены в окончательный пакет:

    xcode always embed false option

  7. Убедитесь, что для параметра Enable Bitcode задано значение No. По состоянию на данный момент Xamarin.iOS не включает Bitcode, в то время как Apple требует, чтобы все библиотеки поддерживали те же архитектуры:

    xcode enable bitcode false option

    Вы можете убедиться, что в результирующих платформах отключен параметр Bitcode, выполнив следующую команду терминала для платформы:

    otool -l SwiftFrameworkProxy.framework/SwiftFrameworkProxy | grep __LLVM
    

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

  8. Убедитесь, что Objective-C параметр "Имя заголовка созданного интерфейса" включен и указывает имя заголовка. Имя по умолчанию — FrameworkName-Swift.h>:<

    xcode objectice-c header enabled option

    Совет

    Если этот параметр недоступен, сначала необходимо добавить .swift файл в проект, как описано ниже, а затем вернуться к Build Settings параметру, который должен быть обнаружен.

  9. Предоставьте нужные методы и пометьте их атрибутом @objc и примените дополнительные правила, определенные ниже. Если вы создаете платформу без этого шага, созданный Objective-C заголовок будет пустым, и Xamarin.iOS не сможет получить доступ к членам платформы Swift. Предоставляйте логику инициализации для базового пакета SDK Gigya Swift, создав новый файл SwiftFrameworkProxy.swift и определив следующий код:

    import Foundation
    import UIKit
    import Gigya
    
    @objc(SwiftFrameworkProxy)
    public class SwiftFrameworkProxy : NSObject {
    
        @objc
        public func initFor(apiKey: String) -> String {
            Gigya.sharedInstance().initFor(apiKey: apiKey)
            let gigyaDomain = Gigya.sharedInstance().config.apiDomain
            let result = "Gigya initialized with domain: \(gigyaDomain)"
            return result
        }
    }
    

    Несколько важных примечаний к приведенному выше коду:

    • Gigya Импорт модуля здесь из исходного стороннего пакета SDK Gigya позволяет получить доступ к любому члену платформы.
    • Помечайте класс SwiftFrameworkProxy с атрибутом @objc , указывающим имя, в противном случае будет создано уникальное непрочитаемое имя, например _TtC19SwiftFrameworkProxy19SwiftFrameworkProxy. Имя типа должно быть четко определено, так как оно будет использоваться позже его именем.
    • Наследуйте прокси-класс от NSObject, в противном случае он не будет создан в файле заголовка Objective-C .
    • Пометьте все элементы, предоставляемые как public.
  10. Измените конфигурацию сборки схемы с отладки на выпуск. Чтобы сделать это, откройте диалоговое окно "Схема редактирования целевого объекта > Xcode>", а затем установите для параметра "Конфигурация сборки" значение Release:

    xcode edit scheme

    xcode edit scheme release

  11. На этом этапе платформа готова к созданию. Создайте платформу для архитектур симулятора и устройства, а затем объедините выходные данные в виде одного пакета двоичной платформы (.xcframework). Выполните сборку со следующими командами:

    xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \
      -scheme "SwiftFrameworkProxy" \
      -configuration Release \
      -archivePath "build/SwiftFrameworkProxy-simulator.xcarchive" \
      -destination "generic/platform=iOS Simulator" \
      -derivedDataPath "build" \
      -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \
      ENABLE_BITCODE=NO \
      SKIP_INSTALL=NO \
      BUILD_LIBRARY_FOR_DISTRIBUTION=YES
    
     xcodebuild -project "Swift/SwiftFrameworkProxy/SwiftFrameworkProxy.xcodeproj" archive \
       -scheme "SwiftFrameworkProxy" \
       -configuration Release \
       -archivePath "build/SwiftFrameworkProxy-ios.xcarchive" \
       -destination "generic/platform=iOS" \
       -derivedDataPath "build" \
       -IDECustomBuildProductsPath="" -IDECustomBuildIntermediatesPath="" \
       ENABLE_BITCODE=NO \
       SKIP_INSTALL=NO \
       BUILD_LIBRARY_FOR_DISTRIBUTION=YES
    

    Совет

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

    Совет

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

  12. Существует два архива с созданными платформами, по одному для каждой платформы, объединяют их в один двоичный пакет платформы, который будет внедрен в проект привязки Xamarin.iOS позже. Чтобы создать пакет двоичной платформы, который объединяет обе архитектуры, необходимо выполнить следующие действия. Пакет Xcarchive — это только папка, поэтому можно выполнять все типы операций, например добавление, удаление и замена файлов:

    • xcframework Создайте в архивах ранее встроенные платформы:

      xcodebuild -create-xcframework \
        	-framework "build/SwiftFrameworkProxy-simulator.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \
        	-framework "build/SwiftFrameworkProxy-ios.xcarchive/Products/Library/Frameworks/SwiftFrameworkProxy.framework" \
        	-output "build/SwiftFrameworkProxy.xcframework"
      

    Совет

    Если вы хотите поддерживать только одну платформу (например, вы создаете приложение, которое можно запускать только на устройстве), можно пропустить шаг, чтобы создать библиотеку Xcframework и использовать выходную платформу из сборки устройства ранее.

    Совет

    Вы также можете использовать вспомогательный скрипт для создания Xcframework, который автоматизирует все описанные выше действия.

Подготовка метаданных

В настоящее время необходимо иметь Xcframework с Objective-C созданным заголовком интерфейса, готовым к использованию привязкой Xamarin.iOS. Следующим шагом является подготовка интерфейсов определения API, которые используются проектом привязки для создания классов C#. Эти определения можно создавать вручную или автоматически с помощью средства Objective Sharpie и созданного файла заголовка. Используйте Sharpie для создания метаданных:

  1. Скачайте последнее средство Objective Sharpie с официального веб-сайта загрузки и установите его, следуя мастеру. После завершения установки его можно проверить, выполнив команду sharpie:

    sharpie -v
    
  2. Создайте метаданные с помощью sharpie и файла заголовка, созданного Objective-C автоматически:

    sharpie bind --sdk=iphoneos16.4 --output="XamarinApiDef" --namespace="Binding" --scope="build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/" "build/SwiftFrameworkProxy.xcframework/ios-arm64/SwiftFrameworkProxy.framework/Headers/SwiftFrameworkProxy-Swift.h"
    

    Выходные данные отражают созданный файл метаданных: ApiDefinitions.cs. Сохраните этот файл для следующего шага, чтобы включить его в проект привязки Xamarin.iOS вместе с собственными ссылками:

    Parsing 1 header files...
    Binding...
        [write] ApiDefinitions.cs
    

    Средство создаст метаданные C# для каждого предоставленного Objective-C элемента, который будет выглядеть примерно так же, как показано в следующем коде. Как видите, его можно определить вручную, так как он имеет удобочитаемый для человека формат и простое сопоставление элементов:

    [Export ("initForApiKey:")]
    string InitForApiKey (string apiKey);
    

    Совет

    Имя файла заголовка может отличаться, если вы изменили параметры Xcode по умолчанию для имени заголовка. По умолчанию он имеет имя проекта с суффиксом -Swift . Вы всегда можете проверка файл и его имя, перейдя к папке заголовков пакета платформы.

    Совет

    В рамках процесса автоматизации можно использовать вспомогательный скрипт для автоматического создания метаданных после создания Xcframework.

Сборка библиотеки привязки

Далее необходимо создать проект привязки Xamarin.iOS с помощью шаблона привязки Visual Studio, добавить необходимые метаданные, собственные ссылки, а затем создать проект для создания используемой библиотеки:

  1. Откройте Visual Studio для Mac и создайте проект библиотеки привязки Xamarin.iOS, присвойте ему имя, в этом случае SwiftFrameworkProxy.Binding и завершите работу мастера. Шаблон привязки Xamarin.iOS расположен по следующему пути: библиотека привязки библиотеки >iOS>:

    visual studio create binding library

  2. Удалите существующий файл метаданных ApiDefinition.cs , так как он будет полностью заменен метаданными, созданными средством Objective Sharpie.

  3. Скопируйте метаданные, созданные Sharpie на одном из предыдущих шагов, выберите следующее действие сборки в окне свойств: ObjBindingApiDefinition для файла ApiDefinitions.cs и ObjBindingCoreSource для файла StructsAndEnums.cs:

    visual studio project structure metadata

    Сами метаданные описывают каждый предоставленный Objective-C класс и член с помощью языка C#. Вы можете увидеть исходное Objective-C определение заголовка вместе с объявлением C#:

    // @interface SwiftFrameworkProxy : NSObject
    [BaseType (typeof(NSObject))]
    interface SwiftFrameworkProxy
    {
        // -(NSString * _Nonnull)initForApiKey:(NSString * _Nonnull)apiKey __attribute__((objc_method_family("none"))) __attribute__((warn_unused_result));
        [Export ("initForApiKey:")]
        string InitForApiKey (string apiKey);
    }
    

    Несмотря на то что это допустимый код C#, он не используется как есть, но вместо этого используется средствами Xamarin.iOS для создания классов C# на основе этого определения метаданных. В результате вместо интерфейса SwiftFrameworkProxy вы получаете класс C# с тем же именем, который можно создать экземпляром кода Xamarin.iOS. Этот класс получает методы, свойства и другие элементы, определенные метаданными, которые будут вызываться способом C#.

  4. Добавьте собственную ссылку на ранее созданный пакет двоичной платформы, а также каждую зависимость этой платформы. В этом случае добавьте собственные ссылки на платформу SwiftFrameworkProxy и Gigya в проект привязки:

    • Чтобы добавить ссылки на собственные платформы, откройте средство поиска и перейдите в папку с помощью платформ. Перетащите платформы в расположение "Собственные ссылки" в Обозреватель решений. Кроме того, можно использовать параметр контекстного меню в папке "Собственные ссылки" и нажмите кнопку "Добавить собственную ссылку ", чтобы найти платформы и добавить их:

    visual studio project structure native references

    • Обновите свойства каждой собственной ссылки и проверка три важных варианта:

      • Set Smart Link = true
      • Set Force Load = false
      • Задайте список платформ, используемых для создания исходных платформ. В этом случае каждая платформа имеет только две зависимости: Foundation и UIKit. Задайте для него поле Frameworks:

      visual studio nativeref proxy options

      Если у вас есть дополнительные флаги компоновщика, задайте их в поле флагов компоновщика. В этом случае сохраните его пустым.

    • При необходимости укажите дополнительные флаги компоновщика. Если библиотека, которую вы привязываете, предоставляет только Objective-C API, но внутренне использует Swift, возможно, возникают такие проблемы:

      error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCore
      error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftQuartzCore
      error MT5209 : Native linking error : warning: Auto-Linking library not found for -lswiftCoreImage
      

      В свойствах проекта привязки для собственной библиотеки необходимо добавить следующие значения в флаги компоновщика:

      L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator/ -L/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphoneos -Wl,-rpath -Wl,@executable_path/Frameworks
      

      Первые два варианта ( -L ... те) сообщают собственному компилятору, где найти библиотеки swift. Собственный компилятор будет игнорировать библиотеки, которые не имеют правильной архитектуры, что означает, что можно передать расположение для библиотек симулятора и библиотек устройств одновременно, чтобы он работал как для симуляторов, так и для сборок устройств (эти пути являются правильными только для iOS; для tvOS и watchOS они должны быть обновлены). Одним из недостатков является то, что этот подход требует, чтобы правильный Xcode был в /Application/Xcode.app, если потребитель библиотеки привязки имеет Xcode в другом расположении, он не будет работать. Альтернативное решение заключается в добавлении этих параметров в дополнительные аргументы mtouch в параметрах сборки iOS исполняемого проекта (--gcc_flags -L... -L...). Третий вариант делает собственный компоновщик хранить расположение быстрых библиотек в исполняемом файле, чтобы ос могли их найти.

  5. Последнее действие — создать библиотеку и убедиться, что у вас нет ошибок компиляции. Часто вы найдете, что метаданные привязок, созданные Objective Sharpie, будут аннотированы атрибутом [Verify] . Эти атрибуты указывают, что вы должны убедиться, что Objective Sharpie сделал правильное действие, сравнивая привязку с исходным Objective-C объявлением (которое будет предоставлено в комментарии над ограничивающим объявлением). Дополнительные сведения о членах, помеченных атрибутом, см. по следующей ссылке. После создания проекта его можно использовать приложением Xamarin.iOS.

Использование библиотеки привязки

Последним шагом является использование библиотеки привязки Xamarin.iOS в приложении Xamarin.iOS. Создайте проект Xamarin.iOS, добавьте ссылку на библиотеку привязки и активируйте пакет SDK Gigya Swift:

  1. Создайте проект Xamarin.iOS. Приложение с одним представлением приложения > iOS > можно использовать в качестве отправной точки:

    visual studio app new

  2. Добавьте ссылку на проект привязки к целевому проекту или .dll, созданному ранее. Рассматривайте библиотеку привязки как обычную библиотеку Xamarin.iOS:

    visual studio app refs

  3. Обновите исходный код приложения и добавьте логику инициализации в основной ViewController, которая активирует пакет SDK Gigya

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        var proxy = new SwiftFrameworkProxy();
        var result = proxy.InitForApiKey("APIKey");
        System.Diagnostics.Debug.WriteLine(result);
    }
    
  4. Создайте кнопку с именем btnLogin и добавьте следующий обработчик нажатия кнопки, чтобы активировать поток проверки подлинности:

    private void btnLogin_Tap(object sender, EventArgs e)
    {
        _proxy.LoginWithProvider(GigyaSocialProvidersProxy.Instagram, this, (result, error) =>
        {
            // process your login result here
        });
    }
    
  5. Запустите приложение, в выходных данных отладки вы увидите следующую строку: Gigya initialized with domain: us1.gigya.com Нажмите кнопку, чтобы активировать поток проверки подлинности:

    swift proxy result

Поздравляем! Вы успешно создали приложение Xamarin.iOS и библиотеку привязки, которая использует платформу Swift. Приведенное выше приложение будет успешно работать в iOS 12.2+ так как начиная с этой версии iOS Apple представила стабильность ABI и все iOS начиная с 12.2+ включают библиотеки среды выполнения Swift, которые можно использовать для запуска приложения, скомпилированного с swift 5.1+. Если необходимо добавить поддержку более ранних версий iOS, выполните несколько действий.

  1. Чтобы добавить поддержку iOS 12.1 и более ранних версий, необходимо отправить определенные dylibs Swift, используемые для компиляции платформы. Используйте пакет NuGet Xamarin.iOS.SwiftRuntimeSupport Для обработки и копирования необходимых libs с помощью IPA. Добавьте ссылку NuGet в целевой проект и перестройте приложение. Дальнейшие шаги не требуются, пакет NuGet установит определенные задачи, выполняемые с помощью процесса сборки, определите необходимые dylibs Swift и упаковает их с окончательным IPA.

  2. Чтобы отправить приложение в магазин приложений, который вы хотите использовать Xcode и распространить параметр, который обновит файл IPA и папку SwiftSupport dylibs, чтобы она была принята AppStore:

    Fx Архивируйте приложение. В меню Visual Studio для Mac выберите "Сборка > архива для публикации":

    visual studio archive for publishing

    Это действие создает проект и достигает его организатору, который доступен Xcode для распространения.

    Fx Распространение через Xcode. Откройте Xcode и перейдите в меню "Организатор окна>":

    visual studio archives

    Выберите архив, созданный на предыдущем шаге, и нажмите кнопку "Распространить приложение". Следуйте инструкциям мастера, чтобы отправить приложение в AppStore.

  3. Этот шаг является необязательным, но важно убедиться, что приложение может работать в iOS 12.1 и более ранних версиях, а также 12.2. Это можно сделать с помощью платформы Test Cloud и UITest. Создайте проект UITest и базовый тест пользовательского интерфейса, который запускает приложение:

    • Создайте проект UITest и настройте его для приложения Xamarin.iOS:

      visual studio uitest new

      Совет

      Дополнительные сведения о создании проекта UITest и его настройке для приложения см. по следующей ссылке.

    • Создайте базовый тест для запуска приложения и используйте некоторые функции пакета SDK Swift. Этот тест активирует приложение, пытается войти в систему, а затем нажмите кнопку отмены:

      [Test]
      public void HappyPath()
      {
          app.WaitForElement(StatusLabel);
          app.WaitForElement(LoginButton);
          app.Screenshot("App loaded.");
          Assert.AreEqual(app.Query(StatusLabel).FirstOrDefault().Text, "Gigya initialized with domain: us1.gigya.com");
      
          app.Tap(LoginButton);
          app.WaitForElement(GigyaWebView);
          app.Screenshot("Login activated.");
      
          app.Tap(CancelButton);
          app.WaitForElement(LoginButton);
          app.Screenshot("Login cancelled.");
      }
      

      Совет

      Дополнительные сведения о платформе UITests и модель автоматизации пользовательского интерфейса см. по следующей ссылке.

    • Создайте приложение iOS в центре приложений, создайте тестовый запуск с новым набором устройств для запуска теста:

      visual studio app center new

      Совет

      Дополнительные сведения о AppCenter Test Cloud см. по следующей ссылке.

    • Установка интерфейса командной строки центра приложений

      npm install -g appcenter-cli
      

      Внимание

      Убедитесь, что у вас установлен узел версии 6.3 или более поздней версии.

    • Запустите тест с помощью следующей команды. Кроме того, убедитесь, что в командной строке центра приложений вошли в систему.

      appcenter test run uitest --app "Mobile-Customer-Advisory-Team/SwiftBinding.iOS" --devices a7e7cb50 --app-path "Xamarin.SingleView.ipa" --test-series "master" --locale "en_US" --build-dir "Xamarin/Xamarin.SingleView.UITests/bin/Debug/"
      
    • Проверьте результат. На портале AppCenter перейдите к запуску тестового теста > приложений:>

      visual studio appcenter uitest result

      Выберите нужный тестовый запуск и проверьте результат:

      visual studio appcenter uitest runs

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