前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >工程化(三)

工程化(三)

作者头像
拉维
发布2023-09-01 09:26:09
5540
发布2023-09-01 09:26:09
举报
文章被收录于专栏:iOS小生活iOS小生活

一、DumpHeaderMap的配置

DumpHeaderMap就是一个工具,其作用就是将.hmap文件中的内容解析展示出来。

DumpHeaderMap的Github地址为:

代码语言:javascript
复制
https://github.com/Cat1237/hmap

直接将工程资源下载下来,如下:

然后点开DumpHeaderMap文件夹,打开里面的Xcode工程,然后运行。

然后Product->Show Build Folder In Finder,找到DumpHeaderMap的二进制可执行文件:

然后将该可执行文件拷贝粘贴到指定目录:

我这里是将DumpHeaderMap的二进制可执行文件放到个人主目录的ThirdPartyLib文件夹的custom文件夹下。ThirdPartyLib文件夹里面放的都是自己写的或者其他人写的一些终端工具,其中自己写的工具放在custom文件夹中。

接下来想一下,如何让DumpHeaderMap这个工具在终端上生效呢?

当前终端环境(Shell环境),如果要使用某一个终端工具,那么就需要在PATH环境变量中去遍历里面配置到其中的路径,然后将该工具的名称配置到路径后面得到工具的完整目录,如果能找到该终端工具就可以使用了。

我们使用如下指令来查看一下当前终端环境的PATH:

代码语言:javascript
复制
echo $PATH

这些路径是通过冒号:来进行分割的。

我是将DumpHeaderMap这个工具放到/Users/lavie/ThirdPartyLib/custom路径下了,所以为了能够使用DumpHeaderMap这个工具,我就需要将/Users/lavie/ThirdPartyLib/custom这个路径配置到环境变量PATH中。

先来查看一下我当前使用的是什么终端:

可以看到,我当前使用的终端是ZSH。

所以我通过cat ~/.zshrc指令去查看.zshrc文件:

在该文件中我找到了配置文件.bash_profile,PATH就是在该文件中配置的,接下来通过vim ~/.bash_profile指令打开.bash_profile文件:

然后在其中添加如下代码:

代码语言:javascript
复制
export PATH="$HOME/ThirdPartyLib/custom:$PATH"

也就是说,通过冒号将原来的PATH与现在的$HOME/ThirdPartyLib/custom拼接到一起,生成新的PATH,如下:

保存后回到终端,使用which DumpHeaderMap指令查询DumpHeaderMap:

可以看到,能查询到DumpHeaderMap终端指令了,接下来就可以在终端使用DumpHeaderMap工具了。

关于DumpHeaderMap的使用,可以看上一篇文章。

二、通过Xcode内置工具往工程中引用源文件

在上一篇文章中,我们提到过,将.swift源码文件引用到工程中有三种方式:

  1. 打开Xcode,直接手动拖进来。
  2. 使用CocoaPods的内置终端工具xcodeproj,调用相关API,将源码文件添加进来。
  3. 主动调用Xcode内置工具,将源码文件添加进来。

以上三种方式,不管是哪一种,本质上都是在修改project.pbxproj文件,关于project.pbxproj文件,我在上一篇文章中有详细讲过。

在上一篇文章中,我也简单介绍了方案二。今天我们详细聊一聊方案三,如何通过手动调用Xcode的内置工具来完成源文件的引用。

实际上,方案一和方案三都是通过Xcode内置工具实现的,只不过方案一是Xcode在内部自动处理的,而方案三是需要我们手动调用该内置工具的API来实现

Xcode中是有很多功能的,这些功能都是通过一个一个的插件来实现的。

在应用程序中找到Xcode,显示包内容:

可以看到在Contents文件夹下面有PlugIns、SharedFrameworks、SystemFrameworks、SystemLibraries等文件夹,这些文件夹里面装的都是各种各样的工具。

PlugIns文件夹里面装载的都是Xcode插件,Xcode插件是bundle类型:

