Подтвердить что ты не робот

Использование Cocoapods в расширении приложения с использованием структуры

У меня есть приложение (пусть его называют MyApp), написанное в Swift со следующими целями:

  • MyApp: главная цель
  • MyAppKit: целевое построение рамки для кода, который используется совместно с приложением и его расширением (-ами), в основном с использованием API-интерфейса и обработки базы данных
  • MyAppWidget: вид виджета Today View (или что бы он ни называл сейчас), который использует структуру MyAppKit.

Структура MyAppKit привязана к каждой цели, которая использует ее, а именно MyApp и MyAppWidget. Введите Cocoapods: у меня была следующая структура Podfile:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    # Mostly UI or convenience pods
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    # Backend pods for networking, storage, etc.
    pod 'Alamofire', '~> 4.0'
    pod 'Fuzi', '~> 1.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Result', '~> 3.0'
end

target 'MyAppWidget' do
    # Added here event though the target only imports MyAppKit but it worked
    pod 'RealmSwift', '~> 2.0'
end

Цель здесь заключалась в том, чтобы разоблачить только структуру MyAppKit для других частей, а не для всех ее модулей (например, я не хочу иметь возможность import Alamofire в основное приложение). Однако, начиная с Cocoapods 1.2.0 RCs, pod install не удалась со следующей ошибкой: [!] The 'Pods-MyApp' target has frameworks with conflicting names: realm and realmswift. , Он работал, потому что контейнеры были объявлены для расширения, но только встроены в хост-приложение (подробнее см. Эту проблему). Поэтому я удалил контейнеры из целевого объекта виджета, оставив мне только пустую target 'MyAppWidget'.

В этой конфигурации pod install выполняется нормально, но компиляция не выполняется на этапе компоновки для цели MyAppWidget: ld: framework not found Realm for architecture x86_64. Это можно устранить, явно добавив как Realm.framework и RealmSwift.framework в RealmSwift.framework "Link Binary With Libraries" и следующий параметр сборки в целевом Pods-MyAppWidget.[debug/release].xcconfig:

FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Realm" "$PODS_CONFIGURATION_BUILD_DIR/RealmSwift"'

Тем не менее, всякий раз, когда я запускаю pod install, настройки сборки, естественно, возвращаются, и мне нужно снова добавить настройки сборки.

Я вижу следующие решения:

  • Добавьте post_install хук, добавляя эти настройки каждый раз, но он кажется "взломанным" и после нескольких ошибочных попыток, я не нашел ссылки на API и не знаю, как добавить эти параметры в целевой объект MyAppWidget через скрипт.
  • Измените подфайл на следующую структуру (или даже заверните ее в абстрактную цель):

    [...]
    target 'MyAppKit' do
        # Backend pods for networking, storage, etc.
        pod 'Alamofire', '~> 4.0'
        pod 'Fuzi', '~> 1.0'
        pod 'KeychainAccess', '~> 3.0'
        pod 'RealmSwift', '~> 2.0'
        pod 'Result', '~> 3.0'
    
        target 'MyAppWidget' do
            inherit! :search_paths # Because else we get the "conflicting names" error
        end
    end
    

    Который кажется логичным для меня в смысле "виджет должен знать, где искать во время компоновки, но не нуждается в контейнерах как таковых", но это не добавляет вышеупомянутые настройки сборки (я, вероятно, неправильно :search_paths inheritance) (edit: он работает, но не с абстрактной мишенью). Эта идея пришла ко мне, потому что в более старых версиях CocoaPods решение, по- видимому, должно было добавить link_with, который теперь устарел.

  • Expose Realm также находится в целевом MyApp, однако это противоречит моей цели - не иметь доступ к коду "backend" в главном коде (это может быть чисто эстетично?).

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

Приветствия и спасибо заранее!


РЕДАКТИРОВАТЬ

