2017-02-08 9 views
7

Mam app (nazwijmy go MojaApl) napisany w Swift z następującymi celami:Korzystanie Cocoapods w rozszerzeniu aplikacji za pomocą ramy

  • MyApp: Głównym celem
  • MyAppKit: cel budowania framework dla kodu współużytkowanego między aplikacją i jej rozszerzeniami, głównie obsługa interfejsu API i obsługa bazy danych:
  • MyAppWidget: Widget Widget Dzisiaj (lub jakkolwiek się teraz nazywa), który wykorzystuje framework MyAppKit.

ramy MyAppKit jest związana w każdej tarczy, który wykorzystuje go, mianowicie MyApp i MyAppWidget. Wprowadź Cocoapods: kiedyś mieć następującą strukturę 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 

Celem tutaj było wystawiać tylko ramy MyAppKit do innych części i nie wszystkie jej strąki (np ja nie chcę, aby móc import Alamofire wewnątrz głównej aplikacji). Jednak począwszy od wersji RC0 Cocoapods, pod install nie powiodło się z następującym błędem: [!] The 'Pods-MyApp' target has frameworks with conflicting names: realm and realmswift.. Kiedyś działało, ponieważ strąki zostały zadeklarowane dla rozszerzenia, ale tylko osadzone w aplikacji hosta (zobacz this issue, aby uzyskać więcej informacji). Więc usunąłem strąki z celu widgetu, zostawiając mnie po prostu pustą linią target 'MyAppWidget'.

Przy tej konfiguracji pod install działa poprawnie, ale kompilacja kończy się niepowodzeniem na etapie łączenia dla celu MyAppWidget: ld: framework not found Realm for architecture x86_64. To może być ustalona przez jawnie dodawanie zarówno Realm.framework i RealmSwift.framework do sekcji „link binarne z bibliotekami” i następującym ustawieniu budować w docelowej Pods-MyAppWidget.[debug/release].xcconfig:

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

Jednak, gdy biegnę pod install ustawienia kompilacji są naturalnie powrócił i muszę ponownie dodać ustawienia kompilacji.

widzę następujące rozwiązania:

  • Dodaj hak post_install dodanie tych ustawień za każdym razem, ale wydaje „hacky” i po kilku błędnych próbach znalazłem żadnego odniesienia API i nie wiem jak dodać te ustawienia do celu MyAppWidget poprzez skrypt.
  • Zmiana Podfile z następującą strukturę (lub nawet owinięcie go w abstrakcyjny cel):

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

    Które wydaje się logiczne dla mnie w sensie „widget powinien wiedzieć, gdzie szukać podczas łączenie ale nie robi 't need strąków per se " ale to nie dodaje wyżej wymienionych ustawień kompilacji (prawdopodobnie źle rozumiem dziedziczenie :search_paths) (edycja: to faktycznie działa, ale nie z celem abstrakcyjnym). Pomysł ten przyszedł mi do głowy, ponieważ w starszych wersjach CocoaPods, solution najwyraźniej dodano link_with, który jest teraz przestarzały.

  • Ujawnić Realm również w celu MyApp, jednak jest to sprzeczne z moim celem, aby nie mieć dostępu do kodu "backend" w głównym kodzie (może to być czysto estetyczne?).

Tak, oto moje pytanie: jaki jest najlepszy sposób na integrację strąków w ramach dzielonego pomiędzy głównym aplikacji i rozbudowy, a jednocześnie jest w stanie skompilować bez szczypanie wokół i ręczne dodawanie rzeczy?

Pozdrawiamy i dziękujemy z góry!


EDIT

Po Prientus' comment Mam zbadać możliwości abstrakcji i dziedziczenia. Bazowe problemy mam teraz odkryte są rzeczywiście różnorodne:

  • on używany do pracy przed Cocoapods 1.2.0 ponieważ strąki zadeklarowane pod cel widgetu zostały osadzone wewnątrz aplikacji hosta jeszcze nadal związany z widgetu. Po prostu nie chce mieć kart o tej samej nazwie dla różnych celów w relacji "główna z rozszerzeniem".
  • Używanie celów abstrakcyjnych jest niewystarczające, ponieważ cele nie mogą dziedziczyć tylko ścieżek wyszukiwania (inherit! :search_paths) z celu abstrakcyjnego.
  • Ścieżki wyszukiwania mogą być dziedziczone z prawdziwego celu, takiego jak MyAppKit, ale to ujawnia wszystkie te podpowiedzi do kodu MyApp (którego chcę uniknąć), i nadal istnieje problem łączenia ram Realm (ponieważ faktycznie widget używa najdrobniejszego kawałka gettera i dlatego go potrzebuje).

