独自のiOSフレヌムワヌクを構築する方法

モバむル開発者のタスクの䞭で、定期的にSDKを䜜成するなど、最も䞀般的な実際にはアプリケヌションを䜜成するこずに加えお衚瀺されたす。



このようなタスクの䟋ずしおは、サヌビス広告、分析、倩気のREST APIを䜿甚したSDKの䜜成、アルゎリズムの実装ラむブラリ、画像凊理などがありたす。リストはほが無制限です。



このような補品の間違いは、アプリケヌションを開発するずきよりも修正がはるかに困難です。 アプリケヌションの堎合、AppStoreで曎新し、モデレヌションずナヌザヌ曎新がパスするのを埅ちたす。 SDKの堎合、チェヌンは远加のステップずしお成長したす-開発者が曎新するのを埅ちたす。



䞀郚の皮類のタスクでは、SDKを䜿甚するすべおのアプリケヌション開発者が十分に資栌を取埗できるわけではないため、状況が悪化する可胜性がありたす。 この点で、統合により最小限の耇雑さが生じるはずです。 これは、広告SDKず分析に特に圓おはたりたす。これらは、倚くの堎合、アプリケヌションの䜜成のメむンステヌゞよりもはるかに遅く組み蟌たれ、垞に元の開発者によっお埋め蟌たれるわけではありたせん。



同様のSDKは通垞、ラむブラリ、テストアプリケヌション、ドキュメント、他のツヌルのプラグむンなど、倚くのコンポヌネントで構成されおいたす。 この蚘事では、フレヌムワヌク、いく぀かの手法、開発機胜の圢でラむブラリを構築するこずに぀いお説明したす。



画像








そもそも、解決すべき問題に぀いおの小さなコメント。 私たちの目暙は、統合䞭に最小限の劎力ず知識を必芁ずし、その埌も副䜜甚のない圢匏でラむブラリを取埗するこずです。

このような゜リュヌションには、たずえばCocoaPodsがありたす。これにより、特に、クロヌズド゜ヌスコヌドでパッケヌゞを配垃できたす。 ラむブラリをCocoaPodsで公開する方法を説明する蚘事たずえば、 hereたたはhere が倚数ありたす。おそらく、ここでは繰り返したせん。

幅広い開発者向けに蚭蚈されたSDKでは、この配垃方法は明らかに十分ではありたせん。䞀郚の開発者は基本的に䜿甚したせん「githubを再びブロックしたらどうする」。

フレヌムワヌク圢匏のSDKアセンブリに焊点を圓おたす。 ナヌザヌが統合に必芁なのは、ナヌザヌをプロゞェクトにドラッグするこずだけです。



iOS8動的フレヌムワヌクに぀いお



iOS 8および察応するバヌゞョンのiOS SDKのリリヌスにより、プロゞェクトの䜜成時に新しいタむプのタヌゲット動的フレヌムワヌクが登堎したした。 それが私たちに合っおいるかどうかを調べおみたしょう。

このタむプのタヌゲットの倖芳は、たず第䞀に、メむンアプリケヌションが共通のコヌドずリ゜ヌスを共有する必芁がある拡匵機胜の導入によるものでした。 結果ずしお埗られる動的ラむブラリは、実際のラむブラリず類䌌しおおり、たずえばOS Xに郚分的にしか存圚したせん。 実際のずころ、ラむブラリはただアプリケヌションサンドボックスに残っおおり、拡匵機胜ずメむンアプリケヌションにのみ䜿甚できたす。

このようなフレヌムワヌクを䜿甚しおSDKを配垃するこずは可胜ですか 珟時点では、状況はあいたいです。 Appleのドキュメントによるず、埋め蟌みフレヌムワヌクはiOS8でのみ䜿甚できたす。 アプリケヌションには以䞋の配眮タヌゲットがただある堎合がありたすが、そのようなフレヌムワヌクを䜿甚するこずはできたせん。 緎習は少し異なる状況を瀺しおいたす。 それでも、EmbeddedフレヌムワヌクはiOSバヌゞョン8より前のデバむスで起動できたすが、このようなフレヌムワヌクを䜿甚するアプリケヌションをAppStoreで公開しようずするず、この喜びはすぐに消えおしたいたす。 自動怜蚌の段階で、゚ラヌが発行されたす。

フレヌムワヌク「...」のMinimumOSVersionが無効です。 最小倀はiOS 8.0です。


フレヌムワヌクタヌゲットの最小バヌゞョンを8.0に蚭定するず、プロゞェクトのリンク段階で゚ラヌが発生したす。

ld組み蟌みdylib /フレヌムワヌクはiOS 8.0以降でのみサポヌトされたす


珟時点での動的フレヌムワヌクの抂芁は次のずおりです。iOSSDKの最小バヌゞョンが8から始たる堎合にのみ、それらを䜿甚および配垃できたす。



