谈谈CocoaPods组件二进制化方案

栏目: Objective-C · 发布时间: 6年前

内容简介:谈谈CocoaPods组件二进制化方案

前言

为了加快编译速度,在工程拆分后,将一些常用库进行二进制化,工程引用库后不需要对源码进行编译。

本文内容适合工程需要二进制化并使用过CocoaPods的朋友,工程的依赖管理可以查看这篇: 谈谈iOS多工程依赖

方案

发现总结的方案有以下几种

  • 分仓库管理

  • podspec宏管理

  • prepare_command + Carthage/cocoapods packager/python/ruby

分仓库管理

创建了一个公用SDK仓库,专门放生成的Framework,spec文件内使用subspecs区分各个Framework。

公用SDK仓库目录结构

谈谈CocoaPods组件二进制化方案

公用SDK仓库spec统一管理

{
  "name": "MFSFrameworks",
  "version": "x.x.x",
  "summary": "MFSFrameworks Test",
  "description": "所有使用到的SDK集合, subspecs内容纯属模拟",
  "homepage": "http://imfong.com",
  "license": "MIT",
  "authors": {
    "maxfong": "devmaxfong@qq.com"
  },
  "platforms": {
    "ios": "6.0"
  },
  "source": {
    "git": "git仓库地址",
    "tag": "x.x.x"
  },
  "libraries": "xml2",
  "requires_arc": true,
  "subspecs": [
    {
      "name": "MFSCache",
      "resources": "MFSCache/*.bundle",
      "vendored_frameworks": "MFSCache/*.framework",
      "vendored_libraries": "MFSCache/*.a",
      "frameworks": "SystemConfiguration"
    },
    {
      "name": "MFSNetwork",
      "source_files": "MFSNetwork/*.{h,m}",
      "vendored_frameworks": "MFSNetwork/*.framework",
      "frameworks": [
        "AVFoundation"
      ],
      "libraries": [
        "z",
        "c++"
      ]
    },
    {
      "name": "MFSIdentifier",
      "source_files": "MFSIdentifier/**/*.{h}",
      "vendored_frameworks": "MFSIdentifier/*.framework",
      "frameworks": [
        "AdSupport"
      ],
      "dependencies": {
        "MFSCache": [
        ]
      }
    }
  ]
}

使用方式

pod 'MFSFrameworks', 'x.x.x',
    :subspecs => ['MFSNetwork', 'MFSCache', 'MFSIdentifier']

假设MFSIdentifier需要源码调试,podfile修改为

pod 'MFSFrameworks', 'x.x.x',
    :subspecs => ['MFSNetwork', 'MFSCache']
pod 'MFSIdentifier', 'x.x.x'

缺点

  • 需要额外维护一个公用SDK仓库

  • 维护2个spec,源码仓库也需要升级

  • 每次功能改动,需要打包并提交到公用SDK仓库

podspec宏管理

比对上一种方案,不需要创建公用SDK仓库,只需要维护源码仓库,将生成的Framework直接提交在源码仓库。

使用MFSIdentifier举例

podspec

使用pod lib create MFSIdentifier创建工程,会自动生成MFSIdentifier.podspec

可使用命令转换成json文件

pod ipc spec MFSIdentifier.podspec ? MFSIdentifier.podspec.json

podspec内是支持if、else语法的

Pod::Spec.new do |s|
  s.name             = 'MFSIdentifier'
  s.version          = '1.0.0'
  s.summary          = 'iOS App DeviceId'
  s.description      = < 'MIT', :file => 'LICENSE' }
  s.author           = { 'maxfong' => 'devmaxfong@qq.com' }
  s.source           = { :git => 'https://github.com/maxfong/MFSIdentifier.git', :tag => s.version.to_s }
  s.ios.deployment_target = '8.0'
44
  if ENV['IS_SOURCE']
    s.source_files = [
      'MFSIdentifier/*.{h,m}',
      'MFSIdentifier/**/*.{h,m}'
    ]
  else
    s.source_files = 'SDK/**/*.{h}'
    s.ios.vendored_frameworks = 'SDK/*.framework'
  end
  44
  s.dependency 'MFSCache'
  s.xcconfig = {
    'OTHER_LDFLAGS' => '-ObjC'
  }
end

仓库目录

提前将二进制文件编译好放在工程仓库的SDK目录内

谈谈CocoaPods组件二进制化方案

使用方式

正常使用

pod install

源码调试

IS_SOURCE=1 pod install

缺点

只支持私有源库,共有库提交后会变成podspec.json,不再支持if判断

每次修改代码需打包新Framework,可能遗漏

调试模式和正常使用切换需要清理Pod缓存

