框架和业务分离

这段时间对项目进行重构,将业务和框架的代码分离,减少彼此之间的耦合,从工程结构层面上做到组件化开发和模块开发。

在这过程中遇到很多以前一直很纳闷的问题,在此记录一下,利己利他。

cocoapods引用第三方库

以前一直很奇怪cocoapod创建的workspace是如何将第三方的框架引用到自己的工程里,因为每个工程的文件是相互隔离,不能相互调用使用,那么pod是怎么做到的呢。

我们先看一下pod install后会生成一个xcworkspace为后缀名的文件,他其实是一个工作站,可以包含很多工程(即以xcodeproj为结尾的文件),而一个工程里其实也可以包含很多的Target,具体关于workspaceprojecttarget之间的讲述网上很多,这里我不过多的描述。

而我们看pods工程下有很多的Target,这些Target是你引用的每个第三方库,pods将我们每个引用的第三方库做成一个.a形式的静态库。

QQ20180821-204712@2x.png

同时我们注意到,这里还会生成一个以Pods-工程名为名字的.a静态库(即Pods-FaceMatchPlatform),我们看到他的Target Dependencies里含有我们引用的第三方的.a。

我们回到自己创建的工程里,Link Binary中含有pods中的.a静态库。

QQ20180821-205405@2x.png

由此,我们可以得到结论,pods引用第三方的方式是将所有的第三方库创建成.a的文件,同时会创建一个Pods-工程名为名字的静态库,而我们的工程里就是引用这个Pods-工程名静态库来实现第三方的引用的。

我现在的工程结构

QQ20180821-212141@2x.png

FaceMatchPlatform是框架代码

JDFaceMatch是业务代码

Pods是生成的Pods工程

将框架公用部分做成静态库

基于上面的思想,我将自己项目中公用的框架部分做成一个库,这样我们在其他的业务工程里就可以使用框架的文件来实现自己的需求,如果在不断增加的业务中,我们只要创建不同的业务工程就可以实现不同的业务的代码分离。

QQ20180821-210454@2x.png

而如果我们的静态库也依赖于一些第三方,我们也可以在之前的Podfile文件的基础上增加我们这个静态库Target的依赖。

platform :ios,'8.0'

workspace 'FaceMatchPlatform'

project 'FaceMatchPlatform.xcodeproj'
project 'JDFaceMatch/JDFaceMatch.xcodeproj'


target "FaceMatchPlatform" do
    pod 'FMDB'
    pod 'SDWebImage'
    pod 'MBProgressHUD', '~> 0.8'
    pod 'Bugly'
    pod 'AFNetworking', '~> 3.0'
project 'FaceMatchPlatform.xcodeproj'
end

target "PlatformLib" do
    pod 'FMDB'
    pod 'SDWebImage'
    pod 'MBProgressHUD', '~> 0.8'
    pod 'Bugly'
    pod 'AFNetworking', '~> 3.0'
project 'FaceMatchPlatform.xcodeproj'
end

框架中有图片的处理

我们知道在工程中,如果我们使用imageNamed来加载图片,那么寻找到的是.app包里面最上层目录下的图片,如果是bundle下的图片我们不能直接取到。如下图中红框部分图片可以取到,但是Resource.bundle中的图片我们必须用[UIImage imageNamed:@"Resource.bundle/xxx.png"]这种方式来获取。

QQ20180821-210746@2x.png

如果工程里直接加入了.bundle的文件,那么工程打包的时候会将这个bundle打包进.app的目录下。

如果cocoapods引用的第三方有图片资源,pods是怎么处理的呢?我看了一下pod的处理方式,是在自己的工程里加入了一段shell脚本,这段shell脚本的作用就是将用到的第三方的bundle文件镜像拷贝到.app的目录下。

QQ20180821-211304@2x.png

所以,模仿cocoapods的处理方式,我修改了一下shell脚本,可以将在框架工程里的bundle的文件拷贝到.app的目录下。

shell脚本

#!/bin/sh
set -e
set -u
set -o pipefail

if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
    # If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
    # resources to, so exit 0 (signalling the script phase was successful).
    exit 0
fi

mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"

RESOURCES_TO_COPY=${TARGET_BUILD_DIR}/resources-to-copy-${TARGETNAME}.txt
> "$RESOURCES_TO_COPY"
# echo "$RESOURCES_TO_COPY"

XCASSET_FILES=()

