1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/CarGuo-GSYFlutterBook

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Flutter-BIOS.md 12 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 10.03.2025 00:06 5767d61

Flutter iOS ОС смешивание Objective-C с Swift проблемы с динамическими и статическими библиотеками решение

Проблемы компиляции Flutter на iOS, наверняка, многие из вас встречали. Возможно, вы сталкивались с ответами типа "очистите проект несколько раз" или "перестройте его несколько раз". Даже после решения этих проблем, состояние вашего проекта может находиться в неопределенности. Поэтому в этой статье я также хочу записать некоторые проблемы, связанные со смешением Objective-C и Swift при работе с динамическими и статическими библиотеками в Flutter, надеюсь это поможет вам.

image-20220422091858815

Итак, какие проблемы могут возникнуть, когда вы внедряете плагин на Swift в проект на Objective-C?

На следующем рисунке показана ситуация, когда если ваш проект Flutter старый, то возможно появится ошибка "не найдено" для плагина на Swift.

image-20220422093205569

Часто предлагается добавить в файл Podfile строки use_frameworks! и иногда use_modular_headers!. Какие они выполняют роли?

target 'Runner' do
  use_frameworks!  
  use_modular_headers!
  flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
end

Мы знаем, что Podfile используется для управления CocoaPods, а use_frameworks! сообщает CocoaPods, что мы хотим использовать Framework вместо статических библиотек. По умолчанию Swift не поддерживает статические библиотеки, поэтому есть ограничение, что Swift должна использовать Framework.Основное различие между статическими библиотеками и framework заключается в следующем:

  • Статическая библиотека с расширением .a представляет собой скомпилированный код, который объединяет исходный код и код библиотеки в один исполняемый файл. Она привязывается к архитектуре устройства и не содержит ресурсных файлов, таких как изображения;
  • Framework представляет собой формат, который позволяет упаковать динамическую библиотеку, заголовочные файлы и ресурсные файлы вместе. Динамическая библиотека — это такой тип библиотеки, который не интегрируется в исполняемый файл, но динамически связывается во время выполнения;

Еще одной конфигурацией является use_modular_headers!, предназначенной для преобразования pods в модульные, так как модульные заголовочные файлы можно импортировать прямо в Swift, без необходимости использования файла bridge-header для моста.> Однако после активации use_modular_headers!, будет использоваться более строгий путь поиска заголовочных файлов. После этого pods будут использовать более строгое правило поиска пути и создание модульной карты, что может вызвать повторное использование в исторических проектах, поскольку в некоторых старых проектах CocoaPods использует Header Search Paths для завершения процесса компиляции. Конечно, использование use_modular_headers! может повысить производительность загрузки и уменьшить объём. Продолжая тему, после добавления use_frameworks!, вы можете столкнуться с различными ошибками вида undefined symbol. Не паникуйте, так как это связано с использованием статических библиотек в Swift.image-20220422103410759

Очевидно, что поведение Swift, которое не поддерживает статические библиотеки, является некорректным. Поэтому начиная с Xcode 9, Swift начал поддерживать статические библиотеки. С версии CocoaPods 1.9.0 была представлена возможность использования use_frameworks! :linkage => :static, чтобы поддерживать ситуации с использованием статических библиотек и frameworks.

После изменения конфигурации use_frameworks! и добавления static, все ошибки типа undefined symbol должны исчезнуть. Однако при запуске могут возникнуть новые проблемы в виде non-modular header.

image-20220422104501881

Если вы будете искать решение этой проблемы, то найдете множество ответов, которые предлагают установить значение Allow Non-modular Includes in Framework Modules равным true. Однако стоит отметить, что это временное решение для экстренной ситуации.

image-20220422105705987

Конечно, вы также можете отдельно настроить ALLOW в .podspec файлах проблемных плагинов, что приведет к аналогичному эффекту, но более легковесному решению.

s.user_target_xcconfig = { 'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES' }

Почему этот подход считается ненадежным? Потому что вы не знаете, когда Apple может удалить эту возможность. Тем не менее, сообщество предлагает различные решения:- Если ошибка вызвана использованием шапки из динамического framework, можно использовать #import "MyFile.h" вместо #import <MyFramework/MyFile.h>;

  • Переместите #import в .m файл (не помещайте его в .h файл), чтобы избежать ошибки non-modular header, например: https://github.com/AFNetworking/AFNetworking/pull/2206/files;
  • Переименуйте шапку таким образом, чтобы она не совпадала с именем модуля, используя #import <FrameworkName/Header.h>;
  • Настройте OTHER_SWIFT_FLAGS в build settings -Xcc -Wno-error=non-modular-include-in-framework-module.

Возможно, эти решения помогут вам, но почему они работают? Какое из этих решений выбрать при следующей встрече с такой же проблемой? Возвращаясь к нашей проблеме, ключевой момент заключается в том, что нельзя использовать нон-модульные заголовочные файлы в модуле Framework Module, то есть проблема состоит в том, что в модуле Framework Module загружены заголовочные файлы, принадлежащие другому модулю, а поскольку заголовочные файлы являются публичными (например, они указаны в s.public_header_files), это приводит к тому, что нон-модульные заголовочные файлы также становятся доступными для внешнего использования, что создаёт риск. Поэтому моё решение очень простое:

*Добавьте в s.public_header_files только те .h файлы плагинов, которые должны быть открытыми, а используйте нон-модульные заголовочные файлы так, чтобы они не были публичными, тем самым соответствуя требованиям и достигая успешной компиляции.Основная идея здесь заключается в том, чтобы не ссылаться на заголовочные файлы Objective-C, которые не предназначены для публичного использования, в umbrella заголовочном файле как на подмодули. Это объясняет логику решения проблемы путем перемещения #import-строки в .m файл.

Например, иногда вы можете ссылаться на системные C модули, и при модулировании framework могут возникнуть аналогичные проблемы.

Итак, понимание причины и метода решения позволяет избежать грубого подхода к конфигурации LLVM для установки Allow Non-modular Includes in Framework Modules, который решает проблему Шредингера.

Кроме того, вам может потребоваться следующее, например, сообщение об ошибке сборки для симулятора iOS, указывающее на недопустимость arm64, неудачу BITCODE, конфликты версий SWIFT и т.д.:

post_install do |installer|
  installer.pods_project.targets.each do |target|
    flutter_additional_ios_build_settings(target)
    target.build_configurations.each do |config|
      # сборка для iOS Simulator, но ссылается на объектный файл, скомпилированный для iOS, для архитектуры ‘arm64’
      config.build_settings['EXCLUDED_ARCHS[sdk=iphonesimulator*]'] = 'arm64'
      # не поддерживается BITCODE
      config.build_settings['ENABLE_BITCODE'] = 'NO'
      # решение проблемы модулей swift
      config.build_settings['SWIFT_VERSION'] = '5.0'
    end
  end
end

Наконец, последнее замечание: бережите волосы, избегайте смешивания Swift.

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/CarGuo-GSYFlutterBook.git
git@api.gitlife.ru:oschina-mirror/CarGuo-GSYFlutterBook.git
oschina-mirror
CarGuo-GSYFlutterBook
CarGuo-GSYFlutterBook
master