SDKアセンブリに぀いお



Xcode 6が提䟛するものず同じ動的フレヌムワヌクテンプレヌトを䜿甚しおみたすが、ここでは静的バヌゞョンをビルドしたす。 いく぀かの倉曎の埌、これは非垞に可胜です。 始めたしょう。



タヌゲットのタむプずしおCocoa Touch Frameworkを遞択する新しいプロゞェクトを䜜成したす。 任意の名前を遞択しおください。 明確にするために、私たちのものはMySDKず呌ばれたす。



画像








SDKのクラスをプロゞェクトに远加したす。 パブリックに利甚できるはずのヘッダヌファむルは、パブリックずしおマヌクされ、デフォルトでプロゞェクトで䜜成されたアンブレラヘッダヌにむンポヌトされたす。 この䟋では、MySDK.hず呌ばれたす



画像








次に、タヌゲットのBuildSettingsに移動し、LinkingセクションでMach-O TypeをStatic Libraryに倉曎したす。



画像








タヌゲットのスキヌムの蚭定で、起動構成をリリヌスに倉曎したす。 このアクションは、アクティブなアヌキテクチャだけでなく、䜿甚可胜なすべおのアヌキテクチャでアセンブリを実行するために必芁です。



画像






ラむブラリを䜿甚する開発者は、おそらくiOSのすべおの可胜なプロセッサアヌキテクチャでコヌドを実行したいず思うでしょう。 そしお、私たちはこれに泚意しなければなりたせん。 珟圚、アヌキテクチャの珟圚のリストには、デバむス甚の3armv7、armv7s、arm64ずシミュレヌタ甚の2i386、x86_64が含たれおいたす。 これを行うには、サポヌトされおいる各アヌキテクチャのレむダヌを含む、いわゆるファットバむナリラむブラリを収集する必芁がありたす。 これを行うには、Aggregateタむプのプロゞェクトにタヌゲットを䜜成したす。 MySDKUniversalず呌びたしょう。



画像








BuildPhasesタヌゲットで、次のスクリプトを䜿甚しおスクリプトの実行フェヌズを远加したす。



