"Fat" Cocoa Touch Framework (Simülatör ve Cihaz için) nasıl dışa aktarılır?


107

Xcode 6 ile kendi Dinamiklerini yaratma yeteneğine sahibiz Cocoa Frameworks.

görüntü açıklamasını buraya girin

Nedeniyle:

  • Simülatör hala 32-bitkitaplığı kullanıyor

  • 1 Haziran 2015'ten itibaren App Store'a gönderilen uygulama güncellemeleri 64 bit desteği içermeli ve iOS 8 SDK ( developer.apple.com ) ile oluşturulmalıdır

Projeyi cihazlarda ve simülatörlerde çalıştırmak için yağ kütüphanesi yapmalıyız. yani Frameworks'de hem 32 hem de 64 biti destekler.

Ancak herhangi bir kılavuz bulamadım, diğer projelerle gelecekteki entegrasyon için Universal fat Framework nasıl dışa aktarılır (ve bu kitaplığı biriyle paylaşılır).

İşte yeniden üretme adımlarım:

  1. Set ONLY_ACTIVE_ARCH=NOiçindeBuild Settings

    görüntü açıklamasını buraya girin

  2. Destek ekleyin armv7 armv7s arm64 i386 x86_64için Architectures(kesinlikle)

görüntü açıklamasını buraya girin

  1. Çerçeve oluşturun ve Finder'da açın:

görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin

  1. Bu çerçeveyi başka bir projeye ekleyin

Gerçek sonuç:

Ama sonunda, bu çerçeveyle projeyi aynı anda cihazlarda ve simülatörde çalıştırmakla ilgili sorun yaşıyorum.

  • Çerçeveyi Debug-iphoneosklasörden alırsam - cihazlarda çalışır ve simülatörlerde hata alır:ld: symbol(s) not found for architecture i386

      xcrun lipo -info CoreActionSheetPicker

    Fat dosyasındaki mimariler: CoreActionSheetPicker: armv7 armv7s arm64

  • Çerçeveyi Debug-iphonesimulatorklasörden alırsam - simülatörler üzerinde çalışır. ve cihazda hata var:ld: symbol(s) not found for architecture arm64

      xcrun lipo -info CoreActionSheetPicker

    Fat dosyasındaki mimariler: CoreActionSheetPicker: i386 x86_64

Peki, cihazlar ve simülatörler üzerinde çalışan dinamik bir çerçeve nasıl oluşturulur?

Bu cevap, Xcode 6 iOS ile ilgili Bir Cocoa Touch Çerçevesi Oluşturma - Mimariler sorunları, ancak yinelenmemiş.


Güncelleme:

Bu dava için bir "kirli bilgisayar" buldum. Benim Bkz aşağıda cevabını . Birisi daha uygun bir yol biliyorsa - lütfen bana bildirin!



@ AndriusSteponavičius bu sorular 2 ay önce soruldu.
skywinder

Evet, ama orada kullanıcıların bilmesi gerektiğini düşündüğüm çok daha ayrıntılı cevaplar var
Andrius Steponavičius

Derleme Ayarlarında ONLY_ACTIVE_ARCH = HAYIR olarak ayarlamak önemli bir adımdır.
Jedidja

Bilgisayarınızda 64 BIT MİMARİ OLSA BİLE simülatörde çalıştırmak istiyorsanız çerçevenizin hem i386 x86_64 dilimine ihtiyacı var! Bunu zor yoldan öğrendik.
J.beenie

Yanıtlar:


82

Bu cevabın gerçekliği: Temmuz 2015. Büyük olasılıkla işler değişecek.

TLDR;

Şu anda Xcode, evrensel fat çerçevesinin otomatik olarak dışa aktarılması için araçlara sahip değildir, bu nedenle geliştiricinin, lipoaracın manuel kullanımına başvurması gerekir . Ayrıca bu radara göre , çerçevenin tüketicisi olan AppStore geliştiricisine sunulmadan önce, liposimülatör dilimlerini bir çerçeveden çıkarmak için de kullanmalıdır .

Daha uzun cevap takip eder


Konuyla ilgili benzer bir araştırma yaptım (cevabın altındaki bağlantı).

