框架和业务分离

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

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

cocoapods引用第三方库

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

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

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

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

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

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

我现在的工程结构

FaceMatchPlatform是框架代码

JDFaceMatch是业务代码

Pods是生成的Pods工程

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

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

而如果我们的静态库也依赖于一些第三方,我们也可以在之前的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"]这种方式来获取。

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

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

所以,模仿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,不然也不会拷贝进去

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

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

  • 在Build Phases中可以新建Copy Files,可以选择想要编译的图片的路径和名字。
  • 编译后products的位置,这里可以修改为自己想要的路径


    框架和业务分离_第13张图片
    image.png
  • recursive属性
    recursive:遍历该目录,non-recursive:默认路径设置;不遍历该目录。如果路径的属性为recursive,那么编译的时候在找库的路径的时候,会遍历该目录下的所有子目录的库文件。

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

  1. cocoapods引用的framework文件是如何引用的?
  2. 关于bundle中有xib和其他文件等,cocoapods是如何处理的?
  3. 关于xcode定义${SRCROOT}等各种命令?
  4. 自己创建cocoapods库。

你可能感兴趣的:(框架和业务分离)