Следуя замечанию Приента, я изучил возможности абстракции и наследования. Основные проблемы, которые я сейчас раскрыл, на самом деле многообразны:

  • Раньше он работал перед Cocoapods 1.2.0, потому что контейнеры, объявленные под целью виджета, были встроены в хост-приложение, но все еще связаны с виджетами. Нет, он просто отказывается иметь стручки с одним и тем же именем для разных целей в соотношении "главное против расширения"
  • Использование абстрактных целей недостаточно, потому что цели не могут наследовать только пути поиска (inherit! :search_paths) от абстрактной цели.
  • Пути поиска могут быть унаследованы от реальной цели, такой как MyAppKit, но это предоставляет все эти MyApp кода MyApp (чего я хочу избежать), и все еще существует проблема связывания структуры Realm (поскольку на самом деле виджет использует мельчайший бит геттер и, следовательно, нуждается в нем).

Использование этой последней опции и ручная привязка Realm.framework работает, но субоптимально относительно моих намерений и того, что использовалось для работы. Некоторые из этих вопросов, как представляется, ошибка в соответствии с различными вопросами на GitHub Cocoapods. Я добавил свою собственную проблему и обновляю, когда у меня есть новости.

4b9b3361

Ответ 1

Итак, что дает:

  • Моя забота о "разделении контейнеров между целями" абсурдна, потому что вы все равно можете импортировать их где угодно.
  • Проблема "вы должны вручную связать" исправлена ​​простым инструктором import RealmSwift.

Таким образом, фиксированный и рабочий подфайл:

platform :ios, '8.0'
use_frameworks!

target 'MyApp' do
    pod 'Eureka', '~> 2.0.0-beta'
    pod 'PKHUD', '~> 4.0'
    pod '1PasswordExtension', '~> 1.8'
end

target 'MyAppKit' do
    pod 'Fuzi', '~> 1.0'
    pod 'RealmSwift', '~> 2.0'
    pod 'Alamofire', '~> 4.0'
    pod 'KeychainAccess', '~> 3.0'
    pod 'Result', '~> 3.0'

    target 'MyAppWidget' do
        inherit! :search_paths
    end
end

И что это. Я бы сказал, что старое поведение было более очевидным и не требовало прочтения "наследования целевого подкаста". Однако я многому научился. Ура!

Ответ 2

Я тебя не знаю. Но для меня совершенно законно и разумно иметь расширение, а приложение-хост содержит все контейнеры, которые определяет инфраструктура. И вот что я имею в виду:

def shared_pods
    pod 'Alamofire'
end

target 'Framework' do
    shared_pods
end

target 'Host' do
    shared_pods
    // Some other pods
end

target 'Extension' do
    shared_pods
end

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

target 'Host' do
    pod Framework, :path => '../Framework'
end

Но тогда вы должны поддерживать файл podspec.

Ответ 3

Это пример профиля проекта SWIFT-3.0.

platform :ios, '8.0'

def import_public_pods

  pod 'SwiftyJSON'

end


target 'Demo' do
  use_frameworks!

  # Pods for Demo
  import_public_pods 
  pod 'Fabric'
  pod 'Crashlytics'

  target 'DemoTests' do
    inherit! :search_paths
    # Pods for testing
  end

  target 'DemoUITests' do
    inherit! :search_paths
    # Pods for testing
  end

end


target 'DemoKit' do
  use_frameworks!

  # Pods for DemoKit
  import_public_pods
  pod 'RealmSwift'

  target 'DemoKitTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

Ответ 4

Чтобы отключить создание/запуск созданного NSExtension, вам необходимо:

  1. Щелкните файл проекта в навигаторе проекта.
  2. Щелкните содержащую цель приложения (ту, которую вы хотите запустить)
  3. Вкладка "Сборка фаз"
  4. Открытые целевые зависимости
  5. Удалите расширение (тот, который вы НЕ хотите запускать)
  6. Чтобы вернуть его, просто нажмите знак + в том же месте и снова добавьте его.

В моем случае, работая успешно