Benim araştırma Apple Geliştirici Forumlar, Kartaca ve Diyar projeleri ve kendi deneylerinin keşif dayanıyordu yüzden dağılımı hakkında herhangi bir resmi belgelerine bulamamıştım xcodebuild, lipo,codesign araçlar.

İşte Apple Geliştirici Forumlarından uzun bir alıntı (benden bir miktar işaretleme ile) Gömülü çerçeveli dışa aktarma uygulaması :

Bir çerçeve projesinden bir çerçeveyi dışa aktarmanın doğru yolu nedir?

Şu anda tek yol, yaptığınız şeydir:

  • Hem simülatör hem de iOS cihazı için hedefi oluşturun.
  • Bu proje için Xcode'un DerivedData klasörüne gidin ve iki ikili dosyayı tek bir çerçevede birlikte lipo haline getirin. Ancak, Xcode'da çerçeve hedefini oluşturduğunuzda, 'Yalnızca Aktif Mimari Oluştur' hedef ayarını 'HAYIR' olarak ayarladığınızdan emin olun. Bu, Xcode'un birden çok binarty türü (arm64, armv7, vb.) İçin hedefi oluşturmasına izin verecektir. Bu, Xcode'dan çalışmasının ancak bağımsız bir ikili olarak çalışmamasının nedeni olabilir.

  • Ayrıca, şemanın bir Sürüm yapısına ayarlandığından emin olmak ve yayına karşı çerçeve hedefini oluşturmak isteyeceksiniz. Hala bir kitaplık yüklenmedi hatası alıyorsanız, çerçevedeki kod dilimlerini kontrol edin.

  • Sonucu kullanın lipo -info MyFramworkBinaryve inceleyin.

lipo -info MyFrameworkBinary

Sonuç i386 x86_64 armv7 arm64

  • Modern evrensel çerçeveler 4 dilim içerecek, ancak daha fazlasını da içerebilir: i386 x86_64 armv7 arm64 En azından bu 4'ünü görmüyorsanız, Etkin Mimari Oluştur ayarından kaynaklanıyor olabilir.

Bu, süreci, @skywinder'ın cevabında yaptığı gibi hemen hemen aynı şekilde tanımlar.

Carthage bu şekilde lipo kullanır ve Realm lipo kullanır .


ÖNEMLİ DETAY

Radar var: Xcode 6.1.1 ve 6.2: Simülatör dilimlerini içeren iOS çerçeveleri App Store'a gönderilemez ve Realm # 1163 ve Carthage # 188 üzerinde özel bir çözümle sonuçlanan uzun bir tartışma :

AppStore iOS çerçeve ikili dosyalarına gönderilmeden önce simülatör dilimlerinden çıkarılmalıdır

Kartaca'nın özel kodu vardır: CopyFrameworks ve ilgili belge parçası:

Bu komut dosyası , evrensel ikili dosyalar tarafından tetiklenen bir App Store gönderim hatası etrafında çalışır .

Realm özel bir komut dosyasına sahiptir: strip-frameworks.sh ve ilgili dokümantasyon parçası:

Bu adım, evrensel ikili dosyaları arşivlerken bir App Store gönderim hatasını gidermek için gereklidir .

Ayrıca iyi bir makale var: Xcode'da Dinamik Kitaplıklardan İstenmeyen Mimarileri Çıkarma .

Benim strip-frameworks.shiçin herhangi bir değişiklik yapmadan mükemmel çalışan Realm'leri kullandım , elbette herkes sıfırdan bir tane yazmakta özgür.


Bu sorunun başka bir yönünü de içerdiği için konuma ilişkin okumayı önerdiğim bağlantı: kod imzalama - iOS / OSX Çerçeveleri Oluşturma: diğer geliştiricilere dağıtmadan önce bunları kodlamak gerekli midir?


1
Lipo kullandım ama simülatörde çerçeve oluştururken, sınıf adıyla birlikte çözülmemiş tanımlayıcı gösteriyor ancak cihazda çalışıyor. İkilinin simülatör sürümünü kullanıyorsanız o zaman çalışıyor .. herhangi bir fikir?
Susim Samanta

2
Aralık 2016'da Xcode 8.2 tarafından bunun değiştiğine dair herhangi bir kanıt bulamadım.: /
Geoffrey Wiseman