install_resource()
{
  if [[ "$1" = /* ]] ; then
    echo "root"
    RESOURCE_PATH="$1"
    echo "$RESOURCE_PATH"
  else
    echo "PODS_ROOT"
    RESOURCE_PATH="${SRCROOT}/$1"
    echo "$RESOURCE_PATH"
  fi
  if [[ ! -e "$RESOURCE_PATH" ]] ; then
    cat << EOM
error: Resource "$RESOURCE_PATH" not found. Please build the resource first.
EOM
    exit 1
  fi
  case $RESOURCE_PATH in
    *.storyboard)
      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
      ;;
    *.xib)
      echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}" || true
      ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
      ;;
    *.framework)
      echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
      mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
      echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}" || true
      rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
      ;;
    *.xcdatamodel)
      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\"" || true
      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
      ;;
    *.xcdatamodeld)
      echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\"" || true
      xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
      ;;
    *.xcmappingmodel)
      echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\"" || true
      xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
      ;;
    *.xcassets)
      ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
      XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
      ;;
    *)
      echo "$RESOURCE_PATH" || true
      echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
      echo "$RESOURCES_TO_COPY"
      ;;
  esac
}

if [[ "$CONFIGURATION" == "Debug" ]]; then
#此处传入你自己的目录
    install_resource "${SRCROOT}/../FaceMatchPlatform/Lib/JFace/Resource.bundle"
    install_resource "${TARGET_BUILD_DIR}/CommonBundle.bundle"
fi
if [[ "$CONFIGURATION" == "Release" ]]; then
#此处传入你自己的目录
    install_resource "${SRCROOT}/../FaceMatchPlatform/Lib/JFace/Resource.bundle"
    install_resource "${TARGET_BUILD_DIR}/CommonBundle.bundle"
fi

mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
  mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
  rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
fi
rm -f "$RESOURCES_TO_COPY"

if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
then
  # Find all other xcassets (this unfortunately includes those of path pods and other targets).
  OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
  while read line; do
    if [[ $line != "${PODS_ROOT}*" ]]; then
      XCASSET_FILES+=("$line")
    fi
  done <<<"$OTHER_XCASSETS"

  if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
    printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
  else
    printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_BUILD_DIR}/assetcatalog_generated_info.plist"
  fi
fi

这样,我们就可以处理bundle的问题了。

其他

  • Header search Paths:是.h文件的搜索路径

  • Framework search Path:是.framework文件的搜索路径

  • Library search Path:是.a文件的搜索路径

  • 如果你的工程里依赖了bundle文件,那在Copy Bundle Resources中也要加入这个bundle,不然也不会拷贝进去

    QQ20180821-211622@2x.png
  • framework编译时Copy Bundle Resources如果加入了文件,该文件会一同打包进framework里,所以在这里加入图片在外面用的时候还是没法获取到。

    QQ20180822-103617@2x.png
  • 在.app中,静态库会直接打包进app的二进制文件中,而动态库在工程里配置时需要Embedded Binaries中加入,会在.app目录下有一个Frameworks的目录,里面存放动态库。

QQ20180822-104932@2x.png
QQ20180822-105010@2x.png
  • 在Build Phases中可以新建Copy Files,可以选择想要编译的图片的路径和名字。
QQ20180822-111203@2x.png
QQ20180822-111453@2x.png
  • 编译后products的位置,这里可以修改为自己想要的路径


    image.png
  • recursive属性
    recursive:遍历该目录,non-recursive:默认路径设置;不遍历该目录。如果路径的属性为recursive,那么编译的时候在找库的路径的时候,会遍历该目录下的所有子目录的库文件。

还有几个问题暂时还没调研清楚:

  1. cocoapods引用的framework文件是如何引用的?
  2. 关于bundle中有xib和其他文件等,cocoapods是如何处理的?
  3. 关于xcode定义${SRCROOT}等各种命令?
  4. 自己创建cocoapods库。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,165评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,720评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,849评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,245评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,596评论 3 288
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,747评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,977评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,708评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,448评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,657评论 2 249
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,141评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,493评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,153评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,108评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,890评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,799评论 2 277
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,685评论 2 272

推荐阅读更多精彩内容

  • 1、通过CocoaPods安装项目名称项目信息 AFNetworking网络请求组件 FMDB本地数据库组件 SD...
    X先生_未知数的X阅读 15,937评论 3 118
  • 静态库与动态库的区别 首先来看什么是库,库(Library)说白了就是一段编译好的二进制代码,加上头文件就可以供别...
    吃瓜群众呀阅读 11,621评论 3 42
  • 总的来说,从事商业活动需要敏锐快速的反应,但没有什么能与控制自己负面念头所需要的敏锐快速的反应相提并论的。在你受到...
    柔光宝宝阅读 292评论 0 0
  • 【读经】 雅歌5 【金句】 他的口极其甘甜;他全然可爱。耶路撒冷的众女子啊,这是我的良人;这是我的朋友。(雅歌 5...
    chanor阅读 264评论 0 0
  • 奎叔,又谈恋爱了! 这个消息犹如重磅炸弹在街坊邻里炸开了锅。 街坊邻里之所以会炸开锅,主要是因为,奎叔这人生的第二...
    丁香静阅读 446评论 3 2