Xcode 6 und Embedded Frameworks werden nur in iOS8 unterstützt

68

Bei Verwendung eines eingebetteten Frameworks (dyld) in Xcode 6.0.1 mit einem Bereitstellungsziel weniger als iOS 8 erhalte ich:

  • Build ist erfolgreich
  • Fehler beim Laden der Laufzeitbibliothek

Error:

dyld: Library not loaded: @rpath/ObjectiveLyricsTouch2.framework/ObjectiveLyricsTouch2        
Referenced from: /private/var/mobile/Containers/Bundle/Application/DC65ACA9-98E5-46CD-95F8-829D3416F6C0/musiXmatch.app/musiXmatch
Reason: image not found
(lldb) 
loretoparisi
quelle
1
Ja, Sie können ein dynamisches Framework unter iOS 7 verwenden: quellish.tumblr.com/post/103107323582/…
quellish
@quellish gut zu wissen, hatte ein Gespräch mit Apple-Ingenieuren auf der WWDC '14. Sie haben diese Technik nicht vorgeschlagen. In einigen Fällen könnte dies jedoch eine mögliche Problemumgehung sein.
Loretoparisi

Antworten:

39

Einige Zeit dachte ich, dass dies auch mein Problem ist, aber für normale Apps ( Nicht-iOS-8-Erweiterung ) müssen Sie nur eine Build-Einstellung in Ihrem gelegentlichen Xcode 6 iOS Universal Framework-Ziel ändern ( Mach-O-Typ festlegen) zur statischen Bibliothek ):

Stellen Sie es auf Statische Bibliothek ein

Danach sollte es kein Problem mit iTunes Connect und iOS 7 geben :)

Maciek Czarnik
quelle
Dies funktioniert nicht und es wird ein Fehler bei der Validierung des iPA ausgegeben.
Ravi Dalmia
5
Während der Validierung wird "ein unerwarteter Mach-O-Header-Code gefunden: someNumbers .." angezeigt.
Ravi Dalmia
2
Ich bin nicht so weit gegangen, die App zu überprüfen, aber das hat bei mir bis zum Einreichen einer Binärdatei bei iTunes Connect funktioniert.
Anthony
1
Ähnlich wie Anthony sagte, konnte ich mit dieser Methode auch eine IPA gegen iTunes Connect validieren. Die App läuft sowohl auf einem iOS 7-Gerät als auch auf einem iOS 8-Gerät mit nur wenigen kurzen Tests. Gute Antwort.
Jonny
Kann jemand genehmigen, dass dies beim Einreichen im Appstore noch funktioniert?
Natanavra
30

Nachdem ich mich umgesehen hatte, kam ich mit der Lösung heraus

Wenn Sie möchten, dass Ihr MyEmbeddedFramework.framework zur App hinzugefügt wird, tun Sie dies

  1. Entfernen Sie MyEmbeddedFramework.framework auf der Registerkarte Allgemein> Eingebettete Binärdateien
  2. Entfernen Sie die Build-Phasen> Kopierphase "Frameworks", wenn Sie dort MyEmbeddedFramework.framework haben.
  3. Bereinigungsordner bereinigen
  4. Verschieben Sie das MyEmbeddedFramework.framework in den Abschnitt void Embedded Frameworks.
  5. Sie werden jetzt sehen, dass von XCode6 eine neue Build-Phase> Embedded Frameworks erstellt wird (nicht Sie, dies erfolgt automatisch).
  6. Wenn Sie jetzt 5 haben, sollte es ohne Fehler laufen.

Um es noch einmal zusammenzufassen, damit es funktioniert, sollten Sie MyEmbeddedFramework.framework in sehen

A) Allgemein> Eingebettete Binärdateien Allgemein> Eingebettete Binärdateien

B) Erstellungsphase> Eingebettete Frameworks Erstellungsphase> Eingebettete Frameworks

Es hat gut funktioniert auf iPhone5 / iOS8, nicht auf iPhone4S / iOS7, wo ich bekomme:

dyld: Bibliothek nicht geladen: @ rpath / ObjectiveLyricsTouch2.framework / ObjectiveLyricsTouch2 Referenziert von: /var/mobile/Applications/739D9C44-3B91-4D4F-805B-83BE66C9CBCA/musiXmatch.app/musiXmatch Grund: Kein geeignetes Bild gefunden. Gefunden: /private/var/mobile/Applications/739D9C44-3B91-4D4F-805B-83BE66C9CBCA/musiXmatch.app/Frameworks/ObjectiveLyricsTouch2.framework/ObjectiveLyricsTouch2: Inkompatibler CPU-Subtyp: 0x0000000 / 739D9C44-3B91-4D4F-805B-83BE66C9CBCA / musiXmatch.app / Frameworks / ObjectiveLyricsTouch2.framework / ObjectiveLyricsTouch2

Das Problem lag im EmbeddedFramework. Ich musste

1) Setzen Sie die Architektur auf die Standardeinstellung. 2) Setzen Sie die gültigen Architekturen auf: armv7, armv7s und armv64 (wie Apple vorschlägt, ist armv64 erforderlich, damit Embedded Frameworks funktionieren).

Dann konnte ich die App mit einem eingebetteten Framework ausführen

  • iPhone5S / iPhone5C iOS8
  • iPhone5S / iPhone5C iOS7
  • iPod 5. Generation / iOS7
  • iPhone4S / iOS7
  • iPhone4 / iOS7

Auf jeden Fall erhalte ich beim Senden an iTunesConnect einige Fehler für die minimal erforderliche Version:

  • Die MinimumOSVersion des Frameworks "..." ist ungültig. Der Mindestwert ist iOS 8.0.
  • Ungültige Architektur: Apps, die eine App-Erweiterung und ein Framework enthalten, müssen arm64 unterstützen.

Embedded Framework-Probleme

loretoparisi
quelle
12
Damit ich klar bin, sagen Sie, dass Ihre Ergebnisse zeigen, dass der App Store Submission Validator eine App ablehnt, die versucht, ein dynamisches Framework unter iOS 7 zu verwenden, obwohl das dynamische Framework unter iOS 7 ausgeführt werden kann.
Matt Foley
3
Ja, es ist genau das, was ich hier nach dem Hinzufügen der arm64-Unterstützung angefordert hatte, wenn Sie eine moderne iOS8-App haben, dh mindestens ein eingebettetes App / Widget-Plu-Embedded-Framework (wie bei Apple Docs). Dann antwortet iTunes Connect auf diese Weise.
Loretoparisi
2
Wir glauben, dass es nicht viel Hoffnung gibt, dass Apple es ihnen jemals erlaubt, auf iOS7 zu laufen und Probleme mit der Codesignatur im dynamischen Framework zu lösen.
Matt Foley
Soweit ich weiß und festgestellt habe, können Sie das eingebettete Framework nicht bereitstellen, wenn Sie es für iOS7 erstellen. In Entwicklungs- oder Intranet-Distributionsumgebungen funktioniert es wie hier gezeigt.
Loretoparisi
1
Wo ist der Abschnitt "in der Leere Embedded Frameworks". in Xcode? Ich sehe das nicht unter General
xta
12

Derzeit gibt es keine Möglichkeit, ein eingebettetes Framework zu verwenden, um Code zwischen einer App und einem Widget freizugeben und unter iOS 8 sowie iOS 7 und früheren Versionen auszuführen.

Hier finden Sie weitere Informationen zu http://atomicbird.com/blog/ios-app-extension-tips

Frameworks vs. iOS 7

Wenn Sie Code zwischen einer App und einer Erweiterung freigeben, können Sie dies auch tun, indem Sie ein eigenes eingebettetes Framework erstellen, in dem der Code gespeichert ist. Unter iOS 8 wird es in beiden Fällen dynamisch geladen, sodass Sie eingestellt sind.

Wenn Sie iOS 7 (oder früher) weiterhin unterstützen, ist dies nicht so eindeutig. Eingebettete Frameworks funktionieren dort nicht. Im Programmierhandbuch für App-Erweiterungen wird sofort darauf hingewiesen, dass Sie dlopen verwenden können, um damit umzugehen. Mit diesem Ansatz schreiben Sie Code, um das Framework zur Laufzeit dynamisch zu laden, anstatt sich darauf zu verlassen, dass iOS es für Sie lädt, wenn Sie überprüft haben, dass der Code auf einer iOS-Version ausgeführt wird, die dies unterstützt.

