Tworzenie struktur iOS / OSX: czy konieczne jest kodowanie ich przed dystrybucją do innych programistów?

90

Uczę się tworzyć frameworki iOS i OSX. Weźmy na przykład iOS, na razie działają dla mnie następujące kroki:

  1. xcodebuild framework przy użyciu -sdk iphonesimulator i akcji Build
  2. xcodebuild framework przy użyciu -sdk iphoneos i akcji Build
  3. Użyj narzędzia lipo, aby utworzyć uniwersalny plik binarny, aby lipo -infouzyskać oczekiwane:

Architektury w pliku fat: Foo.framework / Foo to: i386 x86_64 armv7 arm64

Oto pytania:

  1. Czytałem, że mój framework może zostać ponownie podpisany przez programistę, który go używa: "Kopiowanie kodu logowania", ale nie rozumiem, jakie są jego warunki wstępne, tj. Czy powinienem dodać krok kodowania, aby zakodować ten uniwersalny plik binarny moją tożsamością podpisującą przed rozpowszechniać go innym programistom?

  2. jeśli poprzednie jest pozytywne - czy powinienem użyć mojej tożsamości "Dystrybucja iPhone'a: ​​..." lub "Programista iPhone: ..." wystarczy (aby mój framework będący częścią jakiegoś projektu iOS przeszedł wszystkie rodzaje walidacji, zwłaszcza walidację w App Store ) ?.

Tłem mojej odpowiedzi jest „Błąd CodeSign: podpisywanie kodu jest wymagane dla typu produktu„ Framework ”w SDK„ iOS 8.3 ””, który widziałem w wielu platformach innych firm i Carthage # 235 lub „obiekt kodu nie jest podpisany w ogóle ”(jeden przykład: problem, który zgłosiłem w Realm # 1998 .

Dlatego chcę mieć pewność, że użytkownicy moich frameworków nie napotkają żadnych problemów z kodowaniem podczas ich używania.

PS To pytanie staje się jeszcze bardziej interesujące, gdy odnosi się nie do pojedynczego programisty, ale do organizacji, która jest dostawcą frameworka.

Stanislav Pankevich
źródło
Ten komentarz sugeruje użycie „CODE_SIGN_IDENTITY = iPhone Developer”, ale nie jest jasne, dlaczego „Developer” jest używany zamiast „iPhone Distribution”.
Stanislav Pankevich
Temat pokrewny: Eksportowanie aplikacji z osadzoną strukturą, ale bez jednoznacznej odpowiedzi.
Stanislav Pankevich
Oszukałem również to pytanie na forach programistów Apple: forums.developer.apple.com/thread/6400 .
Stanislav Pankevich
Mam pytanie, kiedy dystrybuujesz framework, dystrybuujesz kompilację debugowania lub kompilację wydania? a jeśli rozprowadzasz go w kompilacji wydania, jak to zrobić?
Pełm25
@ ogm25, to jest jeden ze sposobów jak to robię: stanislaw.github.io/2015/11/23/… .
Stanislav Pankevich

Odpowiedzi:

137

Otworzyłem nagrodę: „Szukam odpowiedzi na podstawie wiarygodnych i / lub oficjalnych źródeł”. ale od tamtej pory ich nie otrzymałem.

Odpowiedź udzielona przez @jackslash jest prawidłowa, ale opowiada tylko część historii, więc chcę napisać własną w taki sposób, w jaki chciałbym ją widzieć w momencie, gdy zadawałem to pytanie.

Aktualność tej odpowiedzi brzmi: lipiec 2015 r. Najprawdopodobniej sytuacja się zmieni.

Przede wszystkim upewnijmy się, że czynności potrzebne do prawidłowego podpisania kodu frameworka należy podzielić na kroki, które musi wykonać Programista frameworka oraz kroki, które musi wykonać Konsument frameworka.

TLDR;

W przypadku frameworka OSX: Programista może rozpowszechniać framework OSX bez kodowania go, ponieważ Konsument i tak będzie go ponownie kodował.

