webentwicklung-frage-antwort-db.com.de

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

Mit Xcode 6 können wir eigene dynamische Cocoa Frameworks Erstellen.

enter image description here

Wegen:

  • Der Simulator verwendet weiterhin die Bibliothek 32-bit

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

Wir müssen eine Fettbibliothek erstellen, um Projekte auf Geräten und Simulatoren ausführen zu können. Unterstützung von 32 und 64 Bit in Frameworks.

Aber ich habe keine Handbücher gefunden, wie man ein universelles Fat Framework für die zukünftige Integration in andere Projekte exportiert (und diese Bibliothek mit jemandem teilt).

Hier sind meine Schritte zur Reproduktion:

  1. Setzen Sie ONLY_ACTIVE_Arch=NO In das Feld Build Settings

    enter image description here

  2. Füge Unterstützung armv7 armv7s arm64 i386 x86_64 Zu Architectures hinzu (sicher)

enter image description here

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

enter image description hereenter image description here

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

Tatsächliche Ergebnis:

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

  • wenn ich das Framework aus dem Ordner Debug-iphoneos nehme, funktioniert es auf Geräten und auf Simulatoren wird ein 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 dem Ordner Debug-iphonesimulator nehme, funktioniert es auf Simulatoren. und ich habe einen 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 kann ein dynamisches Framework erstellt werden, das auf Geräten und Simulatoren funktioniert?

Diese Antwort bezog sich auf Xcode 6 iOS Erstellen eines Cocoa Touch Framework - Architekturprobleme aber es ist kein Duplikat.


Aktualisieren:

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

106
skywinder

Die Aktualität dieser Antwort ist: 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 von Universal Fat Framework. Entwickler müssen daher auf die manuelle Verwendung des Tools lipo zurückgreifen. Ebenfalls laut diesem Radar muss der Framework-Konsument vor der Übermittlung an den AppStore-Entwickler lipo verwenden, um Simulator-Slices von einem Framework zu entfernen.

Eine längere Antwort folgt


Ich habe ähnliche Forschungen zum Thema durchgeführt (der Link am Ende der Antwort).

Ich hatte keine offizielle Dokumentation über die Verbreitung von gefunden, so dass meine Forschung auf der Erforschung von Apple Entwicklerforen, Karthago- und Realm-Projekten und meinen eigenen Experimenten mit xcodebuild, lipo, codesign tools.

Hier ist ein langes Zitat (mit ein bisschen Aufschlag von mir) von Apple Entwicklerforenthread App mit eingebettetem Framework exportieren :

Wie kann ein Framework aus einem Framework-Projekt exportiert werden?

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

  • Erstellen Sie das Ziel für den Simulator und das iOS-Gerät.
  • Navigieren Sie zum Xcode-Ordner DerivedData für dieses Projekt und fassen Sie die beiden Binärdateien in einem einzigen Framework zusammen. Stellen Sie jedoch beim Erstellen des Framework-Ziels in Xcode sicher, dass die Zieleinstellung "Nur aktive Architektur erstellen" auf "NEIN" gesetzt ist. Auf diese Weise 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 festgelegt ist, und das Framework-Ziel gegen Release erstellen. Wenn immer noch ein Fehler beim Laden der Bibliothek auftritt, überprüfen Sie die Codeschnitte im Framework.

  • Verwenden lipo -info MyFramworkBinary und überprüfe das Ergebnis.

lipo -info MyFrameworkBinary

Ergebnis ist i386 x86_64 armv7 arm64

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

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

Dies ist, wie Carthage benutzt Lipo und Realm benutzt Lipo .


WICHTIGES DETAIL

Es gibt Radar: Xcode 6.1.1 & 6.2: iOS-Frameworks mit Simulator-Slices können nicht an den App Store gesendet werden und eine lange Diskussion darüber auf Realm # 116 und Carthage # 188 was mit einer speziellen Problemumgehung endete:

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

Carthage hat einen speziellen Code: CopyFrameworks und eine entsprechende Dokumentation:

Dieses Skript umgeht einen App Store Submission Bug , 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 zu umgehen, wenn universelle Binärdateien archiviert werden.

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

