ReactNative进阶(五十一)project.pbxproj 配置文件详解

本文主要是介绍ReactNative进阶(五十一)project.pbxproj 配置文件详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • 一、前言
    • 二、project.pbxproj 文件解析
    • 三、证书更换
    • 四、探寻scheme 与 target
      • 4.1 scheme
      • 4.2 target

一、前言

Xcode作为日常开发iOS程序的IDE,支持CC++Objective-CSwiftRuby等语言进行编写。日常开发入口就是Xcode workspace或者Xcode project

workspace是一个Xcode文档,它将项目和其他文件、project分组。一个workspace可以包含任意数量的Xcode project,以及资源文件(JSON、脚本、图片、视频等)。workspace除了组织每个project中的文件外,还提供了所包含项目及其目标之间的隐式和显式关系。

project就是一个 Xcode 工程,它是实际管理工程下 targets 、源码、资源文件、framework 等。project 只是一个容器,本身是无法被编译的,所以每个 project 至少应该有一个可编译的 target, target下需要包含可编译的源码。

在这里插入图片描述
由上图可以简单看出workspaceproject的关系:

  • 一个workspace里可以包含多个project
  • 一个project里包含多个target
  • configurationXcode中的Debug/Release 等工程配置;
  • scheme 配置target编译参数;
  • 每个target即每次编译生成对应产物:app或者framework

Xcode 中能看见所有的公共配置信息都存在于 project.pbxproj 中。pbxproj全拼是Project Builder Xcode Project,它其实是我们熟悉的plist文件的一种,但是它不像我们常用的plist文件有着优越的可读性,由于历史原因它才被Xcode一直保存下来。

pbxproj中定义了targetscript、文件、configuration等之间的引用关系,我们看到的Xcode项目布局实际上是可视化了pbxproj

pbxproj主要包含跟文件相关的 BuildFileGroupFileReference;跟编译相关的 BuildPhaseBuild Configuration(List);以及一些列 TargetTargetDependency

开发者比较关键的信息是配置应用PP文件、包名及APP 版本号。

MARKETING_VERSION = 2.4.2;
ONLY_ACTIVE_ARCH = YES;
OTHER_CODE_SIGN_FLAGS = "--deep";
OTHER_LDFLAGS = ("$(inherited)","-ObjC","-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = com.shq5785.com;
PRODUCT_NAME = shq5785;
PROVISIONING_PROFILE_SPECIFIER = "ppFile";

二、project.pbxproj 文件解析

project.pbxproj 文件包含于 Xcode 工程文件 *.xcodeproj 之中,存储着 Xcode 工程的各项配置参数。它本质上是一种旧风格的 Property List 文件,历史可追溯到 NeXT 的 OpenStep。其可读性不如 xmljson,苹果却一直沿用至今,作为一家以创新闻名的公司可能这里剩下的就是情怀吧。

project.pbxproj 使用 UUID 作为交叉引用的索引,保证每个配置信息对象的唯一性。因为 UUID 根据机器硬件和时间戳生成,避免了多人在同一时间段操作修改工程文件带来的问题。也就是说工程中每项配置对象都有个唯一的 UUID,然后其他配置对象想引用某个配置对象直接使用它的 UUID 即可。这就跟我们编程时使用指针指向某个对象的地址一样,其他对象的属性想引用它,只需要给属性传个指针地址就行了。

可以把整个文件的内容想象成一个字典,字典中的 Key 按照字典序来排列。字典的第一层级总共有 5 个键值对,Key 分别为:archiveVersionclassesobjectVersionobjectsrootObject。其中重要的 KeyobjectsrootObject

在这里插入图片描述

所有的配置对象都放在 objects 对应的 Value 中,包括根对象(rootObject)。 objects 对应的 Value 也是一个字典,Key 都为 UUID,Value 依然是个字典。可以将 rootObject 的值(是一个 UUID)作为 Keyobjects 对应的字典中找到根对象。这个根对象的 isa 属性为 PBXProjectisa = PBXProject)。读懂 project.pbxproj 的最好方式就是顺着 rootObject 的各个属性对应的 UUIDobjects 中找到对应的对象,然后一层层看下去。这样整个文件的配置信息存放方式就慢慢摸清了。

objects 的键值对根据内容类型被分成了若干个 section,虽然 section 的顺序是 Xcode 私有 API 钦定的,但每个 section 内部的键值对会根据 Key 的字典序排列。采用注释的方式分节也使得可读性更强。section 的数量跟工程有关,尤其是每个工程的 BuildPhaseTarget 差别都很大。

每个 section 中的对象类型都是相同的,对象的类型是靠 isa 的值区分的。对象内部的属性类型以及含义可以参照这篇文章提供的对照表: Xcode Project File Format

每个对象内部的属性(也是键值对)会把 isa 排在最前面,其余的按照字典序排列。

