iOS

iOS'de Evrensel Kütüphane Oluşturmak

Aramızda daha önce Xcode ile iOS’ta statik kütüphaneler oluşturmuş olanlar vardır. Kodunuzu bir lib.a gibi bir kütüphane dosyası ve içerisinde sadece public fonksiyonları içeren bir header dosyası ile birlikte dağıtır veya kullanırsınız. Bunun gerekliliği kaynak kodunuzu gös...

Abdulbasıt Tanhan |

23.09.2013

Aramızda daha önce Xcode ile iOS’ta statik kütüphaneler oluşturmuş olanlar vardır. Kodunuzu bir lib.a gibi bir kütüphane dosyası ve içerisinde sadece public fonksiyonları içeren bir header dosyası ile birlikte dağıtır veya kullanırsınız. Bunun gerekliliği kaynak kodunuzu göstermeden insanların faydasına sunmanız olabilir; aynı işi yapan birçok dosyayı her projeye taşımadan sadece bir binary ve ilişkili olan headerları taşımak olabilir. Buna benzer sebepleri çoğaltabiliriz.

Apple’a göre kütüphane paylaşılan kaynakları kapsayan hiyerarşik bir dizindir. Bu kaynaklara örnek olarak dinamik paylaşılan kütüphaneleri, nib dosyalarını, görselleri, lokalize stringleri, header dosyalarını ve referans belgelendirmeleri verebiliriz.

Bizim örneğimiz statik kütüphaneler üzerinden olacak. iOS’ta henüz dinamik kütüphane oluşturulmasına izin yok.

Burada dinamik ve statik kütüphaneler arasındaki farkı açıklamakta fayda var. Dinamik kütüphaneler paylaşımlı bir obje oluşturur ve uygulamalar bu objelerle bağlantı kurup objelerin yeteneklerini kullanabilirler. iOS’ta dışarıdan bir kütüphane yükleyip bunu birkaç uygulamanın kullanmasını sağlayamıyoruz. iOS kütüphaneyi uygulama içerisine gömüp sadece o uygulama tarafından kullanılmasına izin veriyor ki bu da aslında statik kütüphane olmuş oluyor.

Başlıktaki evrensel kütüphane kelimesi aslında birkaç mimarı yapı için oluşturulmuş kütüphaneleri ifade ediyor. Örneğin yarattığınız kütüphane i386 mimarisine uygun olduğunda projenizi iPhone Simulator’da test etme şansınız olur. Cihaz için ARMv7 mimarisine uygun olması gerekir. İkisi birden destekleniyorsa evrensel kütüphane olarak adlandırabiliriz.

 

Örnek Uygulama

İhtiyaç konusunu bir örnekle açıklayalım. Örneğin uygulamanıza bir web adresi vererek ve bunu yeni bir sayfada webview içerisinde açmasını istiyorum. Bu program parçacığını birçok projemde kullanmak istiyorum ve değişmediğini düşündüğümüz için tekrar derlenmesine ihtiyaç duymuyorum. Aynı zamanda dışarıdan müdahale edilmeden başkalarının kullanmasını istiyorum.

Bu durumda bunu bir kütüphane olarak tasarlayıp dağıtabilirsiniz. Kütüphanenin web adresi alan bir uygulama programlama arayüzü (API) olması yeterli. Bu örneği adım adım uygulayarak ilk evrensel kütüphanemizi oluşturalım. Burada ayrıca betikler ile kütüphanemizi paketleyip iOS kütüphane yapısına benzeteceğiz.

iOS Facebook kütüphanesinin FacebookSDK.framework yapısını incelediğinizde isminin .framework ile bittiğini görürsünüz. Dosya hiyerarşisi için aşağıdaki resim kısa bir fikir verebilir.
 

Header dosyaları Header klasörü içerisinde. İmaj ve UI dosyalarının tutulduğu bundlelar Resources klasörü içerisinde. Static binary kütüphane A dosyası içerisine ve uzantısız olarak yerleştirilmiş.

 

Yeni Statik Kütüphane Projesi Oluşturmak

Örnek projeyi Github’dan indirip deneyimleyebilirsiniz:

https://github.com/tanhan/WebViewFrameworkExample

Xcode -> File -> New -> Project -> Framework & Library -> Cocoa Touch Static Library seçtikten sonra WebView ismini vererek kütüphane şablonunu yaratmış oluruz.
 

 


Burada unutmadan Targets bölümünden Static kütüphane targetı üzerine gelip valid architectures kısmına i386 eklemeyi unutmayın. Bunu kütüphanemizin evrensel yani cihaz ve simülatörde çalışması için yapıyoruz.

Burada otomatik olarak gelen WebView.h ve WebView.m dosyalarını siliyorum.
 


WebViewController adında yeni bir UIViewController sınıfı ekliyorum.
 


WebViewController.xib dosyasını açarak View altına WebView objesi ekliyorum.
 