Ich selbst benutzte Realms strip-frameworks.sh was für mich perfekt funktioniert hat, ohne dass irgendwelche Änderungen vorgenommen wurden, obwohl natürlich jeder frei ist, eine von Grund auf neu zu schreiben.


Der Link zu meinem Thema, den ich empfehle zu lesen, da er einen weiteren Aspekt dieser Frage enthält: Codesignierung - Erstellen von iOS/OSX-Frameworks: Ist es erforderlich, diese vor dem Verteilen an andere Entwickler mit Codesignierung zu versehen?

78

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

  1. Einstellen ONLY_ACTIVE_Arch=NO in dem Build Settings

    • Erstellen Sie eine Bibliothek für den Simulator
    • Erstellen Sie eine Bibliothek für das Gerät
  2. Öffnen Sie in der Konsole den Ordner Products für Ihr Framework (Sie können ihn öffnen, indem Sie den Ordner framework öffnen und cd .. von dort)

enter image description hereenter image description here

  1. Führen Sie das Skript this aus dem Ordner Products aus. Es erstellt fettes Framework in diesem Ordner. (Oder machen Sie es manuell wie unten in 3. 4. )

Oder:

  1. Kombinieren Sie diese 2 Frameworks mit lipo durch dieses Skript (ersetzen Sie YourFrameworkName durch Ihren Framework-Namen)

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
    
  2. Ersetzen Sie durch eine neue Binärdatei eines der vorhandenen Frameworks:

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

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

Für Projekte, die nicht in Workspaces vorhanden sind:

Sie können auch versuchen, this Gist wie beschrieben here zu verwenden. Aber es scheint, dass es nicht für Projekte in Arbeitsbereichen funktioniert.

56
skywinder

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 das folgende Run Script Phase Hinzugefügt, um das für die Ausführung erforderliche vorkompilierte Framework automatisch zu kopieren die Architektur

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 muss ich weder lipo verwenden, um ein fettes Framework zu erstellen, noch den strip-frameworks.sh Des Realms, um unnötige Slices beim Senden an den App Store zu entfernen.

10
odm

im grunde habe ich dafür eine sehr gute lösung gefunden. Sie müssen nur diese einfachen Schritte befolgen.

  1. Erstellen Sie ein Kakao-Touch-Framework.
  2. Bitcode auf Nein setzen.
  3. Wählen Sie Ihr Ziel und wählen Sie Bearbeitungsschemata. Markieren Sie Ausführen und wählen Sie die Registerkarte Info.
  4. Keine andere Einstellung erforderlich.
  5. Erstellen Sie nun das Framework für einen beliebigen Simulator, da der Simulator auf einer x86-Architektur ausgeführt wird.
  6. Klicken Sie im Projektnavigator auf die Produktgruppe 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 das generische 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 sofortige Superverzeichnis von beiden. So wird die Verzeichnisstruktur jetzt:
    • Desktop
    • gerät
      • MyFramework.framework
    • simulator
      • MyFramework.framework
    • MyFramework.framework Öffnen Sie jetzt Terminal und CD auf dem Desktop. Beginnen Sie nun mit der Eingabe des folgenden Befehls:

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 zusammen, die in MyFramework.framework enthalten ist. Wir erhalten ein universelles Framework, das für alle Architekturen einschließlich Simulator und Gerät erstellt wird.

2
Nrip

Ich möchte nur aktualisieren diese tolle Antwort von @odm. Seit Xcode 10 ist das CURRENT_Arch Variable spiegelt nicht mehr die Build-Architektur 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 mir aufgefallen ist, dass zusätzliche Dateien in Unterverzeichnissen ansonsten nicht überschrieben würden.

2
Dorian Roy

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 (für Simulator und Gerät beide)?

  • 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 Simulator target

Schritte 2: Nachdem der Simulator-Erstellungsprozess erfolgreich abgeschlossen wurde, erstellen Sie jetzt ein Framework mit Auswahl des Geräteziels oder Auswahl des generischen iOS-Geräts

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

Schritt 4: Erstellen Sie nun endlich erneut 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:

enter image description here

enter image description here

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"
1