Wie exportiere ich "fettes" Cocoa Touch Framework (für Simulator und Gerät)?

107

Mit Xcode 6 können wir eigene Dynamics erstellen Cocoa Frameworks.

Geben Sie hier die Bildbeschreibung ein

Wegen:

  • Der Simulator verwendet weiterhin die 32-bitBibliothek

  • Ab dem 1. Juni 2015 müssen App-Updates, die an den App Store gesendet werden, 64-Bit-Unterstützung enthalten und mit dem iOS 8 SDK ( developer.apple.com ) erstellt werden.

Wir müssen eine Fettbibliothek erstellen, um Projekte auf Geräten und Simulatoren ausführen zu können. dh unterstützt sowohl 32 als auch 64 Bit in Frameworks.

Aber ich habe keine Handbücher gefunden, wie man das universelle Fat Framework für die zukünftige Integration mit anderen Projekten exportiert (und diese Bibliothek mit jemandem teilt).

Hier sind meine Schritte zum Reproduzieren:

  1. Stellen Sie ONLY_ACTIVE_ARCH=NOin derBuild Settings

    Geben Sie hier die Bildbeschreibung ein

  2. Fügen Sie Unterstützung armv7 armv7s arm64 i386 x86_64zu Architectures(sicher)

Geben Sie hier die Bildbeschreibung ein

  1. Erstellen Sie das Framework und öffnen Sie es im Finder:

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

  1. Fügen Sie dieses Framework einem anderen Projekt hinzu

Tatsächliche Ergebnis:

Aber am Ende habe ich immer noch Probleme, ein Projekt mit diesem Framework auf Geräten und Simulatoren gleichzeitig auszuführen.

  • Wenn ich das Framework aus dem Debug-iphoneosOrdner nehme , funktioniert es auf Geräten und wird auf Simulatoren als Fehler angezeigt:ld: symbol(s) not found for architecture i386

      xcrun lipo -info CoreActionSheetPicker

    Architekturen in der Fat-Datei: CoreActionSheetPicker sind: armv7 armv7s arm64

  • Wenn ich Framework aus Debug-iphonesimulatorOrdner nehme , funktioniert es auf Simulatoren. und ich habe Fehler auf dem Gerät:ld: symbol(s) not found for architecture arm64

      xcrun lipo -info CoreActionSheetPicker

    Architekturen in der Fat-Datei: CoreActionSheetPicker sind: i386 x86_64

Wie erstelle ich ein dynamisches Framework, das auf Geräten und Simulatoren funktioniert?

Diese Antwort bezog sich auf Xcode 6 iOS. Erstellen eines Cocoa Touch Framework - Architekturprobleme, aber keine Duplikate.


Aktualisieren:

Ich habe einen "Dirty Hack" für diesen Fall gefunden. Siehe meine Antwort unten . Wenn jemand einen bequemeren Weg kennt - bitte lassen Sie es mich wissen!

Skywinder
quelle
doppelte Ausgabe stackoverflow.com/questions/24039470/…
Andrius Steponavičius
@ AndriusSteponavičius Diese Frage wurde 2 Monate zuvor gestellt.
Skywinder
Ja, aber es gibt dort viel detailliertere Antworten, über die Benutzer meiner Meinung nach Bescheid wissen sollten
Andrius Steponavičius
Das Setzen von ONLY_ACTIVE_ARCH = NO in den Build-Einstellungen ist ein wichtiger Schritt.
Jedidja
Ihr Framework benötigt beide i386 x86_64-Slices in der Fat-Binärdatei, wenn Sie es auf dem Simulator ausführen möchten, AUCH WENN IHR COMPUTER EINE 64-BIT-ARCHITEKTUR HAT !!! Das habe ich auf die harte Tour gelernt.
J. Beenie

Antworten:

82

Die Aktualität dieser Antwort lautet: Juli 2015. Es ist sehr wahrscheinlich, dass sich die Dinge ändern werden.

TLDR;

Derzeit verfügt Xcode nicht über Tools für den automatischen Export des universellen Fat Frameworks, sodass Entwickler auf die manuelle Verwendung des lipoTools zurückgreifen müssen . Laut diesem Radar muss vor der Übermittlung an den AppStore-Entwickler, der der Verbraucher des Frameworks ist, auch lipoSimulator-Slices von einem Framework entfernt werden.

Eine längere Antwort folgt


Ich habe ähnliche Nachforschungen zu diesem Thema angestellt (der Link am Ende der Antwort).

Ich hatte keine offizielle Dokumentation über Verteilung der so meine Forschung gefunden auf die Exploration von Apple Developer Forums basiert, Karthago und Realm Projekte und meine eigenen Experimente mit xcodebuild, lipo, codesignWerkzeuge.