清理缓存

命令pod cache clean MFSIdentifier或删除/Users/[用户名]/Library/Caches/CocoaPods/Pods/Release/MFSIdentifier目录

移除工程中Pods/MFSIdentifier文件夹

参考 CocoaPods组件平滑二进制化解决方案

prepare_command + Carthage/cocoapods packager/python/ruby

Carthage

Carthage是一款去中心化的依赖管理器,只需要工程配置好,即可编译

//github
github "maxfong/MFSIdentifier" >= 1.0.0
//自定义git仓库
git "https://github.com/maxfong/MFSIdentifier.git"  >= 1.0.0  
//本地目录
carthage build --no-skip-current

配置Carthage时需选择Manager Schemes并对需要编译的Target勾选Shared,否则会出现提示 

Dependency "项目名" has no shared framework schemes

是因为Carthage编译基于xcodebuild,-workspace编译时需要-scheme参数

而我们配置.gitignore中排除了xcuserdata

git下载的工程(或删掉xcuserdata)后运行xcodebuild -list可以发现不存在Schemes一项

勾选Shared后会在.xcodeproj创建xcshareddata目录,里面保存着.xcscheme

局限性

  • 打成的动态Framework需要添加到工程Embeddd Binaries中,打包后的app内包含framework文件,影响包大小。

  • 使用Carthage生成的Framework,包含完整的类实现,如果依赖库过多影响整体包大小。

区分架构打包后需要通过脚本控制设备和模拟器的库引用比较麻烦

cocoapods packager

安装  
sudo gem install cocoapods-packager

局限性

不用的原因同Carthage,依赖过多会引起类冲突

开源项目将podspec文件也放在仓库中,是为了支持cocoapods packager

谈谈CocoaPods组件二进制化方案

Shell

工程原来使用的编译脚本就是shell,正好可以使用起来

# 更新CocoaPods
#pod update
55
# 填写Framework的Target名称
FMK_NAME=Target名称
WORKSPACE_NAME=${FMK_NAME}
SCHEME_NAME=${FMK_NAME}
# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=Products/${FMK_NAME}.framework
# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework
# project方式
# xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos clean build
# xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator clean build
# workspace方式
xcodebuild -workspace ${WORKSPACE_NAME}".xcworkspace" -configuration "Release" -scheme ${SCHEME_NAME} SYMROOT=$(PWD)/build -sdk iphoneos clean build
xcodebuild -workspace ${WORKSPACE_NAME}".xcworkspace" -configuration "Release" -scheme ${SCHEME_NAME} SYMROOT=$(PWD)/build -sdk iphonesimulator clean build
# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/"
# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/${FMK_NAME}"
rm -r "${WRK_DIR}"

使用这段脚本打出的Framework,不包含引用类,多个framework需相互依赖才可使用。

prepare_command

通过prepare_command 使Pod支持bash script。

CocoaPods prepare_command

使得我们提前执行设定的script,podspec文件改为:

{
  "name": "MFSIdentifier",
  "version": "1.0.0",
  "summary": "iOS App DeviceId",
  "description": "iOS App唯一标识符获取方案",
  "homepage": "https://github.com/maxfong/MFSIdentifier",
  "license": "MIT",
  "authors": {
    "maxfong": "devmaxfong@qq.com"
  },
  "platforms": {
    "ios": "8.0"
  },
  "source": {
    "git": "https://github.com/maxfong/MFSIdentifier.git",
    "tag": "1.0.0"
  },
  "dependencies": {
    "MFSCache": [ ]
  },
  "xcconfig" : {
    "OTHER_LDFLAGS" : "-ObjC"
  },
  "vendored_frameworks": "设定好的编译目录/*.framework",
  "prepare_command": "/usr/bin/python build_framework.py"
  //或
  // "prepare_command": "/usr/bin/ruby build_framework.rb"
  //或
  // "prepare_command": "/bin/sh pod package MFSIdentifier.podspec.json"
  //或
  // "prepare_command": "/bin/sh carthage build --no-skip-current"
}

寻一款熟悉的语言,工程目录内添加对应的脚本文件

I have a pod, I have a carthage, En…

完整的流程

工程创建

创建Cocoa Touch Framework,命名为iOSBinaryPractice

谈谈CocoaPods组件二进制化方案

开启Shared 

谈谈CocoaPods组件二进制化方案

设置Mach-O为Static Library,如果工程支持动态库,则不需要修改

谈谈CocoaPods组件二进制化方案

添加Podfile并pod update

这步是模拟支持依赖其他库,可以不需要

source 'https://github.com/CocoaPods/Specs.git'