Aber wie verwendet man diesen Code unter iOS 7? Das tust du nicht. Wenn sich Ihr freigegebener Code in einem eingebetteten Framework befindet, können Sie ihn unter iOS 7 nicht ausführen. Er ist einfach nicht verfügbar.

Der dlopen-Ansatz kann nützlich sein, wenn Sie den freigegebenen Code nur unter iOS 8 benötigen. Wenn Sie ihn unter iOS 7 benötigen, müssen Sie ihn in das App-Ziel aufnehmen. Und wenn Sie das getan haben, brauchen Sie das Framework nicht mehr. Sie könnten weiterhin ein Framework für die App-Erweiterung verwenden, dies ist jedoch nicht sinnvoll. Sie würden das Framework erstellen, aber keinen Nutzen daraus ziehen. Fügen Sie einfach den gemeinsam genutzten Code in beide Ziele ein.

Und aus Apples Erweiterungshandbuch https://developer.apple.com/library/ios/documentation/General/Conceptual/ExtensibilityPG/ExtensibilityPG.pdf

Wenn Sie von Ihrer enthaltenen App aus eine Verknüpfung zu einem eingebetteten Framework herstellen, können Sie es weiterhin für Versionen von iOS bereitstellen, die älter als 8.0 sind, obwohl eingebettete Frameworks in diesen Versionen nicht verfügbar sind.

BigCheesy
quelle
BigCheesy Ich habe diese Dokumentation für dlopen gelesen, aber nichts verstanden. Ist es möglich, eingebettete Frameworks mit iOS7 zu verwenden
user1010819
@ user1010819 iOS 7 Laufzeit - Nr. Mit Bereitstellungsziel iOS 7 der Haupt-App - ja
Mike Glukhov
4

Der Fehler in xcode 6.1.1 wurde behoben

Öffnen Sie mit vim oder vi die Datei project.pbxproj.

Am Ende der Datei (Suche nach 8.1) befindet sich der Abschnitt XCBuildConfiguration starten

Suchen Sie nach Ihrem Framework.

In unserem Fall hatte der Eintrag in der Datei 8.1 für Debug & Release, obwohl das Bereitstellungsziel über Xcode -> Allgemein in den Zieleinstellungen auf 7.1 festgelegt wurde

Hier ist der alte Dateibereich wie folgt:

CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = ENFramework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 8.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";

Neuer Abschnitt sieht aus wie:

CURRENT_PROJECT_VERSION = 1;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
DYLIB_INSTALL_NAME_BASE = "@rpath";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = ENFramework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 7.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
VERSIONING_SYSTEM = "apple-generic";
VERSION_INFO_PREFIX = "";

Jetzt erhalten wir nicht nur eine Warnung (sondern funktioniert auf iOS 7.1-Geräten): ld: Warnung: Eingebettete Dylibs / Frameworks werden nur unter iOS 8 oder höher ausgeführt

Dies sieht aus wie ein Xcode-Fehler, der verschiedene iOS-Ziele falsch festlegt und dann Fehler verursacht.

Gammapunkt
quelle
1
Haben Sie bestätigt, dass es während des Einreichungsprozesses nicht abgelehnt wurde?
Hammett
funktioniert nicht und die Version wird auch nach Stationen korrekt angezeigt.
Ravi Dalmia
Dies ist die einzige Antwort auf dieser Seite, die für mich funktioniert hat. Einfach IPHONEOS_DEPLOYMENT_TARGET von 8.2 auf 7.1 geändert, die Projektdatei gespeichert und erfolgreich erstellt. Vielen Dank.
John Rogers
4

Bei der Apple-Dokumentation habe ich mich mit dem Befehl dlopen befasst , mit dem die Verknüpfung der Bibliotheken unter bestimmten Bedingungen abhängig von den unterstützten Systemversionen und Bibliotheken vorgenommen wird.

Anwendungsbeispiel dlopen: Ist die Funktion 'dlopen ()' eine private API?

Schauen wir uns also die von Apple Docs bereitgestellte Lösung an:

Bereitstellen einer enthaltenen App für ältere Versionen von iOS

Wenn Sie von Ihrer enthaltenen App aus eine Verknüpfung zu einem eingebetteten Framework herstellen, können Sie es weiterhin für Versionen von iOS bereitstellen, die älter als 8.0 sind, obwohl eingebettete Frameworks in diesen Versionen nicht verfügbar sind.

