# 为什么这么做?

  现在有这么一个使用场景,基线能生成项目A,项目B,项目C...如果只有项目A中使用SDK_A,其他项目都不使用,这时候就需要对基线进行差分,只有当我切换到项目A时,才插入SDK_A。

  不同于cocoapods的库管理方式,xcodeproj是通过脚本在编译前向项目中插入指定代码文件。

# Xcode中的项目结构

  

   项目中都会有个主target作为根节点,底下有很多group节点,这些group节点管理者三类文件

    1. 常规的 .h/.m 文件

    2. 资源文件

    3. 库文件,分为静态库.a文件、动态库.framework文件、阉割版的动态库embed franework文件

## 如何引入

   这里涉及到xcodeproj的具体使用,贴一下官方文档:

#获取项目
$project = Xcodeproj::Project.open($project_path); #获取target,通常取第一个为项目的主target
$target = $project.targets.first # 获取插件目录的group,如果不存在则创建
$group_One = $project[$plugin_folder] || $project.main_group.find_subpath(File.join($plugin_folder), true); # 在目标目录新建group目录
$group = $group_One.find_subpath($folderName, true)
$SDK_PATH = $group_One.real_path.to_s + "/" + $plugin_folder + "/" + $folderName # 判断SDK_PATH目录下是否存在第三方代码,不存在则退出
if !FileTest::exists?($SDK_PATH)
puts "SDK file not found in #{$SDK_PATH}"
exit 1
end

  * project_path 是项目的路径

  * plugin_folder 是插入的目录名称,它是创建在项目目录底下的

  * folder_name 是插入的第三方库的文件夹的名称,它是创建在plugin_folder目录底下的

  

  注意,这里的第三库的代码文件其实和项目的代码是放在一块的,我们要做的只是将它和项目关联起来,也就是在XXX.xcodeproj文件中添加其引用。具体的关联就是建立target底下的group组后 添加上述3类文件的引用。

  1. .h/.m 文件添加引用

if filePath.to_s.end_with?(".h") then
fileReference = aGroup.new_reference(filePath);
# aTarget.source_build_phase.add_file_reference(fileReference, true)
elsif filePath.to_s.end_with?(".m", ".mm", ".cpp") then
fileReference = aGroup.new_reference(filePath);
aTarget.source_build_phase.add_file_reference(fileReference, true)

  需要注意的是.h文件只需要 在group底下new一个reference,.m文件需要将group底下的reference添加进source_build_phase

  2. 资源文件添加引用

if filePath.to_s.end_with?(".bundle",".plist" ,".xml",".png",".xib",".js",".html",".css",".strings")
fileReference = aGroup.new_reference(filePath);
aTarget.resources_build_phase.add_file_reference(fileReference, true)

  根据资源文件创建其group的reference后,需要将其添加进resources_build_phase

  3. 库文件的引用

if filePath.to_s.end_with?(".framework" ,".a")
fileReference = aGroup.new_reference(filePath);
build_phase = aTarget.frameworks_build_phase;
build_phase.add_file_reference(fileReference);
if $isEmbed == true
#添加动态库
$embed_framework.add_file_reference(fileReference)
#勾上code sign on copy选项(默认是没勾上的)
$embed_framework.files.each do |file|
# puts "entry filePath : #{filePath} fileRef path : #{file.file_ref.path}"
if filePath.end_with?(file.file_ref.path) then
if file.settings.nil? then
# puts "setting is nil"
file.settings = Hash.new
end
file.settings["ATTRIBUTES"] = ["CodeSignOnCopy", "RemoveHeadersOnCopy"]
end
end
end

  库文件需将 reference 添加进frameworks_build_phase,如果是embed framework还需将其添加进embed_frameworks_build_phase,其在xcodeproj中的具体类型是PBXCopyFilesBuildPhase

## 如何清除

  因为SDK_A仅仅是项目A使用,如果从项目A切换到项目B,此时就得从XXX.xcodeproj文件中清除关于SDK_A的所有引用,其实是添加引用的一个逆向工程。

  上文中我们说到 将SDK_A插入{$PROJECT_PATH}/plugin_folder,所以只需遍历这个group,清除其中所有的reference即可。

def removeBuildPhaseFilesRecursively(aTarget, aGroup)
aGroup.files.each do |file|
if file.real_path.to_s.end_with?(".m", ".mm", ".cpp") then
aTarget.source_build_phase.remove_file_reference(file)
elsif file.real_path.to_s.end_with?(".bundle",".plist" ,".xml",".png",".xib",".js",".html",".css",".strings") then
aTarget.resources_build_phase.remove_file_reference(file)
elsif file.real_path.to_s.end_with?(".framework" ,".a")
aTarget.frameworks_build_phase.remove_file_reference(file)
# remove embed ref
if $isEmbed && !$embed_framework.nil?
$embed_framework.remove_file_reference(file)
end
end # extra r+emove file ref
file.remove_from_project
end aGroup.groups.each do |group|
# puts "group path : #{group.path}"
if group.path == "embed"
$isEmbed = true
end
removeBuildPhaseFilesRecursively(aTarget, group)
$isEmbed = false
end
end

  * .m 文件的引用由source_build_phase移除

   * 资源文件的引用由resources_build_phase移除

   * 库文件的引用由frameworks_build_phase移除,其中embed的framework还需由embed_framework_build_phase额外移除一下