数组内部的顺序完全按照元素内容的字典序排列。

大概分为以下几类信息:

  • 工程中的文件关联信息、资源关联信息

    • PBXBuildFile 参与编译的文件;

    • PBXFileReference 工程中的所有文件信息;

  • 文件的组织结构信息

    • PBXGroup 工程中的文件夹;
  • 工程的编译配置、证书配置信息

    • PBXResourcesBuildPhase 编译阶段的资源配置;

    • PBXFrameworksBuildPhase 编译阶段的framework配置;

    • PBXProject 工程信息;

    • PBXNativeTarget 工程中所有target的信息;

    • XCConfigurationList 每个target下包含的编译模式,如Debug 、 Release等模式;

    • XCBuildConfiguration 具体的编译信息,如Release模式下的编译配置;

文件间的关系大致如下图所示:

在这里插入图片描述

每一项资源在这个文件中都有一个值作为唯一标识,如903C829A2075C24300EB9AD0。可以看做是id。

一般每个ID值后面都会有一个注释来进行说明这个ID对应的具体内容。如903C829C2075C24300EB9AD0 /* TLauncher */,表示这个ID是代表的是TLauncher这个target。

相同类型的资源是按段进行整理的。

每一段内容前用/* Begin xxx section */注释作为开始。用/* End xxx section */ 作为这一段内容的结束。

每一项内容中用isa = xxx 指示该资源所属于的类型。

其中,PBXFrameworksBuildPhasePBXResourcesBuildPhasePBXShellScriptBuildPhasePBXTargetDependencyPBXSourcesBuildPhase这几项内容都是对工程在编译阶段的配置。

对应于工程中如下配置内容:
在这里插入图片描述

下面是 objectsPBXNativeTarget section 的一个对象,感受一下格式:

/* Begin PBXNativeTarget section */00E356ED1AD99517003FC87E /* shq5785Tests */ = {isa = PBXNativeTarget;buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "mrcsTests" */;buildPhases = (E813BE00D49641555FA7986E /* [CP] Check Pods Manifest.lock */,00E356EA1AD99517003FC87E /* Sources */,00E356EB1AD99517003FC87E /* Frameworks */,00E356EC1AD99517003FC87E /* Resources */,);buildRules = ();dependencies = (00E356F51AD99517003FC87E /* PBXTargetDependency */,);name = shq5785Tests;productName = shq5785Tests;productReference = 00E356EE1AD99517003FC87E /* shq5785Tests.xctest */;productType = "com.apple.product-type.bundle.unit-test";};13B07F861A680F5B00A75B9A /* shq5785 */ = {isa = PBXNativeTarget;buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "shq5785" */;buildPhases = (C8F5F5993094D81A94013E0D /* [CP] Check Pods Manifest.lock */,FD10A7F022414F080027D42C /* Start Packager */,13B07F871A680F5B00A75B9A /* Sources */,13B07F8C1A680F5B00A75B9A /* Frameworks */,13B07F8E1A680F5B00A75B9A /* Resources */,00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,605CC81222DD68EB009545B7 /* Embed Frameworks */,3A54938F9F6AAF435223E489 /* [CP] Copy Pods Resources */,);buildRules = ();dependencies = ();name = mrcs;productName = mrcs;productReference = 13B07F961A680F5B00A75B9A /* shq5785.app */;productType = "com.apple.product-type.application";};2D02E47A1E0B4A5D006451C7 /* shq5785-tvOS */ = {isa = PBXNativeTarget;buildConfigurationList = 2D02E4BA1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "shq5785-tvOS" */;buildPhases = (A6B45AA48E3A2F14663044B6 /* [CP] Check Pods Manifest.lock */,FD10A7F122414F3F0027D42C /* Start Packager */,2D02E4771E0B4A5D006451C7 /* Sources */,2D02E4781E0B4A5D006451C7 /* Frameworks */,2D02E4791E0B4A5D006451C7 /* Resources */,2D02E4CB1E0B4B27006451C7 /* Bundle React Native Code And Images */,);buildRules = ();dependencies = ();name = "shq5785-tvOS";productName = "shq5785-tvOS";productReference = 2D02E47B1E0B4A5D006451C7 /* shq5785-tvOS.app */;productType = "com.apple.product-type.application";};2D02E48F1E0B4A5D006451C7 /* shq5785-tvOSTests */ = {isa = PBXNativeTarget;buildConfigurationList = 2D02E4BB1E0B4A5E006451C7 /* Build configuration list for PBXNativeTarget "shq5785-tvOSTests" */;buildPhases = (D14E060D8F1725B6C5A79756 /* [CP] Check Pods Manifest.lock */,2D02E48C1E0B4A5D006451C7 /* Sources */,2D02E48D1E0B4A5D006451C7 /* Frameworks */,2D02E48E1E0B4A5D006451C7 /* Resources */,);buildRules = ();dependencies = (2D02E4921E0B4A5D006451C7 /* PBXTargetDependency */,);name = "shq5785-tvOSTests";productName = "shq5785-tvOSTests";productReference = 2D02E4901E0B4A5D006451C7 /* shq5785-tvOSTests.xctest */;productType = "com.apple.product-type.bundle.unit-test";};
/* End PBXNativeTarget section */