Używanie tej ostatniej opcji i ręczne łączenie Realm.framework działa, ale jest nieoptymalne pod względem moich intencji i tego, co kiedyś działało. Niektóre z tych problemów wydają się być błędem według variousissueson GitHub firmy Cocoapods. Dodałem my own issue i zaktualizuję po otrzymaniu wiadomości.

+0

Wspomniałeś o używaniu klasy abstrakcyjnej w swoich rozwiązaniach, ale zastanawiałem się, czy faktycznie to wypróbowałeś. Masz tu bardzo dobre pytanie, które wpadłem na siebie. – Prientus

+0

Ponadto spróbuję użyć dziedziczenia! metoda, ale cel jest zadeklarowany poza rodzicem. Zauważyłem, że składnia tutaj: https://guides.cocoapods.org/syntax/podfile.html#target i pomyślałem, że może być przydatna. – Prientus

Odpowiedz

7

Więc, co daje:

  • Moja troska o „oddzielenie strąków między celami” jest absurdalne, ponieważ nadal można importować je w dowolnym miejscu.
  • "Musisz ręcznie link" problem jest ustalony przez łatwe oświadczenie import RealmSwift.

stałe i pracuje Podfile zatem brzmi:

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 

I to wszystko. Powiedziałbym, że stare zachowanie było bardziej oczywiste i nie wymagało czytania "dziedziczenia celu pliku podfile". Dużo się jednak nauczyłem. Twoje zdrowie!

+0

Zrobiłem tak, jak powiedziałeś i używaj 'dziedziczenia! : search_paths', które działa tylko podczas budowania na urządzeniu. Kiedy próbuję i zarchiwizuję aplikację, nie działa "Brak takiego modułu" dla każdej kapsuły, którą próbuję użyć w rozszerzeniach. – YichenBman

+0

@YichenBman Właśnie zarchiwizowałem moją aplikację bez żadnych błędów. Może mógłbyś pokazać mi swój Podfile lub otworzyć nowe pytanie tutaj. Zasadą jest, że upewnij się, że CocoaPods i Xcode są aktualne. –

+0

Wielkie dzięki, zaoszczędzisz mi godzin ciężkiej pracy, ale archiwum nie działa. Nie rozpoznaje modułu podczas jego importowania ... – Eduard

1

Nie znam cię. Ale dla mnie jest całkowicie uzasadnione i uzasadnione, aby rozszerzenie i aplikacja hosta zawierały wszystkie podsody zdefiniowane przez framework. I to jest to, co mam na myśli:

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 

wiem, że są martwi, ale jeśli myślisz o tym, wszystkie te ramy 3rd Party użyć, wszystkie one mają zależności. Nie musisz się o nie martwić, ponieważ Cocoapods zajmuje się nimi za Ciebie. Jeśli chcesz to wykorzystać, musisz umieścić na liście wpis na lokalny podajnik.

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

Ale musisz zachować plik podspec.

+0

Po paraliżujących umysłach badaniach i testach za nic znalazłem rozwiązanie mojego problemu (zamieszczone poniżej w celach informacyjnych). W większości przypadków chodzi o to, że jakkolwiek skonfigurujesz swój Podfile, wszystkie kapsuły mogą być importowane wszędzie (chyba ze względu na połączony framework współdzielony) i dlatego moim głównym problemem jest brak problemów. Należy zauważyć, że twoje rozwiązanie nie spowodowałoby, że "obiekt docelowy ma frameworki ze sprzecznymi nazwami", ponieważ kończy się odwoływaniem do modułu wewnątrz rozszerzenia. –

0

To jest przykład profilu projektu Swift 3.0.