Der Mechanismus, mit dem Sie dies tun können, ist der Befehl dlopen , mit dem Sie ein Framework-Bundle bedingt verknüpfen und laden. Sie verwenden diesen Befehl als Alternative zu der Verknüpfung zur Erstellungszeit, die Sie im Zieleditor von Xcode General oder Build Phases angeben können . Die Hauptidee besteht darin , eingebettete Frameworks nur unter iOS 8.0 oder neuer mit Ihrer enthaltenen App zu verknüpfen .

Sie müssen Objective-C und nicht Swift in Ihren Code-Anweisungen verwenden, die ein Framework-Bundle bedingt laden. Der Rest Ihrer App kann in beiden Sprachen geschrieben werden, und das eingebettete Framework selbst kann ebenfalls in beiden Sprachen geschrieben werden.

Greifen Sie nach dem Aufruf von dlopen mit der folgenden Anweisung auf die eingebetteten Framework-Klassen zu:

MyLoadedClass *loadedClass = [[NSClassFromString (@"MyClass") alloc] init];

WICHTIG

Wenn Ihr enthaltenes App-Ziel mit einem eingebetteten Framework verknüpft ist, muss es die arm64-Architektur enthalten. Andernfalls wird es vom App Store abgelehnt.

So richten Sie ein App-Erweiterungs-Xcode-Projekt ein, um die bedingte Verknüpfung zu nutzen

  1. Legen Sie für jede Ihrer enthaltenen App-Erweiterungen das Bereitstellungsziel wie gewohnt auf iOS 8.0 oder höher fest. Tun Sie dies im Abschnitt "Bereitstellungsinformationen" der Registerkarte "Allgemein" im Xcode-Zieleditor.
  2. Legen Sie für Ihre enthaltene App das Bereitstellungsziel als die älteste Version von iOS fest, die Sie unterstützen möchten.
  3. Konditionieren Sie in Ihrer enthaltenen App Aufrufe des Befehls dlopen innerhalb einer Laufzeitprüfung für die iOS-Version mithilfe der systemVersion-Methode. Rufen Sie den Befehl dlopen nur auf, wenn Ihre enthaltene App unter iOS 8.0 oder höher ausgeführt wird. Verwenden Sie bei diesem Anruf unbedingt Objective-C und nicht Swift.

Bestimmte iOS-APIs verwenden eingebettete Frameworks über den Befehl dlopen. Sie müssen Ihre Verwendung dieser APIs genau wie beim direkten Aufruf von dlopen konditionieren . Diese APIs sind vom undurchsichtigen Typ CFBundleRef :

CFBundleGetFunctionPointerForName
CFBundleGetFunctionPointersforNames

Und aus der NSBundle-Klasse:

load
loadAndReturnError:
classNamed:

Rufen Sie in einer enthaltenen App, die Sie für Versionen von iOS bereitstellen, die älter als 8.0 sind, diese APIs nur innerhalb einer Laufzeitprüfung auf, die sicherstellt, dass Sie in iOS 8.0 oder neuer ausgeführt werden, und rufen Sie diese APIs mit Objective-C auf.

E-Riddie
quelle
2

Wir haben versucht, den neuesten Code für die folgenden Konfigurationen auszuführen:

iOS 8+ - iPhone 5s iOS 7.1.2 - iPhone 4 iOS 6.1.3 - iPad 4

Die App funktioniert auf allen drei Geräten einwandfrei, aber die Warnung ist beim Kompilieren im Xcode vorhanden. "Embedded Dylibs / Frameworks laufen nur unter iOS 8 oder höher"

Außerdem habe ich versucht, die App zu archivieren, um sie an den App Store zu senden.

Außerdem wurde ein Link gefunden, bei dem in einem Apple-Entwickler angegeben wurde, dass dies ein Fehler ist: https://devforums.apple.com/message/999579#999579

Ravi Dalmia
quelle
Wenn wir jedoch das Verteilungsprofil verwenden und versuchen, die App an itunesconnect zu senden. es gibt den Fehler aus Die MinimumOSVersion des Frameworks "..." ist ungültig. Der Mindestwert ist iOS 8.0.
Ravi Dalmia
2

Nur zur Veranschaulichung ... Ich hatte dieses Problem, als ich ein Projekt von iOS8 auf iOS7-Bereitstellungstyp änderte.