Xcode插件是Xcode预留的接口,它可以让开发者使用Xcode的内置功能。Xcode插件是放置在如下目录中的:

代码语言:javascript
复制
/Applications/Xcode-14.0.1.app/Contents/PlugIns

Xcode插件会在Xcode启动的时候加载。

从Xcode8开始,官方签名的Xcode是不能使用自定义的Xcode插件了,但是我们可以使用自签名的Xcode来加载插件。

再比如,SharedFrameworks里面就有各种各样的framework:

plugin也好,framework也好、library也好,它们都是Xcode内置的功能框架,我如果能够将这里的某些功能框架集中到我自己的工程中的话,那么就可以在我自己的工程中去调用对应功能框架提供的功能了。也就是说,Xcode的内置的所有功能,我们都可以去集成对应功能框架,然后通过代码的形式去进行功能调用。

但是现在有一个难点就是,这里有很多的功能框架,每一个功能框架分别可以提供什么样的功能,我现在不知道。

网上有人将Xcode内置工具的头文件给砸出来了,我把它传到了github上,大家可以自行下载,地址如下:

代码语言:javascript
复制
https://github.com/xuyuchenglan/Xcode-RuntimeHeaders-master

下载下来之后可以看到,文件夹内容是这样的:

通过文件的命名,我们大概就能猜到他是什么功能。

经过我不懈努力查找,我发现在Xcode内置插件中,DevToolsCore这个framework就是专门用于修改project.pbxproj工程文件的,查找过程如下:

首先在PlugIns文件夹下找到Xcode3Core.ideplugin

然后显示包内容,按如下路径就可以找到了:

然后我在砸出的文件夹里面找到DevToolsCore,就可以看到对应的头文件了,如下:

接下来我要做的事情就是将DevToolsCore.framework集成到我自己的项目中。

由于Xcode是MacOS上面使用的App,所以其内置framework也是给MacOS使用的,所以我首先创建一个MacOS的命令行工具工程,如下:

命名为NormanPB。

然后我将在Xcode安装目录下找到的DevToolsCore.framework文件夹拷贝粘贴到NormanPB工程目录下,如下:

然后将DevToolsCore.framework文件夹直接拖到Frameworks and Libraries这一栏:

然后运行,运行之后报错了:

报错信息是Library not loaded。这个错误是dyld动态连接器抛出来的,因为我们使用的DVTPortal.framework是一个动态的framework.

这个错误是说,dyld在通过路径'@rpath/DVTPortal.framework/Versions/A/DVTPortal'查找DVTPortal这个framework的时候,没有找到,此时dyld就会告知它加载不了这个动态库,也就是说会抛出【Library not loaded】这个错误。

如果想要dyld能够找到对应的动态库的话,最好的方式就是告诉dyld这个动态库的完整路径,也就是说,直接告诉dyld这个动态库的绝对路径。但是工程中使用到的这些framework是需要被放到ipa包中的,也就是说这些frameworkwork是需要被放到工程路径下的,这也就意味着我们没有办法获取动态库的绝对路径,因为该路径的前半部分是由IPA进行控制的,而这个IPA是装载到手机的哪个位置是不好控制的,而由IPA位置控制的这部分路径就是@rpath

@rpath是需要在工程中进行配置的,我直接到工程的Build settings中去搜索@rpath

可以看到,默认情况下@rpath是空的,这个时候通过路径'@rpath/DVTPortal.framework/Versions/A/DVTPortal'肯定是找不到对应的动态库的,所以我现在需要配置一下@rpath

首先来找到DVTPortal.framework存放的位置:

我在Xcode的工程路径下找到了DVTPortal.framework,其路径为:

代码语言:javascript
复制
/Applications/Xcode-14.0.1.app/Contents/SharedFrameworks/DVTPortal.framework

此时@rpath对应的路径是:/Applications/Xcode-14.0.1.app/Contents/SharedFrameworks