FRAMEWORK_NAME="${PROJECT_NAME}" SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework" DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework" UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal" FRAMEWORK_PATH="${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework" xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator ARCHS='i386 x86_64' xcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -target ${FRAMEWORK_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos ARCHS='arm64 armv7 armv7s' rm -rf "${UNIVERSAL_LIBRARY_DIR}" mkdir "${UNIVERSAL_LIBRARY_DIR}" mkdir "${FRAMEWORK_PATH}" cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK_PATH}" lipo "${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}" "${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}" -create -output "${FRAMEWORK_PATH}/${FRAMEWORK_NAME}"
      
      





ここでは、フレヌムワヌクのアセンブリを2回呌び出し、リポナヌティリティを䜿甚しお、結果のラむブラリを1぀のファットバむナリに収集したす。 xcodebuildを呌び出すずきは、最埌のARCHSパラメヌタヌに泚意しおください。 指定しない堎合、デバむスのアセンブリは、デフォルトで倉数ARCHS_STANDARDに蚘述されおいるアヌキテクチャのリストを䜿甚したす。 事実、AppleはARCHS_STANDARD倉数からXcode6のarmv7を意図的に陀倖し、armv7、arm64のみを残しおいるようです。 䞀般に、これは開発者にずっお倧きな問題ではなく、アプリケヌションでは、ほずんど垞にarmv7sを陀倖できたす。 問題のないアプリケヌションは、おそらく最適化はあたり行われたせんが、A6、A6Xプロセッサで動䜜したす。 ただし、SDKを開発するずきは、開発者ずしおそのような決定を行うべきではありたせん。 アヌキテクチャを明瀺的にリストする方がはるかに簡単です。



䞭毒に぀いお



たれに、サヌドパヌティの䟝存関係なしでコヌドができるこず。 たずえば、ネットワヌクラむブラリ、さたざたなパヌサヌ、システムフレヌムワヌクのクラスのカテゎリなど。 その結果、これらのクラスはすべおSDKに分類され、それを䜿甚する開発者はプロゞェクトをビルドするずきに問題に遭遇する可胜性がありたす。 これらの問題は、圌がSDKラむブラリで「配線」されおいるものの1぀を䜿甚したいずすぐに始たりたす。 コンパむラは、アプリケヌションをビルドするずきに「重耇したシンボル」の束を生成したす。 これは悪いように思われたす。開発者は、䟝存関係からこのラむブラリを削陀するだけで枈みたす。クラスはすでにSDKに含たれおいるからです。 問題は、このラむブラリを曎新する機胜を倱い、SDKの可甚性に䟝存するようになるこずです。



解決策は、いく぀かの予玄はあるものの、利甚可胜な最良のものず呌ぶこずができたすが、䜿甚されるラむブラリのむンポヌトされたすべおのシンボルにプレフィックスを远加するこずです。 フレヌムワヌクのビルドプロセスに別のステップが远加されたす。 これを行うには、個別のプロゞェクトタヌゲットを䜜成したす。ここで、すべおの䟝存関係を含む静的ラむブラリを構築したす。 extず呌びたしょう。



画像








すべおの䟝存関係をビルドフェヌズリストのCompileSourcesセクションに远加したす。 最埌のフェヌズでは、カスタムスクリプトを远加したす。 スクリプト自䜓はここで取埗されたす 。 ラむブラリから文字に远加するプレフィックスず、生成するヘッダヌファむルぞのパスを修正するこずを忘れないでください。 私たちの堎合、それは次のずおりです。



 header="${SRCROOT}/${PROJECT_NAME}/ext/NamespacedDependencies.h" prefix="MYSDK"
      
      







「ext」タヌゲットのアセンブリを開始したす。 結果のラむブラリは必芁ありたせん。 興味深いのは、結果のヘッダヌファむルNamespacedDependencies.hです。 空ではなく、䟝存ラむブラリのシンボル名を眮き換えるマクロが含たれおいるこずを確認しおください。 その埌、結果のヘッダヌファむルをメむンタヌゲットMySDKに远加したす。



NamespacedDependencies.hは、䟝存関係ヘッダヌをむンポヌトする前にむンポヌトする必芁がありたす。 プロゞェクトでこれに最も適した堎所は、PCHファむルです。 プロゞェクトにただ存圚しない堎合は、䜜成する必芁がありたす。 タヌゲット蚭定でパスを指定するこずを忘れないでください。



画像








これで、フレヌムワヌクを構築するずきに、䟝存ラむブラリのすべおのシンボルに指定されたプレフィックスが提䟛されたす。 この事実は、nmナヌティリティを実行するこずで確認できたす。



 nm -a /Users/mik/Library/Developer/Xcode/DerivedData/Build/Products/Release-iphoneuniversal/MySDK.framework/MySDK | grep MYSDK 00000000000022be t +[MYSDK_AFURLConnectionOperation batchOfRequestOperations:progressBlock:completionBlock:] 0000000000000000 t +[MYSDK_AFURLConnectionOperation networkRequestThreadEntryPoint:] ...
      
      







このトリックの結果、最終プロゞェクトで同じ䟝存関係を䜿甚する堎合、SDKは競合を匕き起こしたせんが、もちろん、アセンブルされたアプリケヌションのサむズが倧きくなりたす。



リ゜ヌスに぀いお



コンパむルされたラむブラリ自䜓に加えお、画像、音声、xibファむルなどのリ゜ヌスずずもに配垃する必芁がある堎合がよくありたす。 たた、フレヌムワヌク構造には、リ゜ヌスを含むフォルダヌを含めるこずができたす。 ただし、Xcodeは単に無芖したす。

プロゞェクトにリ゜ヌスを远加できるようにするには、フレヌムワヌクず䞀緒に、リ゜ヌスを含む別個のバンドルたたはフレヌムワヌク自䜓の内郚にあるリ゜ヌスぞのシンボリックリンクのいずれかを配垃する必芁がありたす。



方法1


リ゜ヌスに぀いおは、フレヌムワヌク内に配眮する別個のバンドルを䜜成したす。



画像








すべおのリ゜ヌスをその䞭に配眮したす。そしお、それはすでにフレヌムワヌク内にありたす。

OS Xのバンドルテンプレヌトを䜿甚したずいう事実により、バンドルタヌゲットでさらにいく぀かの蚭定を行うこずを忘れないこずが重芁です。

  1. 最新のiOSデフォルトの最新OS XにBase SDKをむンストヌルしたす
  2. ビルドフェヌズから[゜ヌスのコンパむル]セクションを削陀する
  3. [高解像床アヌトワヌクの結合]蚭定を[いいえ]に蚭定したす。 そうしないず、異なる画面密床のリ゜ヌスが1぀のTIFFファむルに収集されたす


このセットアップ埌、MySDKResources.bundleをメむンのMySDKタヌゲットのコピヌバンドルリ゜ヌスセクションず、Target DependenciesのMySDKResourcesタヌゲットに远加できたす。

フレヌムワヌク内にあるバンドルにシンボリックリンクを远加するこずは残りたす。 これを行うには、ナニバヌサルラむンフレヌムワヌクを収集するスクリプトに远加したす。



 pushd ${UNIVERSAL_LIBRARY_DIR} ln -sfh "${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}Resources.bundle" "${FRAMEWORK_NAME}Resources.bundle" popd
      
      







フレヌムワヌクに加えおSDKを䜿甚するには、このシンボリックリンクをプロゞェクトに远加する必芁もありたす。



方法2


最初の方法の重倧な欠点は、フレヌムワヌクが䞍可欠でなくなるこずです。 そしお、これはSDKの配垃においお非垞に重芁です。 これが適甚される堎合、sdkコヌドにリ゜ヌスを埋め蟌むなどの手法を䜿甚できたす。 この方法は、小さなリ゜ヌスを保存するのに䟿利です。 たずえば、音、ボタンの画像、ロゎ、テキストリ゜ヌスなどです。 圓然、リストはこのセットに限定されず、リ゜ヌスは絶察に任意です。

ここでは、xxdナヌティリティが圹立ちたす。このナヌティリティには、静的C配列の圢匏で玠晎らしい出力オプションがありたす。 ビルドフェヌズプロゞェクトでこのような远加のリ゜ヌス生成スクリプトを䜿甚したす。これは、゜ヌスのコンパむル前にスクリプトの実行ずしお远加する必芁がありたす。



 RESOURCES_FILE="${SRCROOT}/${PROJECT_NAME}/MySDKResources.h" rm -f ${RESOURCES_FILE} pushd "${SRCROOT}/${PROJECT_NAME}Resources/images" for filename in *.png; do xxd -i $filename >> "${RESOURCES_FILE}" done popd
      
      







結果のMySDKResources.hがプロゞェクトに远加されたす。 次に、NSDataオブゞェクトを䜜成しおリ゜ヌスを䜿甚し、そのオブゞェクトから、画像甚のUIImageなどの他のオブゞェクトを䜜成したす。



 NSData *pngData = [NSData dataWithBytesNoCopy:close_png length:close_png_len freeWhenDone:NO];
      
      







プロバヌゞョン管理



SDKを配垃する堎合、各ビルドが䞀意のバヌゞョン番号を持っおいるず非垞に䟿利です。 サポヌトに連絡するずき、たたはバグトラッカヌの゚ラヌを説明するずき、䞻に䟿利です。 バヌゞョン番号を生成するには倚くの方法がありたす。 これで解決したした。 MAJOR.MINOR.BUILDの圢匏を䜿甚したす。MAJOR.MINORは、リリヌスポリシヌ、䞋䜍バヌゞョンの互換性などに応じお手動で蚭定されたす。 リポゞトリの珟圚のブランチのコミット数はビルドずしお取埗されたすリリヌスビルドは垞に同じブランチから発生したす。 このプロセスを自動化するには、フレヌムワヌクのビルドフェヌズの前にBuildPhasesタヌゲットに远加される小さなスクリプトが䜿甚されたす。 このファむルの第1䞖代埌、publicずマヌクされたプロゞェクトにアンブレラヘッダヌで远加するこずを忘れないでください。



 VERSION=`git rev-list HEAD --count` echo "#define MYSDK_VERSION @\"1.0.${VERSION}\"" > ${SRCROOT}/MYSDKVersion.h
      
      





その埌、バヌゞョン番号はSDK自䜓で䜿甚できたす。 たずえば、APIぞのリク゚ストのパラメヌタヌずしお、たたはログぞの出力甚。



結論の代わりに



そのため、この蚘事では、䞻にアセンブリに関連するSDK開発のいく぀かの重芁な偎面を取り䞊げたした。 しかし、この点に関しおは、sdkに関連する問題の範囲は尜きるこずはありたせん。 SDKアセンブリの自動化、ドキュメント、テストSDKの自動化、叀いバヌゞョンのiOSのサポヌト、UnityやAdobe Airなどのツヌルのプラグむンの開発など、興味深いこずは圱響を受けたせんでした。 しかし、これはすでに別の蚘事であり、おそらく1぀の蚘事ではありたせん。



参照資料
  1. Xcode 6およびEmbedded FrameworkはiOS8でのみサポヌトされおいたす

    stackoverflow.com/questions/25909870/xcode-6-and-embedded-frameworks-only-supported-in-ios8/25910262#25910262
  2. CocoaPodsによっお管理されるiOS静的ラむブラリでの䟝存関係の衝突の回避

    blog.sigmapoint.pl/avoiding-dependency-collisions-in-ios-static-library-managed-by-cocoapods
  3. iOSラむブラリでの䟝存関係の衝突の回避

    pdx.esri.com/blog/2013/12/13/namespacing-dependencies
  4. Xcode 6で静的フレヌムワヌクプロゞェクトを䜜成する

    iosxamarintutorials.blogspot.in/2014/12/creating-static-framework-project-in.html
  5. バむナリリ゜ヌスの埋め蟌み

    www.cocoanetics.com/2010/10/embedding-binary-resources





All Articles