Bu WebView objesini kaynak dosyadaki WebView objemizle ilişkilendiriyoruz.

Buraya çok fazla kod ekleyip uzatmak istemedim.

WebViewController.h ve WebViewController.m içeriğine yukarıda verdiğim github linkindeki örnek projeden ulaşabilirsiniz.

 

Bundle Oluşturmak

İmaj, plist, xib ve benzeri dosyaları kütüphane içerisine koymak için Bundle'lar oluşturmamız gerekiyor. Yukarıdaki Facebook örneğinde resources klasörü altında bundleları görebilirsiniz.

Proje dosyası üzerine geldiğinizde targetları göreceksiniz. Sol aşağıdan Add Target seçeneğini seçerek. Framework & Library -> Bundle seçeneğinden WebViewBundle isminini vererek Bundle eklenir.
 

 


 

Bundle iOS’a uygun hale getirmek için Base SDK ve Architecture ayarları yapılır.

Burada unutmadan Targets bölümünden Bundle üzerine gelip, valid architectures kısmına i386 eklemeyi unutmayın. Bunu kütüphanemizin evrensel yani cihaz ve simülatörde çalışması için yapıyoruz.
 


Daha sonra bundle üzerine geldiğinizde Copy Bundle Resources bölümündeki sol alttaki artı işaretleri ile WebViewController.xib dosyası eklenir.
 

 

Evrensel Kütüphanemizi Oluşturalım

Burada amaç oluşturduğumuz statik kütüphane, bundle ve headerlarımızı ve bir araya getirip uzantısı .framework olan bir paket oluşturmak.

Add Target -> Aggregate seçilir.
 


 

Sağ alltan Add Run Script eklenir. Adını Build Static Libs olarak verebilirsiniz. Bu script static kütüphalerimizi ve bundlemızı oluşturacak. Shell kısmına aşağıdaki script yazılır.

[code]xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -target ${PROJECT_NAME}Bundle -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos[/code]
 


 

Sağ alltan yeni bir Add Run Script eklenir. Adını Build Universal Framework olarak verebilirsiniz. Buy script framework uzantılı paketi hazırlayacak. Shell kısmına aşağıdaki script yazılır.
 

 

[code]SIMULATOR_LIBRARY_INCLUDE_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/include/${PROJECT_NAME}" &&

DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" &&

BUNDLE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}Bundle.bundle" &&

UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal" &&

UNIVERSAL_LIBRARY_PATH="${UNIVERSAL_LIBRARY_DIR}/${PRODUCT_NAME}" &&

FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${PRODUCT_NAME}.framework" &&

# Create framework directory structure.

rm -rf "${FRAMEWORK}" &&

mkdir -p "${UNIVERSAL_LIBRARY_DIR}" &&

mkdir -p "${FRAMEWORK}/Versions/A/Headers" &&

mkdir -p "${FRAMEWORK}/Versions/A/Resources" &&

# Generate universal binary for the device and simulator.

lipo -create "${SIMULATOR_LIBRARY_PATH}" "${DEVICE_LIBRARY_PATH}" -output "${UNIVERSAL_LIBRARY_PATH}" &&

# Move files to appropriate locations in framework paths.

cp "${UNIVERSAL_LIBRARY_PATH}" "${FRAMEWORK}/Versions/A" &&

ln -s "A" "${FRAMEWORK}/Versions/Current" &&

ln -s "Versions/Current/Headers" "${FRAMEWORK}/Headers" &&

ln -s "Versions/Current/Resources" "${FRAMEWORK}/Resources" &&

ln -s "Versions/Current/${PRODUCT_NAME}" "${FRAMEWORK}/${PRODUCT_NAME}" &&

cp "${SIMULATOR_LIBRARY_INCLUDE_PATH}/WebViewController.h" "${FRAMEWORK}/Headers/"

cp -r "${BUNDLE_LIBRARY_PATH}" "${FRAMEWORK}/Resources/"[/code]
 

Aggregate target'ı çalıştırıldığında, geliştirme çatımız (framework) aşağıdaki resimde gösterilen dizinde oluşacaktır. Frameworkler Xcode -> Preferences -> Locations -> Derived Data dizininde oluşur.

Lütfen ayrıntılar ve oluşturulan bir WebViewFramework.framework ile yapılan BrowserUsingWebViewFramework örneğini inceleyiniz.

Kaynak kodları: https://github.com/tanhan/WebViewFrameworkExample

Abdulbasıt Tanhan |

23.09.2013

Yorumlar

Abdulbasıt Tanhan
09.11.2013 - 06:53

Geçenlerde oluşturduğum frameworku projede kullanırken armv7' ye uygun olmadığı hatası alıyordum. Bir saat uğraştıktan sonra yukarıdaki yazıda da atlamış olduğum bir alandan dolayı olduğunu buldum.

Target -> Build Settings -> Build Active Architecture Only -> NO yapmanız gerekiyor.