# 后记

  xcodeproj 其实不光只是添加引用,xcode中的build_settings的所有选项几乎都可以通过xcodeproj的脚本控制,这里先按下不表。

  最后附一下 github的传送门地址:https://github.com/xuanyuelin/ManuallyInsertCodes

使用xcodeproj 动态插入第三方代码的更多相关文章

  1. js动态插入标签代码(insertAdjacentHTML)

    做网页时通过ajax请求获取到数据后,有的需要把数据拼接到带有各种标签的字符串中,拼接完字符串就需要把字符串动态添加到网页上的某个位置,举个

  2. 动态插入的html代码,点击节点无效以及获取节点下标的方法

    动态插入的html,需要使用delegate或者on事件来监听,方式如下. 如果需要获取节点对应的下标,$(this).index()是无法获取的,需要以$(selectot).index(this) ...

  3. (转载)JAVA动态编译--字节代码的操纵

    在一般的Java应用开发过程中,开发人员使用Java的方式比较简单.打开惯用的IDE,编写Java源代码,再利用IDE提供的功能直接运行Java 程序就可以了.这种开发模式背后的过程是:开发人员编写的 ...

  4. XML 动态 插入 父类标示 子类标示

    由于第一次写博客,写的不好的地方,还请各位大神多多指点, 讲解一下:xml动态插入数据并保存,写这个时候费了我不少劲,最后终于皇天不负有心人让我搞出来了,特意分享给大家,写的不完美的地方还请大家多多指 ...

  5. JavaScript 动态插入 CSS

    写组件时有时想把一些组件特性相关的 CSS 样式封装在 JS 里,这样更内聚,改起来方便.JS 动态插入 CSS 两个步骤就可以 创建一个 style 对象 使用 stylesheet 的 inser ...

  6. FMDB处理动态插入语句

    昨天做一个需求,参数的数量不确定,所以无法使用这个API: - (BOOL)executeUpdate:(NSString*)sql, ... 但是用 - (BOOL)executeUpdate:(N ...

  7. jquery动态插入行

    这是一个利用jquery动态插入输入内容的代码. html代码: <div title="分表2" class="ui-edit" style=" ...

  8. jquery动态插入行,不用拼写html,简洁版

    这个一个利用jquery实现动态插入输入行效果小功能,不用在javascript里拼写html字符串,更简洁.高效. html代码: <div class="fitem"&g ...

  9. iOS_动态插入或删除行

    终于效果图: 分MVC三层设计;自己定义的Cell有两种;一种是MainCell,由ModelArr提供数据源;还有一种是插入的cell,由代码创建,而且由另外一个数组供状态数据 数据源部分: wat ...

随机推荐

  1. python实现发送微信消息

    import json from threading import Timer from wxpy import * import requests import urllib.parse def g ...

  2. scrapy异常状态码处理

    scrapy异常状态码处理 在setting.py中加入 scrapy  的 state 默认只处理200到300之间 # 403状态的响应不被自动忽略,对403 的响应做个性化处理 HTTPERRO ...

  3. GeforceRTX系列参数对比

    GeforceRTX系列参数对比

  4. 2020年Yann Lecun深度学习笔记(下)

    2020年Yann Lecun深度学习笔记(下)

  5. Java线程池底层源码分享和相关面试题(持续更新)

    线程池各个参数讲解 public ThreadPoolExecutor(int corePoolSize, //线程池核心工作线程数量,比如newFixedThreadPool中可以自定义的线程数量就 ...

  6. 「题解」300iq Contest 2 H. Honorable Mention

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331H. 题意概述 给定一个长度为 \(n\) 的序列 \(a\),有 \(q\) 次询问,每次询问给定三个 ...

  7. Python 机器学习实战 —— 监督学习(上)

    前言 近年来AI人工智能成为社会发展趋势,在IT行业引起一波热潮,有关机器学习.深度学习.神经网络等文章多不胜数.从智能家居.自动驾驶.无人机.智能机器人到人造卫星.安防军备,无论是国家级军事设备还是 ...

  8. SQL server中自定义排序

    select * from OrderPolicyDetail order by ( case Project when 'C' then 1, when 'A' then 2, when 'D' t ...

  9. ES6学习笔记之函数(一)

    1.函数的默认参数 在ES6 之前,我们不能直接为函数的参数指定默认值,只能采用其他方法.如: function show (num, callback){ num = num || 6; callb ...

  10. external-provisioner源码分析(2)-main方法与Leader选举分析

    更多ceph-csi其他源码分析,请查看下面这篇博文:kubernetes ceph-csi分析目录导航 external-provisioner源码分析(2)-main方法与Leader选举分析 本 ...