W przypadku platformy iOS: programista może dystrybuować framework iOS bez kodowania go, ponieważ konsument i tak go ponownie koduje, ale programista jest zmuszony przez Xcode do kodowania ich struktury podczas kompilacji dla urządzenia z systemem iOS.

Z powodu radaru: „Struktury iOS zawierające wycinki symulatora nie mogą być przesłane do App Store” Konsument frameworku iOS jest zmuszony do uruchomienia specjalnego skryptu, takiego jak „copy_frameworks” lub „strip_frameworks”, który służy lipo -removedo usuwania wycinków symulatora ze środowiska iOS -codesigns pozbawiony frameworka, ponieważ w tym momencie jego tożsamość kodowania, czymkolwiek był (lub nie był), jest usuwana jako efekt uboczny lipo -removemanipulacji.

Następuje dłuższa odpowiedź.


Ta odpowiedź nie jest „czerpaniem z wiarygodnych i / lub oficjalnych źródeł”, ale raczej opiera się na szeregu obserwacji empirycznych.

Obserwacja empiryczna nr 1: Konsumentów to nie obchodzi, ponieważ przeprogramują framework, który otrzymają od programisty

Binarne dystrybucje ram dobrze znanych projektów open source na Github nie są kodowane . Polecenie codesign -d -vvvvpodaje: „obiekt kodu nie jest w ogóle podpisany” we wszystkich binarnych frameworkach iOS i OSX, których używałem do eksploracji. Kilka przykładów: ReactiveCocoa and Mantle , Realm , PromiseKit .

Z tej obserwacji jasno wynika, że ​​autorzy tych frameworków zamierzają być podpisane przez konsumenta w ich imieniu, tj. Konsument musi użyć flagi „Code Sign on Copy” w fazie budowy „Embed frameworks” dostarczonej przez Xcode lub użyć niestandardowej powłoki skrypt, który robi to samo ręcznie: koduje framework w imieniu Konsumenta.

Nie znalazłem ani jednego przykładu odwrotnego: framework open source, który byłby dystrybuowany z tożsamością kodowania, więc w pozostałej części odpowiedzi przyjmuję to szeroko przyjęte podejście jako poprawne: nie ma potrzeby, aby programista frameworków rozpowszechniać ich framework innym programistom z kodowaniem tożsamości, ponieważ Konsument i tak go przeprogramuje .

Empiryczna obserwacja nr 2, która dotyczy tylko iOS i która jest całkowicie troską dewelopera

Podczas gdy konsument nie obchodzi czy ramy otrzymują oni od deweloper jest codesigned lub nie, Programista musi jeszcze codesign ich ramy iOS jako część procesu kompilacji, gdy budować go na urządzeniu z iOS , bo inaczej Xcode nie buduje: CodeSign error: code signing is required for product type 'Framework' in SDK 'iOS 8.1'. Cytując Justina Spahra-Summersa :

Frameworki OS X nie muszą być kodowane podczas kompilacji ... Niestety, Xcode wymaga, aby struktury iOS były kodowane w czasie kompilacji.

To całkiem dobra odpowiedź na moje pytanie nr 2: tożsamość „programisty iPhone'a” wystarczy, aby zmusić Xcode do zbudowania struktury iOS dla urządzenia. Ten komentarz do Kartaginy nr 339 mówi to samo.

Obserwacja empiryczna nr 3: narzędzie lipo

Specyficzne zachowanie narzędzia lipo: po nałożeniu na ramowej binarnym, to zawsze rekurencyjnie usuwa wszelkie codesign tożsamości od niego : lipo -create/-remove codesigned framework ... -> not codesigned framework.

To może być odpowiedź, dlaczego wszystkie przykłady w obserwacji nr 1 nie są w ogóle oznakowane kodem: ich tożsamość kodowa zostaje zniweczona po zastosowaniu lipo, ale ponieważ zgodnie z obserwacją nr 1 Konsument nie dba o to, jest w porządku.

Ta obserwacja jest szczególnie istotna dla następnej obserwacji # 4 dotyczącej AppStore.

Obserwacja empiryczna nr 4: frameworków iOS zawierających wycinki symulatora nie można przesłać do App Store