可以根据 00E357021AD99517003FC87E 找到对应的 buildConfigurationList 对象的内容,所以说 project.pbxproj 使用 UUID 作为交叉引用的索引。通过这种关系,可以递归构建一张有向图,每个对象都是一个节点。

三、证书更换

当更换证书信息时,可按照如下步骤实施。

  1. 首先,通过字符串匹配/* Begin PBXProject section */,找到工程信息内容。

    在该段内容中,通过查找targets字段。找到该工程下的所有target。通过字符串与注释进行匹配,找到需要打包的target的ID值。

  2. 获取到目标target的ID值之后。通过注释,筛选出PBXNativeTarget内容段。

  3. PBXNativeTarget内容段中,找到targetID对应的内容。在这段内容中找到buildConfigurationList字段,获取到这个target下的编译配置列表对象ID。

  4. 此时,进入XCConfigurationList内容段。在该范围中,通过上一步中的编译配置列表对象ID,获取该target下的配置模式列表内容。

  5. 在配置列表中,找到需要使用的模式。拿到该模式对应的配置对象ID值。

  6. 进入XCBuildConfiguration编译配置段。通过上一步中的对象ID值,定位到该配置对象。

  7. 修改该配置对象中的内容。如可以通过修改PROVISIONING_PROFILE等字段的值实现更换证书。

四、探寻scheme 与 target

4.1 scheme

scheme不是编译target的必要条件,没有scheme不影响Xcode的编译操作,但是,没有scheme就没办法在编译时传入参数条件,插入编译脚本,配置个性化编译配置,所以schemeXcode编译时的必须选项。

打开一个scheme源文件,我们可以看到如下布局:

可以看到,最外层包含着buildtestlaunchprofileanalyzearchive。恰好对应了Xcode中的与之对应的命令,再次验证了Xcode就是pbxproj的可视化呈现。

在这里插入图片描述

进入BuildAction可以看到在Xcode中添加的预编译脚本和各种环境变量配置,这些配置有的是在编译过程中必不可少的参数,有的是方便开发者管理编译产物的必须配置,灵活运用这些配置,可以让Xcode更好的为开发者服务。

4.2 target

target用于指定要构建的产物,即framework或者apptarget只包含了当前project中的部分指定的代码和资源文件,每一个target只能构建出一个特定的构建产物,为了丰富构建产物,一个project可以拥有多个target

target使用Build SettingsBuild Phases的形式来进行个性化配置,默认这些配置可以通过project继承,也可以通过手动或者配置文件的方式覆盖其他配置。

target之间可以互相依赖,如果是在同个workspace下,Xcode默认会触发隐式依赖,当然,如果用手动配置依赖关系,则会变为显式依赖。显式依赖的优先级高于隐式依赖。

这篇关于ReactNative进阶(五十一)project.pbxproj 配置文件详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/541242

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

[MySQL表的增删改查-进阶]

🌈个人主页:努力学编程’ ⛅个人推荐: c语言从初阶到进阶 JavaEE详解 数据结构 ⚡学好数据结构,刷题刻不容缓:点击一起刷题 🌙心灵鸡汤:总有人要赢,为什么不能是我呢 💻💻💻数据库约束 🔭🔭🔭约束类型 not null: 指示某列不能存储 NULL 值unique: 保证某列的每行必须有唯一的值default: 规定没有给列赋值时的默认值.primary key:

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP

【Linux 从基础到进阶】Ansible自动化运维工具使用

Ansible自动化运维工具使用 Ansible 是一款开源的自动化运维工具,采用无代理架构(agentless),基于 SSH 连接进行管理,具有简单易用、灵活强大、可扩展性高等特点。它广泛用于服务器管理、应用部署、配置管理等任务。本文将介绍 Ansible 的安装、基本使用方法及一些实际运维场景中的应用,旨在帮助运维人员快速上手并熟练运用 Ansible。 1. Ansible的核心概念

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

从0到1,AI我来了- (7)AI应用-ComfyUI-II(进阶)

上篇comfyUI 入门 ,了解了TA是个啥,这篇,我们通过ComfyUI 及其相关Lora 模型,生成一些更惊艳的图片。这篇主要了解这些内容:         1、哪里获取模型?         2、实践如何画一个美女?         3、附录:               1)相关SD(稳定扩散模型的组成部分)               2)模型放置目录(重要)