Die App verwendete Cocoapods und keine benutzerdefinierten eingebetteten Frameworks.

Ich musste das Hauptprojekt zwei Ziele ändern
Application
Application-Test

Ändern des Mach-O-Typs in statisch (von der obigen Antwort).

Dann zum Cocoapods-Projekt. Ändern Sie unter jedem Sub-Pod-Projekt den Mach-O-Typ in statisch, und lassen Sie die Mach-O-Einstellung für das Haupt-Pod-Projekt leer.

StuartM
quelle
2

Ich habe den Mach-O-Typ auf EXECUTABLE gesetzt und es hat bei mir funktioniert. Wenn Sie es auf "Statisch", "Dynamisch" oder "Bundle" setzen, treten beim Ausführen andere Fehler auf.

Ziel> "Ihre App"> Build-Einstellungen> Verknüpfen> Mach-O-Typ> Ausführbar

ctw
quelle
Hat auch für mich unter iOS 9.3.2 funktioniert, dies ist nur eine Lösung.
DzungPV
1

Ich löse dieses Problem folgendermaßen: Verwenden Sie dasselbe Bereitstellungsziel sowohl für das Ziel "Embedded Framework" als auch für das Ziel "Haupt-App".

Payal Maniyar
quelle
1

Also, vorübergehend, sagte ich nein zur dynamischen Bibliothek, während viele Geräte unter iOS 7. Wie ich mein Problem löste. Ich brauchte lib für die Übertragung des Modells zwischen App und Erweiterung. Also habe ich mein Modell in einen JSON-String in einen gemeinsam genutzten Container gelegt. Und es funktioniert wie ein Zauber.

Andrey Gagan
quelle
Dies ist eine gute Option, um das Objektmodell zu serialisieren / deserialisieren und über die Container-App und die Erweiterung freizugeben. Das Problem ist, wenn Sie ein komplexeres Framework haben und die Logik teilen müssen. Über die Sandbox, in der sich die eingebettete Binärdatei der Erweiterung und die App befinden, können Sie einen Dateisystemordner freigeben, sodass Sie auch eine gesamte Datenbank freigeben können.
Loretoparisi
0

Wenn Sie eine dynamische Bibliothek auf ios verwenden, müssen Sie die Bibliothek mit einem Code signieren. Im Xcode 6 sollten Sie "Code Sign On Copy" auswählen. Und mit dem Xcode5 sollten Sie die Bibliothek selbst mit dem Ausführungsskript signieren. mögen :

LOCATION="${BUILT_PRODUCTS_DIR}"/"${FRAMEWORKS_FOLDER_PATH}"
IDENTITY="iPhone Developer: xxxxx"
codesign --verbose --force --sign "$IDENTITY" "$LOCATION/BeeFramework.framework/BeeFramework"
iOkay
quelle
Dies funktioniert wirklich, da dies dazu führen kann, dass Ihre App ausgeführt wird. Aber Apple erlaubt das möglicherweise nicht.
iOkay
Ja, dadurch wird die App ausgeführt, dies schlägt jedoch während des Validierungsprozesses von itunesconnect fehl.
Ravi Dalmia
0

Entfernen Sie die Use Frameworks! aus Ihrer PodFile, wenn das Framework in iOS 7.0 funktionieren soll. Führen Sie den Befehl pod deintegrate aus, ändern Sie Ihre PodFile und führen Sie den Befehl pod install erneut aus

Auch danach musste ich alle .h-Dateien des Frameworks in die Bridging-Datei einfügen, wodurch das Problem behoben wurde. Entfernen Sie auch die importierte TestLibrary aus den schnellen Dateien

Sohil Dedhia
quelle
0

Ich hatte einen Fehler beim Update auf xcode 7.3. Und ich hatte eine Lösung für mich. - Ziele im Pods-Projekt ändern -> 7.0 - Hoffe es nützlich! Attacke

PhuocLuong
quelle
0

Ich hatte ein Problem, bei dem ich einige Bibliotheken als eingebettete Frameworks einbinden musste, andernfalls erhielt ich den obigen Fehler, und als ich genau das tat, erhielt ich Fehler beim Senden an den App Store.

Meine Lösung bestand darin, Pods zu verwenden und sicherzustellen, dass Sie die "use_frameworks!" Linie.

Jason Silver
quelle