Jest to szeroko omawiane w: Realm # 1163 i Carthage # 188, a radar zostaje otwarty: rdar: // 19209161 .

Jest to całkowicie kwestia konsumenta: w przypadku uniwersalnej platformy iOS, którą konsument zawiera w swojej aplikacji, podczas budowania aplikacji muszą oni uruchomić specjalny skrypt (niestandardowa faza uruchamiania skryptu), który usuwa wycinek symulatora z pliku binarnego tej platformy, aby aplikacja mogła przejść walidację AppStore.

Dobry przykład dla binarnych frameworków, który znalazłem w Realm: strip-frameworks.sh .

Używa lipodo usunięcia wszystkich fragmentów architektur innych niż, ${VALID_ARCHS}a następnie ponownie koduje go z tożsamością konsumenta - w tym miejscu pojawia się obserwacja nr 3: framework ma zostać ponownie zakodowany z powodu manipulacji lipo.

Carthage ma skrypt CopyFrameworks.swift, który robi to samo ze wszystkimi frameworkami zawartymi przez Consumer: usuwa fragmenty symulatora i ponownie koduje framework w imieniu konsumenta.

Jest też dobry artykuł: Usuwanie niechcianych architektur z bibliotek dynamicznych w Xcode .


Teraz przegląd kroków wymaganych do stworzenia systemu iOS i OSX z perspektywy dewelopera i konsumenta. Najpierw łatwiejszy:

OSX

Deweloper:

  1. Buduje framework OSX
  2. Daje to Konsumentowi

Od programisty nie są wymagane żadne czynności związane z kodowaniem.

Konsument:

  1. Otrzymuje framework OSX od Developer
  2. Kopiuje framework do Frameworks / katalogu i automatycznie podpisuje go w swoim imieniu Konsumenta w ramach procesu "Code Sign on Copy".

iOS

Deweloper:

  1. Buduje platformę iOS dla urządzenia. Xcode wymaga kodowania, wystarczy tożsamość „programisty iPhone'a”.
  2. Buduje strukturę iOS dla symulatora.
  3. Używa lipo, który tworzy uniwersalną strukturę iOS z dwóch poprzednich. W tym momencie tożsamość kodowania 1 kroku zostaje utracona: plik binarny uniwersalnej struktury „w ogóle nie jest podpisany”, ale to jest w porządku, ponieważ „Konsument nie obchodzi”.
  4. Daje to Konsumentowi

Konsument:

  1. Odbiera strukturę iOS od dewelopera
  2. Kopiuje framework do katalogu Frameworks / (ten krok może być zbędny w zależności od tego, jaki skrypt w kroku 3 jest).
  3. Używa specjalnego skryptu jako części procesu budowania: ten skrypt usuwa symulator z platformy iOS, a następnie ponownie koduje go w swoim imieniu konsumenta.
Stanislav Pankevich
źródło
9
To cenny opis. Niezły
Jackslash
@Stanislaw dziękuje za spostrzeżenia i cenne dane. Kiedy piszę framework, który sam zaprojektowałem dla programistów, chcę, aby mogli używać tego frameworka tak, jak jest i używać go bez konieczności tworzenia specjalnego skryptu w celu przesłania go do sklepu z aplikacjami. Myślę, że GoogleMobileAd działa w ten sposób. ale mówisz, że muszą uruchomić określony skrypt? masz pomysł, jak reklamy GoogleMobileAd nie wymagają tego? dzięki
Michael A
@MichaelA, rzeczywiście, to interesujące. Spojrzę.
Stanislav Pankevich 07.07.15
Czy możesz podać link do reklam GoogleMobileAds, z których korzystasz?
Stanislav Pankevich 07.07.15
1
Dziękuję za zaoszczędzenie czasu, który pracował dla mnie. Xcode 7.3, Mac OS X 10.11.4.
eugen
21