1
@Geoffrey, bu Xcode 9.2'de mi değişti yoksa farklı bir şey mi var? Bu, dağıtım için ilk kez bir ikili çerçeve oluşturuyorum ve şimdiden korkuyorum ...
ScottyB

Bunu biraz, ne yazık ki yapmadım - söyleyemem. İyi şanslar.
Geoffrey Wiseman

57

Bu çok açık bir çözüm değil, ancak bulmamın tek yolu var:

  1. Set ONLY_ACTIVE_ARCH=NOiçindeBuild Settings

    • Simülatör için kitaplık oluşturun
    • Cihaz için kitaplık oluşturun
  2. ProductsÇerçeveniz için konsol klasöründe açın (çerçeve klasörünü açarak ve cd ..oradan açabilirsiniz )

görüntü açıklamasını buraya girin görüntü açıklamasını buraya girin

  1. Bu betiği Productsklasörden çalıştırın . Bu klasörde fat Framework oluşturur. (veya aşağıda 3. 4'te açıklandığı gibi manuel olarak yapın . )

Veya:

  1. Bu 2 Çerçeveyi lipo kullanarak bu komut dosyasıyla birleştirin ( YourFrameworkNameÇerçeve adınızla değiştirin )

    lipo -create -output "YourFrameworkName" "Debug-iphonesimulator/YourFrameworkName.framework/YourFrameworkName" "Debug-iphoneos/YourFrameworkName.framework/YourFrameworkName"
  2. Mevcut çerçevelerden yeni ikili biriyle değiştirin:

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

  1. Kar: ./YourFrameworkName.framework- kullanıma hazır yağ ikilisi! Bunu projenize aktarabilirsiniz!

Çalışma Alanlarında olmayan proje için:

Bu özü burada açıklandığı gibi kullanmayı da deneyebilirsiniz . Ancak görünüşe göre çalışma alanlarındaki projeler için işe yaramıyor.


Apple'ın artık şişman ikili dosyaları kabul etmediğini sanıyordum. kodmunki.wordpress.com/2015/03/04/…
Monstieur

1
@skywinder Cocoa Touch Framework'ü fat ikili kullanmaya hazır hale getirmek için başka basit bir yol buldunuz mu? Yukarıdaki ile aynı yaklaşımı kullanıyorum ama hoşuma gitmiyor. Xcode, süreci otomatikleştiren bazılarına sahip olmalıdır.
dev gr

1
@devgr henüz değil .. bu yüzden kendi cevabımı kabul etmedim. Hala daha iyi bir çözüm arıyorum.
skywinder

1
Simülatörde çalıştırılamıyor ancak cihazda 3 ve 4 kademeli çalışıyor
jose920405

1
@ neden yalnızca Debug-klasörün kullanıldığını açıklayabilir lipo -createmi? Bu çerçeve Releaseyapılandırma için kullanılabilir mi ve neden? Teşekkürler.
Yevhen Dubinin

10

@Stainlav cevabı çok yardımcı oldu, ancak bunun yerine çerçevenin iki sürümünü derlemek (biri cihaz ve diğeri simülatör için) ve ardından Run Script Phaseçalışan mimari için gereken önceden derlenmiş çerçeveyi otomatik olarak kopyalamak için aşağıdakileri ekledim

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

Bu şekilde, lipone Realm'in ne strip-frameworks.shde App Store'a gönderirken gereksiz dilimleri kaldırmak için şişman bir çerçeve oluşturmak için kullanmıyorum .


Hangisiyle bağlantı kuruyorsunuz?
Jaka Jančar

@ JakaJančar Klasördekilere bağlanıyorum ${SRCROOT}/Frameworks/Active. Derleme zamanında etkin mimari için doğru önceden derlenmiş çerçeveler için değiştirilirler.
odm

2
Sevdim! Bu, birleştir ve sonra ayır lipoyaklaşımından çok daha basit .
clozach

2

temelde bunun için çok iyi bir çözüm buldum. sadece bu basit adımları izlemeniz gerekir.

  1. Bir kakao dokunmatik çerçevesi oluşturun.
  2. Bit kodunu etkinleştirmeyi Hayır olarak ayarlayın.
  3. Hedefinizi seçin ve düzenlemeleri düzenleyin. Çalıştır'ı seçin ve Bilgi sekmesinden Serbest Bırak'ı seçin.
  4. Başka bir ayar gerekmez.
  5. Simülatör x86 mimarisinde çalıştığı için şimdi herhangi bir simülatör için çerçeve oluşturun.
  6. Proje Gezgini'nde Ürünler grubuna tıklayın ve .framework dosyasını bulun.
  7. Sağ tıklayın ve Bulucuda göster seçeneğine tıklayın. Kopyalayıp herhangi bir klasöre yapıştırın, kişisel olarak 'simülatör' adını tercih ediyorum.
  8. Şimdi, Generic iOS Device için çerçeve oluşturun ve 6'dan 9'a kadar olan adımları izleyin. Klasörü 'simulator' yerine 'device' olarak yeniden adlandırmanız yeterlidir.
  9. Aygıtın .framework dosyasını kopyalayın ve başka bir dizine yapıştırın. Her ikisinin de doğrudan süper dizinini tercih ederim. Böylece dizin yapısı artık şu hale gelir:
    • Masaüstü Bilgisayar
    • cihaz
      • MyFramework.framework
    • simülatör
      • MyFramework.framework
    • MyFramework.framework Şimdi terminali açın ve Masaüstüne cd yapın. Şimdi aşağıdaki komutu yazmaya başlayın:

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

ve bu kadar. Burada, MyFramework.framework içinde bulunan MyFramework ikili programının simülatör ve aygıt sürümünü birleştiriyoruz. Simülatör ve cihaz dahil tüm mimariler için oluşturulmuş evrensel bir çerçeve elde ediyoruz.


bit kodu etkinleştirilmiş FAT dosyası oluşturmak istiyorum. Lütfen bana yol göster.
user3898700

2

Sadece güncellemek istiyorum Bu harika yanıtı @odm . Xcode 10'dan beri, CURRENT_ARCHdeğişken artık yapı mimarisini yansıtmamaktadır. Bunun yerine platformu kontrol etmek için komut dosyasını değiştirdim:

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

Ayrıca, kopyalamadan önce hedef dizini temizlemek için bir satır ekledim, çünkü alt dizinlerdeki ek dosyaların aksi takdirde üzerine yazılmayacağını fark ettim.


1

Cevabım aşağıdaki noktaları kapsar:

  • Hem simülatör hem de Cihaz için çalışan bir çerçeve oluşturun

  • "Fat" Cocoa Touch Framework nasıl dışa aktarılır (hem Simülatör hem de Cihaz için)?

  • X86_64 mimarisi için tanımlanmamış semboller

  • ld: x86_64 mimarisi için semboller bulunamadı

Adım 1: Önce Simülatör hedefiyle çerçevelerinizi oluşturun

Adım 2: Simülatör oluşturma sürecinin başarılı olmasından sonra, şimdi cihaz hedef seçimi veya Genel iOS Cihaz seçimi ile çerçeveniz için oluşturun

Adım 3: Şimdi çerçeve hedefinizi seçin ve bunun için "Derleme Aşamaları" altında "Komut Dosyası Ekle" yi seçin ve aşağıdaki kod kodunu kopyalayın)

Adım 4: Şimdi nihayet, tekrar derleyin ve çerçeveniz hem simülatör hem de cihaz uyumluluğu için hazır. Yaşasın !!!!

[Not: Son adım 4'ten önce her iki uyumlu çerçeveye sahip olmalıyız (simülatör ve cihaz mimarisi uyumlu değilse, lütfen yukarıdaki 1. ve 2. adımları doğru şekilde izleyin)

Referans resme bakın:

görüntü açıklamasını buraya girin

görüntü açıklamasını buraya girin

Aşağıdaki kodu kabuk alanına koyun:

#!/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"


Bu komut dosyası kendisini çağırıyor ve böylece sonsuz bir döngüye neden oluyor gibi görünüyor !! Bilgisayarımı çalıştırdıktan sonra yeniden başlatmak zorunda kaldım! Sürekli olarak yeni xcodebuild süreçleri
üretiyor

Özyineleme sorunu olmayan benzer bir komut dosyası için bu SO S / A'daki @ l0gg3r yanıtına bakın .
J.beenie
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.