Utilisation de Cocoapods dans une extension d'application à l'aide d'un cadre

J'ai une application (appelons-la MyApp) écrite dans Swift avec les cibles suivantes:

  • MyApp : la cible principale
  • MyAppKit : une cible établissant un cadre pour le code partagé entre l'application et ses extensions, principalement le backend de l'API et la gestion de la database
  • MyAppWidget : un widget "Vue d'aujourd'hui" (ou quel que soit son nom actuel) qui utilise le framework MyAppKit .

Le framework MyAppKit est lié à chaque cible qui l'utilise, à savoir MyApp et MyAppWidget . Entrer Cocoapods: J'avais l'habitude d'avoir la structure de Podfile suivante:

 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 

Le but ici était d'exposer uniquement le framework MyAppKit aux autres parties et pas à tous ses modules (par exemple, je ne veux pas pouvoir import Alamofire dans l'application principale). Cependant, en commençant par les RC Cocoapods 1.2.0, l' pod install échoué avec l'erreur suivante: [!] The 'Pods-MyApp' target has frameworks with conflicting names: realm and realmswift. . Cela fonctionnait parce que les pods étaient déclarés pour l'extension mais seulement embeddeds dans l'application hôte (voir ce numéro pour plus d'informations). J'ai donc retiré les pods de la cible du widget, me laissant avec juste une ligne target 'MyAppWidget' .

Avec cette configuration, l' pod install s'exécute MyAppWidget mais la compilation échoue à l'étape de binding pour la cible MyAppWidget : ld: framework not found Realm for architecture x86_64 . Cela peut être corrigé en ajoutant explicitement à la fois le Realm.framework et le RealmSwift.framework à la section "Link Binary With Libraries" et le paramètre de construction suivant dans les Pods-MyAppWidget.[debug/release].xcconfig la cible Pods-MyAppWidget.[debug/release].xcconfig :

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

Cependant, chaque fois que pod install , les parameters de construction sont naturellement inversés et je dois à nouveau append les parameters de construction.

Je vois les solutions suivantes:

  • Ajouter un hook post_install ajoutant ces parameters à chaque fois, mais cela semble "hacky" et après quelques tentatives mal orientées, je n'ai trouvé aucune reference d'API et je ne sais pas comment append ces parameters à la cible MyAppWidget par le biais du script.
  • Remplacez le file Podfile par la structure suivante (ou même en l'enveloppant dans une cible abstraite):

     [...] 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 

    Ce qui me semble logique dans le sens de "le widget devrait savoir où regarder pendant la binding mais n'a pas besoin des pods en soi" mais cela n'ajoute pas les parameters de construction mentionnés précédemment (je me :search_paths probablement l'inheritance :search_paths ) : cela fonctionne réellement, mais pas avec une cible abstraite). Cette idée m'est venue parce que dans les anciennes versions de CocoaPods, la solution était apparemment d'append link_with , qui est maintenant obsolète.

  • Expose Realm également dans la cible MyApp , mais cela est en conflit avec mon objective de ne pas avoir access au code "backend" dans le code principal (il pourrait être purement esthétique?).

Alors, voici ma question: quel est le meilleur moyen d'intégrer des pods dans un cadre partagé entre l'application principale et l'extension tout en étant capable de comstackr, sans avoir à modifier et append manuellement des choses?

Santé et merci d'avance!


MODIFIER

Après le commentaire de Prientus, j'ai exploré les possibilités de l'abstraction et de l'inheritance. Les problèmes sous-jacents que j'ai maintenant découverts sont en fait multiples:

  • Il fonctionnait avant Cocoapods 1.2.0 parce que les pods déclarés sous la cible du widget étaient embeddeds dans l'application hôte mais toujours liés au widget. Non, il refuse simplement d'avoir des pods portant le même nom pour différentes cibles dans une relation "main vs extension"
  • L'utilisation de cibles abstraites est insuffisante car les cibles ne peuvent pas hériter uniquement des paths de search ( inherit! :search_paths ) d'une cible abstraite.
  • Les paths de search peuvent être hérités d'une cible réelle comme MyAppKit , mais cela expose tous ces pods au MyApp de MyApp (que je veux éviter), et il y a toujours le problème de lier le framework Realm (parce que le widget utilise le plus petit peu de getter et en a donc besoin).

Utiliser cette dernière option et relier manuellement Realm.framework fonctionne mais est sous-optimal quant à mes intentions et ce qui fonctionnait. Certains de ces problèmes semblent être un bug selon divers problèmes sur GitHub de Cocoapods. J'ai ajouté mon propre numéro et je vais le mettre à jour quand j'ai des nouvelles.

Alors, qu'est-ce qui donne:

  • Mon souci de «séparer les pods entre les cibles» est absurde car vous pouvez toujours les importer n'importe où.
  • Le problème "vous devez lier manuellement" est corrigé par une instruction import RealmSwift facile à import RealmSwift .

Le Podfile fixe et fonctionnel est donc:

 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 

Et c'est tout. Je dirais que l'ancien comportement était plus évident et ne nécessitait pas de lire sur "l'inheritance de la cible podfile". J'ai beaucoup appris cependant. À votre santé!

Je ne te connais pas. Mais pour moi, il est totalement légitime et légitime que l'extension et l'application hôte contiennent tous les modules définis par un framework. Et voici ce que je veux dire:

 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 

Je sais que vous vous inquiétez, mais si vous y réfléchissez, tous les frameworks tiers que vous utilisez, ils ont tous des dependencies. Vous n'avez pas à vous soucier d'eux parce que Cocoapods prend soin d'eux pour vous. Si vous voulez utiliser cela, vous devez mettre une input de pod local dans la list.

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

Mais alors vous devez maintenir le file podspec .

C'est l'exemple de profil d'un projet 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