Po przeczytaniu połączonego wątku w repozytorium Kartaginy wydaje się to stosunkowo proste. Jeśli rozpowszechniasz framework binarny, musisz go podpisać w kodzie, a jeśli dystrybuujesz źródło za pośrednictwem kartaginy lub strąków kakao, nie robisz tego, ponieważ te narzędzia zajmują się tym za pomocą różnych metod.

Powodem, dla którego musisz podpisać kod podczas dystrybucji struktury binarnej, jest to, że Xcode nie utworzy pliku binarnego frameworka bez podpisania kodu. Jeśli spróbujesz nie podpisywać kodu w strukturze binarnej, otrzymasz ten błąd:

CodeSign error: code signing is required for product type 'Framework' in SDK 'iOS 8.1'

Nie ma znaczenia, z jaką tożsamością kodujesz framework (iPhone Developer lub iPhone Distribution), ponieważ, jak zauważyłeś, framework zostanie ponownie zakodowany z ustawieniem „code sign on copy”. Oznacza to, że Twój framework zostanie ponownie zakodowany przez odpowiedni certyfikat z profilu programisty konsumenta frameworka, gdy zostanie on skopiowany do jego aplikacji. Oznacza to, że nie będzie problemów z App Store, ponieważ będzie on widział tylko ostateczny podpis kodu od konsumenta platformy.

Pod koniec dnia możesz równie dobrze podpisać kod binarny .framework, ponieważ nie chcesz utrzymywać egzotycznego procesu kompilacji, a ponieważ Xcode wypisze tylko podpisane frameworki, nie powinieneś zbytnio oddalać domyślne. Zresztą i tak nie ma to znaczenia, ponieważ konsument końcowy ponownie go podpisze.

jackslash
źródło
w swojej odpowiedzi, w drugim akapicie, mówisz, że nie ma potrzeby kodowania frameworka, ponieważ zostanie on ponownie zakodowany przez konsumenta i jestem teraz w 95% pewien, że to prawda, ale nie rozumiem dlaczego jednocześnie w pierwszym akapicie mówisz: "Jeśli rozprowadzasz framework binarny, musisz go zakodować i podpisać" - jaka jest różnica - jeśli rozprowadzam framework binarny (tj. nie jego źródło przez kartaginę lub kokosowe) dlaczego Musiałbym to kodować?
Stanislav Pankevich
Myślę, że nie powinienem kodować swojego frameworka bez względu na rodzaj dystrybucji, którego używam (spakowany plik .framework, kartagina lub cocoapods). Przykłady: wszystkie następujące dystrybucje binarnych frameworków nie są oznaczone kodem : Realm , ReactiveCocoa , OCMockito .
Stanislav Pankevich
Więc jestem trochę zdezorientowany z twoim „Jeśli rozprowadzasz binarny framework, musisz go podpisać w kodzie”, co (imho) jest sprzeczne z resztą twojej odpowiedzi. Proszę o wyjaśnienie. Proszę również zauważyć, że otworzyłem to zlecenie jako „Szukam odpowiedzi z wiarygodnych i / lub oficjalnych źródeł”.
Stanislav Pankevich
1
Tak, przyjrzałem się także Realm i OCMockito. Realm ma tożsamości „iPhone Developer” i tak, OCMockito jest biblioteką statyczną. Myślę, że rozumiem problem - to lipo usuwa kodowanie z iphoneos, gdy łączy w sobie kodowane iphoneos i niekodowany iphonesimulator.
Stanislav Pankevich
1
Mam pytanie, kiedy dystrybuujesz framework, dystrybuujesz kompilację debugowania lub kompilację wydania? a jeśli rozprowadzasz go w kompilacji wydania, jak to zrobić?
Pełm25
1

Powyższa odpowiedź Stanisława Pankewicza jest bardzo ważna i poprawna. Należy jednak pamiętać, że począwszy od Xcode 9.4, IDE poprosi o wyłączenie podpisywania kodu dla iOS Cocoa Touch Framework. Firma Apple mówi teraz, że nie zaleca się kodowania podpisywania .framework.

Mam nadzieję, że to pomoże.

Dino Alves
źródło
1
Czy masz źródło, które Apple zaleca przeciwko platformom do podpisywania?
Rick