Hier ist ein langes Zitat (mit ein bisschen Markup von mir) aus dem Apple Developer Forums-Thread. Exportieren einer App mit eingebettetem Framework :

Was ist der richtige Weg, um ein Framework aus einem Framework-Projekt zu exportieren?

Derzeit ist der einzige Weg genau das, was Sie getan haben:

  • Erstellen Sie das Ziel sowohl für den Simulator als auch für das iOS-Gerät.
  • Navigieren Sie zum DerivedData-Ordner von Xcode für dieses Projekt und führen Sie die beiden Binärdateien zu einem einzigen Framework zusammen. Wenn Sie jedoch das Framework-Ziel in Xcode erstellen, müssen Sie die Zieleinstellung "Nur aktive Architektur erstellen" auf "NEIN" anpassen. Dadurch kann Xcode das Ziel für mehrere Binarty-Typen (arm64, armv7 usw.) erstellen. Aus diesem Grund funktioniert es mit Xcode, jedoch nicht als eigenständige Binärdatei.

  • Außerdem sollten Sie sicherstellen, dass das Schema auf einen Release-Build eingestellt ist, und das Framework-Ziel gegen Release erstellen. Wenn immer noch der Fehler "Bibliothek nicht geladen" angezeigt wird, überprüfen Sie die Codeschnitte im Framework.

  • Verwenden lipo -info MyFramworkBinaryund untersuchen Sie das Ergebnis.

lipo -info MyFrameworkBinary

Ergebnis ist i386 x86_64 armv7 arm64

  • Moderne universelle Frameworks enthalten 4 Slices, können aber auch mehr enthalten: i386 x86_64 armv7 arm64 Wenn Sie mindestens diese 4 nicht sehen, kann dies an der Einstellung Build Active Architecture liegen.

Dies beschreibt den Prozess ziemlich genau so, wie es @skywinder in seiner Antwort getan hat.

So verwendet Karthago Lipo und Realm Lipo .


WICHTIGES DETAIL

Es gibt Radar: Xcode 6.1.1 & 6.2: iOS-Frameworks, die Simulator-Slices enthalten, können nicht an den App Store gesendet werden. Eine lange Diskussion darüber in Realm Nr. 1163 und Karthago Nr. 188 endete mit einer speziellen Problemumgehung:

Vor der Übermittlung an AppStore müssen iOS-Framework-Binärdateien von den Simulator-Slices entfernt werden

Karthago hat einen speziellen Code: CopyFrameworks und die entsprechende Dokumentation:

Dieses Skript umgeht einen App Store-Übermittlungsfehler, der durch universelle Binärdateien ausgelöst wird.

Realm hat ein spezielles Skript: strip-frameworks.sh und eine entsprechende Dokumentation:

Dieser Schritt ist erforderlich, um einen App Store-Übermittlungsfehler beim Archivieren universeller Binärdateien zu umgehen.

Es gibt auch einen guten Artikel: Entfernen unerwünschter Architekturen aus dynamischen Bibliotheken in Xcode .

Ich selbst habe Realm's verwendet, strip-frameworks.shdie ohne Änderungen perfekt für mich funktionierten, obwohl natürlich jeder frei ist, eine von Grund auf neu zu schreiben.


Der Link zu meinem Thema, den ich zum Lesen empfehle, da er einen weiteren Aspekt dieser Frage enthält: Codesignatur - Erstellen von iOS / OSX-Frameworks: Ist es erforderlich, sie vor der Verteilung an andere Entwickler zu codieren?

Stanislav Pankevich
quelle
1
Ich habe Lipo verwendet, aber wenn das Framework im Simulator erstellt wird, zeigt es eine ungelöste Kennung mit dem Klassennamen an, aber im Gerät funktioniert es. Wenn Sie eine Simulatorversion der Binärdatei verwenden, funktioniert sie. Irgendeine Idee?
Susim Samanta
2
Ich habe festgestellt , keine Beweise dies von Xcode 8.2 im Dezember hat sich geändert 2016.: /
Geoffrey Wiseman
1
@Geoffrey, hat sich das in Xcode 9.2 geändert oder ist etwas anderes? Dies ist mein erstes Mal, dass ich ein binäres Framework für die Verteilung erstelle, und ich habe bereits Angst ...
ScottyB
Ich habe das leider nicht ein bisschen gemacht - kann ich nicht sagen. Viel Glück.
Geoffrey Wiseman
57

Dies ist keine so klare Lösung, aber es gibt nur einen Weg, den ich finde:

  1. Stellen Sie ONLY_ACTIVE_ARCH=NOin derBuild Settings

    • Bibliothek für Simulator erstellen
    • Bibliothek für Gerät erstellen
  2. Öffnen Sie den Konsolenordner Productsfür Ihr Framework (Sie können ihn öffnen, indem Sie den Framework-Ordner öffnen und cd ..von dort aus).