也就是说,我将工程配置中的@rpath配置为/Applications/Xcode-14.0.1.app/Contents/SharedFrameworks之后,应该就可以找到DVTPortal.framework这个动态库了。

这里我不直接在BuildSettings中进行直接配置,而是通过xcconfig文件的方式进行配置。

先创建一个xcconfig文件:

然后找到@rpath对应的key,并将其设置为/Applications/Xcode-14.0.1.app/Contents/SharedFrameworks:

然后将xcconfig配置到对应的Target:

然后再运行,发现找不到DVTPortal.framework的报错没有了,但是又报了个新的错误,说是找不到libclang.dylib

libclang.dylib是存在Xcode工程文件的如下目录:

我们还需要将这个路径配置到@rpath中,如下:

以此类推,缺少谁就将其对应的路径给加进来。

最后,就可以成功运行了。

有同学可能会有疑问,既然找到了对应的动态库了,那么为什么不直接把这个库拖进来呢?

原因就在于,DevToolsCore.framework这个库内部牵扯到了很多其他的库,这些库可能会很多,如果我直接将这些库一个一个拖进来的话就会拖进来非常多的库,而如果通过配置前面的路径的方式,就会方便很多,我将前面的路径配置好,这样这个路径下的所有的库就都可以找到了。

当我手动将一个framework拖进工程中的时候(比如上面将DevToolsCore.framework拖进来),Xcode帮我配置了两个路径:

(1)framework search paths

该路径指示去哪里搜索framework

这里的 $(PROJECT_DIR) 就是我们拖入的 DevToolsCore.framework 的存放路径。

(2)配置链接器的-framework参数,告诉链接器要链接的framework名称

我们运行一下工程,就可以在Build的link阶段查看到 -framework DevToolsCore,这其实就是告诉链接器需要链接名为DevToolsCore的framework。

既然我了解了当我手动将一个framework拖进工程中的时候Xcode帮我配置的路径参数,那么实际上我就不需要手动将DevToolsCore.framework拖进来了,而是直接配置对应的环境变量就可以了。

我先将项目中的从Xcode安装文件中拷贝过来的DevToolsCore.framework文件夹删除,并且从工程中将该引用也删除;

然后修改配置文件,如下:

我直接将 FRAMEWORK_SEARCH_PATHS 赋值为Xcode安装文件中的 DevToolsCore.framework文件夹所在的路径,这样我在工程中就是直接引用的Xcode里面的插件库了。

运行之后,工程运行成功,DevToolsCore.framework也被添加到了我的工程中。

现在我已经将 DevToolsCore.framework 成功导入到工程中了,接下来就是使用 DevToolsCore.framework 来引用代码源文件。

我们找到DevToolsCore.framework文件夹,翻遍该文件夹,也没有找到有效的相关API的头文件,如下:

而没有头文件的话,我就找不到对应的API进行调用了。所以我现在就需要站在巨人的肩膀上,将别人解析好的DevToolsCore头文件给直接放到工程目录下,如下:

然后我直接手动将DevToolsCore文件夹拖入到工程中:

然后我们就可以在工程中找到PBXProject这个类了

然后在main.m文件中引用PBXProject.h头文件:

运行之后发现报错了,报错信息如下:

我通过直接将DevToolsCore拖入工程的形式,DevToolsCore文件夹中的所有文件的相对路径都是相对当前的工程(即下面红框)的:

#import<>来引入头文件的方式,是直接根据文件目录来引入的。Xcode在 NormanPBOC.xcodeproj 这个路径下是找不到 DevToolsCore 文件夹的,所以会报错。

如果我采取直接将 DevToolsCore 文件夹拖入到工程中的方式,那么在通过import引用头文件的时候,就不能使用 #import<> ,而是采取 #import”” 。但是在DevToolsCore文件夹内部的各个文件中有很多 #import<> ,所以我就不能采取直接将 DevToolsCore 文件夹拖入到工程中的方式,而是采用配置 Header Search Paths 的方式。