target 'iOSBinaryPractice' do
pod 'MFSIdentifier'
end

添加功能类,引用依赖MFSIdentifier

谈谈CocoaPods组件二进制化方案

创建Example引用iOSBinaryPractice.framework

这步是测试iOSBinaryPractice.framework能否正常使用

谈谈CocoaPods组件二进制化方案

更新Podfile

source 'https://github.com/CocoaPods/Specs.git'

target 'iOSBinaryPractice' do
pod 'MFSIdentifier'
end

target 'Example' do
    pod 'MFSIdentifier'
end

在Example调用,发现运行一切正常 

谈谈CocoaPods组件二进制化方案

Shell创建

工程目录创建build_framework.sh,内容为之前 shell 脚本

如果仓库只要pod依赖,需要开启#pod update

FMK_NAME=Target名称需要修改,直接使用${PROJECT_NAME}会有问题

终端打开工程目录,执行sh build_framework.sh,查看是否生成了Products目录,并且iOSBinaryPractice.framework是否生成

podspec创建提交

创建podspec,测试并且提交cocoapods,最终的iOSBinaryPractice.podspec.json文件

过程省略

{
  "name": "iOSBinaryPractice",
  "version": "1.0.0",
  "summary": "iOSBinaryPractice",
  "description": "iOS 组件二进制化方案 Demo",
  "homepage": "https://github.com/maxfong/iOS-Library-Binary-Practice",
  "license": "MIT",
  "authors": {
    "maxfong": "devmaxfong@qq.com"
  },
  "platforms": {
    "ios": "7.0"
  },
  "source": {
    "git": "https://github.com/maxfong/iOS-Library-Binary-Practice.git",
    "tag": "1.0.0"
  },
  "source_files": "Products/**/*.{h}",
  "vendored_frameworks": "Products/*.framework",
  "dependencies": {
    "MFSIdentifier": [
    ]
  },
  "prepare_command": "/bin/sh build_framework.sh"
}

使用方式

在podfile中引用

pod 'iOSBinaryPractice', '1.0.0'

Installing iOSBiaryPractice 1.0.0过程时间会长一点,是在编译

完成后查看Pods目录文件结构

谈谈CocoaPods组件二进制化方案

调试问题

二进制化后的提高了工程编译速度,但是不可以调试,所以我们需要支持源码调试模式

创建0.1.alpha标签,规定0.1.alpha为调试版本,podspec内容

很难命名,这边就叫0.1.alpha,想直接定义为debug标签,但是CocoaPods不允许

1.标签排在第一位,一般不会被使用到

2.很难被重复定义

{
  "name": "iOSBinaryPractice",
  "version": "0.1.alpha",
  "summary": "iOSBinaryPractice",
  "description": "iOS 组件二进制化方案 Demo",
  "homepage": "https://github.com/maxfong/iOS-Library-Binary-Practice",
  "license": "MIT",
  "authors": {
    "maxfong": "devmaxfong@qq.com"
  },
  "platforms": {
    "ios": "7.0"
  },
  "source": {
    "git": "https://github.com/maxfong/iOS-Library-Binary-Practice.git",
    "tag": "0.1.alpha"
  },
  "source_files": [
    "iOSBinaryPractice/*.{h,m}"
  ],
  "dependencies": {
    "MFSIdentifier": [
    ]
  }
}

源码模式

在podfile中引用

pod 'iOSBinaryPractice', '0.1.alpha'

0.1.alpha标签类似一个指针,可以修改并指向代码的最新版本

如果发现源码与标签指向的不同,你可能需要做一次清理

参考文章之前的 清理

完整的代码

iOS-Library-Binary-Practice

后续

使用这种方式将Xcode的build时间提前到了pod update阶段,使得开发时效率加快。

文章的很多细节没有表达出来,如果实践有问题可以留言。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

大思维:集体智慧如何改变我们的世界

大思维:集体智慧如何改变我们的世界

杰夫·摩根 / 郭莉玲、尹玮琦、徐强 / 中信出版集团股份有限公司 / 2018-8-1 / CNY 65.00

智能时代,我们如何与机器互联,利用技术来让我们变得更聪明?为什么智能技术不会自动导致智能结果呢?线上线下群体如何协作?社会、政府或管理系统如何解决复杂的问题?本书从哲学、计算机科学和生物学等领域收集见解,揭示了如何引导组织和社会充分利用人脑和数字技术进行大规模思考,从而提高整个集体的智力水平,以解决我们时代的巨大挑战。是英国社会创新之父的洞见之作,解析企业、群体、社会如何明智决策、协作进化。一起来看看 《大思维:集体智慧如何改变我们的世界》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器