Проблемы компиляции Flutter на iOS, наверняка, многие из вас встречали. Возможно, вы сталкивались с ответами типа "очистите проект несколько раз" или "перестройте его несколько раз". Даже после решения этих проблем, состояние вашего проекта может находиться в неопределенности. Поэтому в этой статье я также хочу записать некоторые проблемы, связанные со смешением Objective-C и Swift при работе с динамическими и статическими библиотеками в Flutter, надеюсь это поможет вам.
Итак, какие проблемы могут возникнуть, когда вы внедряете плагин на Swift в проект на Objective-C?
На следующем рисунке показана ситуация, когда если ваш проект Flutter старый, то возможно появится ошибка "не найдено" для плагина на Swift.
Часто предлагается добавить в файл 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
представляет собой скомпилированный код, который объединяет исходный код и код библиотеки в один исполняемый файл. Она привязывается к архитектуре устройства и не содержит ресурсных файлов, таких как изображения;Еще одной конфигурацией является use_modular_headers!
, предназначенной для преобразования pods в модульные, так как модульные заголовочные файлы можно импортировать прямо в Swift, без необходимости использования файла bridge-header для моста.> Однако после активации use_modular_headers!
, будет использоваться более строгий путь поиска заголовочных файлов. После этого pods будут использовать более строгое правило поиска пути и создание модульной карты, что может вызвать повторное использование в исторических проектах, поскольку в некоторых старых проектах CocoaPods использует Header Search Paths для завершения процесса компиляции. Конечно, использование use_modular_headers!
может повысить производительность загрузки и уменьшить объём. Продолжая тему, после добавления use_frameworks!
, вы можете столкнуться с различными ошибками вида undefined symbol. Не паникуйте, так как это связано с использованием статических библиотек в Swift.
Очевидно, что поведение Swift, которое не поддерживает статические библиотеки, является некорректным. Поэтому начиная с Xcode 9, Swift начал поддерживать статические библиотеки. С версии CocoaPods 1.9.0 была представлена возможность использования use_frameworks! :linkage => :static
, чтобы поддерживать ситуации с использованием статических библиотек и frameworks.
После изменения конфигурации use_frameworks!
и добавления static
, все ошибки типа undefined symbol должны исчезнуть. Однако при запуске могут возникнуть новые проблемы в виде non-modular header.
Если вы будете искать решение этой проблемы, то найдете множество ответов, которые предлагают установить значение Allow Non-modular Includes in Framework Modules
равным true
. Однако стоит отметить, что это временное решение для экстренной ситуации.
Конечно, вы также можете отдельно настроить 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>
;-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 )