接下来我就将拖入的DevToolsCore文件夹从工程里面删除其引用,然后找到Header Search Paths对应的环境变量:

然后在配置文件中配置环境变量 HEADER_SEARCH_PATHS 为 ${SRCROOT} ,当然也可以直接在build settings中进行配置:

${SRCROOT} 就是工程所在的目录,比如下图中的左侧的 NormanPBOC 文件夹的路径就是NormanPBOC 这个工程中的 SRCROOT。

配置好之后再运行,发现 #import "PBXProject.h" 的地方还是报错,这是因为我现在不是通过直接拖入的方式,而是通过配置 HEADER_SEARCH_PATHS 的方式将DevToolsCore引入进来的,所以 PBXProject.h 这个文件的相对路径不再是 NormanPBOC.xcodeproj 了,而是

代码语言:javascript
复制
#import "DevToolsCore/PBXProject.h"

再运行的话这里就不会报错了。

但是会有下面的一个报错:

这是因为我们使用的 DevToolsCore 是直接从Xcode的工程文件中拿过来的,而在Xcode工程中是可以直接使用Foundation的内容的,但是在我们自己的工程里面,如果需要使用Foundation还是需要导入的,所以我就将 #import <Foundation/Foundation.h> 全部替换为 #import <Foundation/Foundation.h> ,然后再运行,可能还是会有一些报错,这些报错应该就是一些API里面的定义的报错了,直接注释掉即可,最后就能成功运行了。

至此,所有的环境就都配置好了,我们就可以写代码了。我通过NormanPBOC.xcodeproj的文件路径拿到PBXProject的实例,然后运行,报了一个断言错误:

这里的报错是因为,我这里使用的API是XcodeIDE的API,而所有XcodeIDE的API在使用之前都需要初始化,所以我还需要对IDE 的API进行初始化:

这个时候会报一个编译器错误,IDEInitialize这个函数是在运行之后可以找到的,因此我就需要再编译预处理和链接两个阶段来“骗”编译器,让其不报错。

编译预处理阶段,我只需要在前面声明一个IDEInitialize函数即可:

这个时候我只要不编译,那么编译器就不会报错了。但是当我编译之后还是会报错,因为链接器在生成最后的可执行文件的时候,还是需要函数的具体声明的,报错如下:

因此我还要针对链接阶段进行处理:

-Xlinker是给链接器直接传递参数的意思,也就是说,-Xlinker后面接的参数是直接传递给链接器的,而不是通过clang转给链接器的。

-U是指定不要让链接器管其后面的符号,后面运行的时候自然有人会管。

上面红框中的参数传递的意思就是,告诉链接器,不要管_IDEInitialize这个符号,后面运行的时候会有人管的。

然后再次运行,运行成功了,并且弹出了一个弹框:

这说明它正在访问我的桌面文件夹。

接下来我就调用PBXProject的相关API将代码源文件引入到工程中。

先把代码源文件放入到工程目录下:

然后编写相关代码:

(1)PBXProject *project = [PBXProject projectWithFile:@"/Users/liwei/Desktop/NormanPBOC/NormanPBOC.xcodeproj”]; 这行代码的意思就是根据工程路径拿到对应的工程实例对象。

(2)[[project rootGroup] addFiles:@[@"/Users/liwei/Desktop/NormanPBOC/ViewController.h"] copy:NO createGroupsRecursively:NO]; 这行代码就是说,往工程的rootGroup下添加文件。

rootGroup指的就是project这一层级里面的第一个层级。

copy这个参数值跟我们直接拖文件的时候系统提醒的是否copy是同一个意思。

(3)[project writeToFileSystemProjectFile:YES userFile:NO checkNeedsRevert:NO];是说讲文件写入工程。

运行成功之后,就把对应源文件添加进来了:

至此,整个流程就讲完了。

通过这一整个流程的介绍,我们可以探知到,我们其实也是可以直接去使用Xcode里面的功能的

三、Ruby环境配置

1,Ruby VS Python

Python的解析器实现更成熟,第三方库的质量很高;Ruby的包管理更简单、方便,对移动开发者更友好。

Python在测试领域应用的比较多。在移动开发领域,Ruby的应用非常广泛,CocoaPods、Fasline等都是Ruby开发的,Ruby中有很多针对移动端的第三方库,比如分析修改macho的第三方库ruby-macho:

这里需要说明的一点是:在Ruby中引用第三方库是使用gem,这类似于在iOS中引用第三方库是使用pod,二者的对比如下:

上面这一行,是在iOS工程里面使用CocoaPods去引入三方库;下面这一行,是在Ruby中使用bundler去引入三方库。之所以要对比两者,是因为CocoaPods是使用Ruby开发的,它完全仿照了Ruby引入三方库的流程。

可以看到,在Ruby中导入三方库和在CocoaPods中导入三方库,其流程是一样的,只不过使用的工具名称不一样。

Ruby会在它的sources源里面找到Gem这个仓库,然后读取gemspec里面的三方库描述信息找到对应的三方库,使用bundle命令来安装更新三方库。实际上,CocoaPods就是Ruby的一个三方库。

CocoaPods会在它的sources源(比如CDN)里面找到Pod这个仓库,然后读取podspec里面的三方库描述信息找到对应的三方库,使用pod命令来安装更新三方库。

2,Ruby版本的管理

rvm、rbenv这两个都是命令行工具,可以让你轻松安装、管理和使用多个Ruby环境。如果你有必要在你的电脑上装多个Ruby环境,比如你需要维护多个指定版本的Ruby项目,那么就需要使用rvm或者rbenv来管理Ruby。

如果我不需要维护特定版本的Ruby项目,也就是说我就只需要装一个比较新版本的Ruby,那么此时使用brew来安装Ruby就可以了:

代码语言:javascript
复制
brew install ruby

安装好Ruby之后,我们可以使用 ruby -v 来查看当前的Ruby环境:

所有的脚本语言(Shell、Python、Ruby),都是基于路径的。比如我当前的Ruby环境是3.1.1p18,那么在我的电脑里就会有一个文件夹叫做Ruby3.1.1p18,我在当前Ruby环境下安装的所有的三方库都是放到Ruby3.1.1p18这个文件夹里面。

在配置三方IDE的时候,配置使用的的Ruby版本要与我安装Ruby三方库的Ruby版本保持一致。比如我在Ruby3.1.1p18里面通过gem命令安装了一些三方库,而我在VSCode中配置的Ruby版本是Ruby3.1.0,那么这个时候在VSCode中就不能使用我刚才通过gem命令安装的三方库了。

3,Ruby Gems镜像

所谓镜像,其实就是Sources源。默认的Ruby镜像是 https://rubygems.org/ ,所以为了保证速度以及稳定性,我将Ruby镜像切换成国内的:

代码语言:javascript
复制
gem sources --add https://mirrors.tuna.tsinghua.edu.cn/rubygems/ --remove https://rubygems.org/

这是添加国内清华镜像,并移除默认镜像。

然后我通过gem sources -l指令查看当前的Ruby镜像:

发现Ruby镜像已经切换成清华镜像了。

然后还需要使用如下指令来替换bundler的默认源:

代码语言:javascript
复制
bundle config mirror.https://rubygems.org https://mirrors.tuna.tsinghua.edu.cn/rubygems

4,VSCode中终端环境的配置

首先查看我当前终端上使用的Shell是哪一种:

可以看到,当前终端使用的是bin下面的zsh。

打开VSCode的设置页面:

然后搜索profile字段:

将终端环境设置为zsh。

5,Ruby插件的安装

(1)bundler

首先查看bundler是否已经安装了:

可以看到,bundler已经安装了。

(2)ruby-debug-ide

首先查看ruby-debug-ide 有没有安装:

可以看到,并没有安装ruby-debug-ide,所以需要安装:

ruby-debug-ide提供了交互环境。和IDE(例如RubyMine,Visual Studio Code 或Eclipse)之间建立通信的协议。ruby -debug-ide 将命令从IDE重定向到调试器,然后它将从调试器收到的答案/事件返回给IDE。

(3)debase

debase是针对Ruby 2.0的标准Ruby调试器debug.rb的快速实现。它是通过利用新的 Ruby TracePoint类实现的。核心组件提供了前端可以建立的支持。它提供断点处理, 堆栈信息等。

首先检查是否已安装:

已经安装了无需重复安装。

(4)rubocop

rubocop 是基于 ruby-style-guide / Ruby ⻛格指导实现的一个代码⻛格检查器。

(5)solargraph

solargraph是一种语言服务器,为Ruby提供智能感知,代码完成和内联文档。

(6)rake

6,VSCode中Ruby的配置

VSCode的本质是通过插件调用终端上的安装好的工具。比如我要在VSCode上面去使用Ruby,那么就需要在VSCode上面去安装对应的Ruby工具:

Ruby、Ruby Solargraph、Error Lens

在VSCode上调试运行的所有的项目,都是通过launch.json文件进行配置的,这个文件指明了你要对当前项目做什么操作,Ruby插件就是为了在打开Ruby项目的时候辅助我们生成launch.json文件的。

我们可以点击如下按钮来打开launch.json文件:

这里的name就是调试运行的时候执行的配置名称,显示在启动配置下拉菜单中;

type是配置类型;

request是请求配置类型,可以是启动或者附加;

program指的是所要执行的程序的绝对路径。

我们在终端中执行pod install的时候,这个pod本质上就是一个Ruby代码文件,也就是Ruby类型的program。

如上图所示,先通过which指令找到pod的路径,然后通过open指令打开文件夹,然后找到pod二进制可执行文件并将其拖到VSCode打开:

可以看到,pod本质上就是一个Ruby代码文件。我每次在执行pod指令,其实都是在调用这个Ruby代码文件,由这个文件去处理接收到的各个参数。

而这里的program配置的就是所要执行的Ruby文件的地址,一般而言,Ruby三方库中暴露出来的Ruby文件都是存放在bin目录下:

其路径就是我们上面已经配置好的"${workspaceRoot}/bin/xcodeproj"

上面我们也提到,Ruby工程三方库的管理与iOS工程中使用CocoaPods管理三方库的流程是一样的,只不过名称不一样而已。

比如Podfile对应的是Gemfile,podspec对应的就是gemspec,pod命令对应的就是bundle命令,等等。

Ruby工程也是依赖很多三方库的,因此我还需要执行bundle install命令将这些依赖的三方库给安装上:

当看到Bundle complete! 之后,说明已经安装完成了~~

接下来我们运行一下工程:

运行之后有可能会报如下错误:

这个错误其实是比较常见的一个错误,我们在使用CocoaPods来管理iOS工程三方库的时候也会经常遇到,它的意思是说,rake这个三方库在Gemfile中指定的版本(具体版本号可以在Gemfile.lock中查看)与当前终端中默认的rake版本是不匹配的

我们先使用gem info rake指令查看终端中默认的rake版本:

可以看到,终端中默认使用的rake版本是13.0.6。

而在Gemfile中指定的rake版本是:

这就与终端中默认使用的rake版本不匹配了,所以报错。

在Ruby里面,$打头的变量被称为是全局变量,它可以在程序的任何地方加以引用。全局变量无需变量声明,引用尚未初始化的全局变量的时候,其值为nil

由于Ruby这些脚本语言都是基于路径的,所以Ruby在寻找三方库的时候,是需要知道三方库的完整路径的。LOAD_PATH(或者只是:)是一个全局变量,它会告诉Ruby可以在哪里找到所需的依赖项,也就是说,Ruby会将LOAD_PATH中的路径与gem名称拼接到一起拿到gem的完整路径。如果一个依赖项不在Gemfile中,那么该依赖项的路径就不会存在LOAD_PATH中,那么Ruby就没有办法找到它。

执行”bundler/setup”时加载的文件,主要是调用了Bundler.setup函数。我们是使用bundler来管理Ruby中使用的三方库的,该设置首先会清理加载路径,然后仅激活Gemfile中定义的gem,也就是说,只会将Gemfile中定义的gem的路径添加到LOAD_PATH变量中,而没有使用到的gem的路径将会被从LOAD_PATH变量中移除。

【解决方案一】

在上面的报错信息中,有这么一条提示文案:

代码语言:javascript
复制
Prepending ‘bundle exec’ to your command may solve this.

在使用bundle exec 运行命令的时候,默认会将当前目录下Gemfile文件中指定的gem加载到Ruby程序中。也就是说,如果在一句gem指令前面加上bundle exec,那么该指令就会在当前目录下Gemfile中描述的Gem环境下执行。如果你安装了多个gem版本,那么就需要指定当前使用的gem版本,通过在命令前面加上bundle exec,就可以指定【使用Gemfile中描述的Gem版本运行!】

举个例子,我们在上面打开的Ruby工程路径下分别执行gem info rake和bundle exec gem info rake,结果输出如下:

可以看到,指令前面加了bundle exec之后,输出的就是Gemfile中指定的rake版本。

再举个例子,我们在上面打开的Ruby工程路径下分别执行 gem list和bundle exec gem list。通过输出结果我们可以看到,指令前面加了bundle exec之后,输出的就是Gemfile中能够适配到的特定版本的gem。

所以解决上面那个报错的方案之一就是,在bundle install前面加上bundle exec,把Podfile.lock文件删掉之后重新执行一下bundle exec bundle install指令即可。

【解决方案二】

修改系统终端环境中的相关gem的默认版本。

由于每个工程中使用的gem三方库的版本可以能是不一样的,所以直接修改对应gem的系统默认版本的话会对其他工程产生影响,所以该方案被pass。

【解决方案三】

将当前工程中使用的gem的版本调整成系统终端环境中默认的gem版本。

前面我们提到,VSCode的本质是通过插件调用终端上的安装好的工具。我在终端上安装了一个solargraph插件,solargraph是一种语言服务器,为Ruby提供智能感知,代码完成和内联文档。如果我想要在VSCode中使用solargraph的功能,那么就需要装Ruby Solargraph插件,这个VSCode插件我在前面也已经安装过了,但是我在运行工程的时候,鼠标定位到某个地方,IDE中并没有出现对应的导航弹框。这是因为我没有在VSCode中配置终端命令路径:

如上图所示,我需要在Command Path里面配置solargraph这个gem的路径,在终端使用which solargraph 命令获取到二进制可执行文件的路径,将它配置上去即可:

这样配置好之后再运行,鼠标所到之处就会出现引导说明弹框了,如下:

这样就可以点进去跳转查看对应的源码说明了。

四、CocoaPods调试

前面我们调试的是xcodeproj这个gem的工程源码,我将这一份源码传到了github,大家有需要的话可以自行下载:

代码语言:javascript
复制
https://github.com/xuyuchenglan/Xcodeproj

接下来我们再来调试一下cocoapods。我们知道,cocoapods也是一个使用Ruby写的gem,我这里有一份cocoapods的Ruby工程源码:

代码语言:javascript
复制
https://github.com/xuyuchenglan/CocoaPods

将这一份CocoaPods的源码下载下来之后,我们使用VSCode打开:

点击创建launch.json文件,模板有Ruby的话就选Ruby,没有Ruby的话就随便选一个模板:

然后修改name和program:

然后进入终端执行bundle install,报了一个这样的错误:

这个错误是说,Gemfile.lock中的bundler版本跟终端环境中运行的bundler版本不匹配。我将Gemfile.lock文件删除,然后重新bundle install,就可以解决该问题了。

还有可能会出现下面的问题:

要解决这个问题,就需要在终端执行brew install coreutils,然后再bundle install就可以了。

然后点击运行,就可以运行成功了。

我们知道,平常在开发过程中调用的pod,其本质就是一个Ruby脚本,终端中调用的这个pod是有其存储路径的,如下:

这个pod跟我现在调试的这个pod工程半毛钱关系都没有,因为我当前调试的pod工程的路径是"${workspaceRoot}/bin/pod”,如下:

那么我们平常调用的pod指令,在工程中是怎么调试的呢?

比如,pod install这个指令,在我们自己的这个调试工程中就可以像下面这样调试:

也就是说,pod命令后面的任何参数都是可以放到args这个参数数组中的

其实通过这个案例我也是想说明一点,pod本身也是一个Ruby工程,它后面跟的都是它的参数,如果pod这个Ruby工程使用VSCode打开的话,那么这个参数都是可以放到args这个参数数组中的

五、索引速度

当我打开一个新的工程的时候,首先会Loading,然后会indexing,如下:

Loading的时候其实就是在解析工程文件.xcodeproj。

indexing的时候其实就是根据project工程文件,来扫描其中的源码路径、分析代码关联,这样我才可以在工程中进行方法的跳转。这个扫描的过程就是索引过程,这个过程的速度就是索引速度,而索引速度的大小是跟对应工程中的文件数量有关的,文件量越小索引速度就会越快

Cocoapods推出了一个选项,该选项可以将我们引入的三方库的每一个target都生成一个对应的project文件,这样的话就不会所有的文件都集中在主工程的这一个Project中了,这样的话在打开工程的时候indexing就会快一些。

该选项实际上是Xcode对其内置的clang所做的定制化处理,该选项名称为:COMPILER_INDEX_STORE_ENABLE,如下图所示:

该选项是Xcode内置的clang提供的功能,而开源的clang是没有该选项的,因此当我们需要使用自定义clang的时候,需要将该配置项给关掉。

六、VSCode配置进阶

1,--conservativ

bundle update 会更新你所有的gems到最新的可用版本,如果我只想更新其中一个gem,那么可以使用--conservativ参数,如下:

代码语言:javascript
复制
bundle install --conservative rake

这里就是只更新rake这一个gem,这样就不需要频繁删除gemfile.lock文件了。

2,debuggerPort

使用VSCode调试Ruby程序的时候,每一个Ruby程序的调试都需要申请一个调试端口,其默认端口号是1234。如果你想要调试多个Ruby程序,那么就需要配置该选项,这样端口才不会起冲突。

3,cwd

cwd是program要执行的目录

4,useBundler

useBundler配置默认是false,表示调试使用的IDE是当前终端安装的IDE;如果启用该选项,那么就会使用指定的IDE版本,但是此时需要在gemfile中去引入所要使用的rubuDebugIDE的版本。

每个Ruby的版本跟它的调试编译器是配置在一起的,这就有可能导致终端安装的rdebug-ide的版本跟我们所需要的rdebug-ide版本不一致,此时useBundler选项就会发挥作用了。

5,env

这里面可以配置当前Ruby所要使用的环境变量。

如果我们当前的终端上装了很多个版本的Ruby环境, 这就有可能导致我此时VSCode中读取到的环境变量并不是我想要的Ruby环境,这个时候我就可以用过env将我想要的Ruby环境直接引入进来。

那么我需要在env中配置哪些内容呢?

首先我复制如下代码:

代码语言:javascript
复制
printf "\n\"env\": {\n \"PATH\": \"$PATH\",\n \"GEM_HOME\": \"$GEM_HOME\",\n \"GEM_PATH\": \"$GEM_PATH\",\n \"RUBY_VERSION\": \"$RUBY_VERSION\"\n}\n\n"

在终端中粘贴、回车,打印内容如下:

然后直接复制粘贴到launch.json中即可。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 iOS小生活 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档