Geben Sie hier die Bildbeschreibung ein Geben Sie hier die Bildbeschreibung ein

  1. Führen Sie dieses Skript aus dem ProductsOrdner aus. Es erstellt Fat Framework in diesem Ordner. (oder machen Sie es manuell, wie unten in 3. 4. erklärt )

Oder:

  1. Kombinieren Sie diese beiden Frameworks mithilfe von Lipo mit diesem Skript (ersetzen Sie sie YourFrameworkNamedurch Ihren Framework-Namen).

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
  2. Ersetzen Sie eines der vorhandenen Frameworks durch ein neues binäres Framework:

    cp -R Debug-iphoneos/YourFrameworkName.framework ./YourFrameworkName.framework
    mv YourFrameworkName ./YourFrameworkName.framework/YourFrameworkName

  1. Gewinn: ./YourFrameworkName.framework- ist gebrauchsfertige Fat Binary! Sie können es in Ihr Projekt importieren!

Für Projekte, die nicht in Arbeitsbereichen enthalten sind:

Sie können auch versuchen, dieses Wesentliche wie hier beschrieben zu verwenden . Es scheint jedoch nicht für Projekte in Arbeitsbereichen zu funktionieren.

Skywinder
quelle
Ich dachte, Apple akzeptiert keine fetten Binärdateien mehr. kodmunki.wordpress.com/2015/03/04/…
Monstieur
1
@skywinder Haben Sie eine andere einfache Möglichkeit gefunden, Cocoa Touch Framework zu exportieren, um fette Binärdateien zu verwenden? Ich benutze den gleichen Ansatz wie oben, aber ich mag es nicht. Xcode sollte einige haben, die den Prozess automatisieren.
dev gr
1
@devgr noch nicht .. deshalb habe ich meine eigene Antwort nicht akzeptiert. Immer noch auf der Suche nach einer besseren Lösung.
Skywinder
1
Kann nicht im Simulator ausgeführt werden, funktioniert jedoch im Gerät mit den Schritten 3 und 4
jose920405
1
@ Könnte jemand erklären, warum nur Debug-Ordner mit verwendet wird lipo -create? Könnte dieses Framework für die ReleaseKonfiguration verwendet werden und warum? Vielen Dank.
Yevhen Dubinin
10

Die Antwort von @Stainlav war sehr hilfreich, aber ich habe stattdessen zwei Versionen des Frameworks kompiliert (eine für das Gerät und eine für den Simulator) und dann Folgendes hinzugefügt, um das Run Script Phasefür die laufende Architektur erforderliche vorkompilierte Framework automatisch zu kopieren

echo "Copying frameworks for architecture: $CURRENT_ARCH"
if [ "${CURRENT_ARCH}" = "x86_64" ] || [ "${CURRENT_ARCH}" = "i386" ]; then
  cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
  cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

Auf diese Weise kann ich lipoweder ein fettes Framework erstellen, noch die Realms strip-frameworks.sh, um die unnötigen Slices zu entfernen, wenn ich sie an den App Store sende.

odm
quelle
Gegen welches verlinkst du?
Jaka Jančar
@ JakaJančar Ich verlinke gegen die im ${SRCROOT}/Frameworks/ActiveOrdner. Sie werden zur Kompilierungszeit durch die richtigen vorkompilierten Frameworks für die aktive Architektur ersetzt.
Odm
2
Liebe es! Dies ist so viel einfacher als der lipoAnsatz des Kombinierens und Zerreißens .
Clozach
2

Grundsätzlich habe ich dafür eine sehr gute Lösung gefunden. Sie müssen nur diese einfachen Schritte befolgen.

  1. Erstellen Sie ein Cocoa Touch Framework.
  2. Setzen Sie den aktivierten Bitcode auf Nein.
  3. Wählen Sie Ihr Ziel und wählen Sie Bearbeitungsschemata. Wählen Sie Ausführen und dann Freigeben von der Registerkarte Info.
  4. Keine andere Einstellung erforderlich.
  5. Erstellen Sie jetzt das Framework für jeden Simulator, da der Simulator auf einer x86-Architektur ausgeführt wird.
  6. Klicken Sie im Projektnavigator auf die Gruppe Produkte und suchen Sie die .framework-Datei.
  7. Klicken Sie mit der rechten Maustaste darauf und klicken Sie auf Im Finder anzeigen. Kopieren Sie es und fügen Sie es in einen beliebigen Ordner ein. Ich persönlich bevorzuge den Namen "Simulator".
  8. Erstellen Sie nun das Framework für generisches iOS-Gerät und befolgen Sie die Schritte 6 bis 9. Benennen Sie den Ordner einfach in "Gerät" anstelle von "Simulator" um.
  9. Kopieren Sie die .framework-Datei des Geräts und fügen Sie sie in ein anderes Verzeichnis ein. Ich bevorzuge das unmittelbare Superverzeichnis von beiden. Die Verzeichnisstruktur lautet nun:
    • Desktop
    • Gerät
      • MyFramework.framework
    • Simulator
      • MyFramework.framework
    • MyFramework.framework Öffnen Sie nun das Terminal und die CD auf dem Desktop. Geben Sie nun den folgenden Befehl ein:

lipo -create 'device / MyFramework.framework / MyFramework' 'simulator / MyFramework.framework / MyFramework' -output 'MyFramework.framework / MyFramework'

und das ist es. Hier führen wir die Simulator- und Geräteversion der MyFramework-Binärdatei in MyFramework.framework zusammen. Wir erhalten ein universelles Framework, das für alle Architekturen einschließlich Simulator und Gerät erstellt wird.

Nrip
quelle
Ich möchte eine FAT-Datei mit aktiviertem Bitcode erstellen. Bitte führen Sie mich.
user3898700
2

Ich möchte nur diese großartige Antwort von @odm aktualisieren. Seit Xcode 10 CURRENT_ARCHspiegelt die Variable die Build-Architektur nicht mehr wider. Also habe ich das Skript geändert, um stattdessen die Plattform zu überprüfen:

echo "Copying frameworks for platform: $PLATFORM_NAME"
rm -R "${SRCROOT}/Frameworks/Active"
if [ "${PLATFORM_NAME}" = "iphonesimulator" ]; then
    cp -af "${SRCROOT}/Frameworks/Simulator/." "${SRCROOT}/Frameworks/Active"
else
    cp -af "${SRCROOT}/Frameworks/Device/." "${SRCROOT}/Frameworks/Active"
fi

Ich habe auch eine Zeile hinzugefügt, um das Zielverzeichnis vor dem Kopieren zu löschen, da ich festgestellt habe, dass zusätzliche Dateien in Unterverzeichnissen sonst nicht überschrieben würden.

Dorian Roy
quelle
1

Meine Antwort deckt die folgenden Punkte ab:

  • Erstellen Sie ein Framework, das sowohl für den Simulator als auch für das Gerät funktioniert

  • Wie exportiere ich "fettes" Cocoa Touch Framework (sowohl für Simulator als auch für Gerät)?

  • Undefinierte Symbole für die Architektur x86_64

  • ld: Symbol (e) für Architektur x86_64 nicht gefunden

Schritte 1: Erstellen Sie zuerst Ihre Frameworks mit dem Simulator-Ziel

Schritte 2: Nach erfolgreichem Simulator-Erstellungsprozess erstellen Sie jetzt für Ihr Framework mit Gerätezielauswahl oder generischer iOS-Geräteauswahl

Schritt 3: Wählen Sie nun Ihr Framework-Ziel aus und wählen Sie dazu unter "Build Phases" "Add Run Script" aus und kopieren Sie den folgenden Skriptcode.

Schritt 4: Jetzt endlich wieder erstellen und Ihr Framework ist sowohl für die Simulator- als auch für die Gerätekompatibilität bereit. Hurra!!!!

[Hinweis: Wir müssen beide kompatiblen Frameworks vor dem letzten Schritt 4 bereit haben (Simulator- und Gerätearchitektur kompatibel, wenn nicht, befolgen Sie bitte die obigen Schritte 1 und 2 korrekt).

Siehe das Referenzbild:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Fügen Sie den folgenden Code in den Shell-Bereich ein:

#!/bin/sh


UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal


# make sure the output directory exists

mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"


# Step 1. Build Device and Simulator versions

xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos  BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build

xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build


# Step 2. Copy the framework structure (from iphoneos build) to the universal folder

cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"


# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory

SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."

if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then

cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"

fi


# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory

lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"


# Step 5. Convenience step to copy the framework to the project's directory

cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"


# Step 6. Convenience step to open the project's directory in Finder

open "${BUILD_DIR}/${CONFIGURATION}-universal"

Sandip Patel - SM
quelle
Dieses Skript scheint sich selbst aufzurufen und verursacht somit eine Endlosschleife !! Musste meinen Computer nach dem Ausführen neu starten! Lauchte ständig neue xcodebuild-Prozesse ... und öffnete neue Finder-Fenster - Würde abstimmen
J.beenie
Schauen Sie sich die Antwort von @ l0gg3r in dieser SO- Frage / Antwort für ein ähnliches Skript ohne Rekursionsproblem an.
J. Beenie