从脚本向Xcode项目添加文件?

58

目前我正在使用一些脚本来生成文件,并将它们作为资源包含在Xcode中。问题是我先运行脚本,然后将其从项目中删除,再将其添加回项目中。肯定有一种方法可以自动化这个最后一步,使得脚本可以生成文件并自动将它们添加到xcode项目中。

我正在使用bash,但任何语言的示例都会有所帮助。

谢谢, 安德鲁


4
@Andrew:你成功让这个工作了吗?我很好奇最终结果。 - e.James
我知道有点晚了,但我刚刚看到了这篇文章,它解释了如何做一些听起来像是你正在寻找的东西。文章链接:http://www.benzado.com/blog/post/352/file-references-relative-to-derived_file_dir-in-xcode - Richard
8个回答

43
我有一个和Andrew类似的需求。我需要能够在不提前知道这些资源的情况下,从脚本中包含资源。以下是我想出的解决方案:
在“复制包资源”之后添加一个新的Run Script构建阶段,其中包含以下命令:
find -L ${SRCROOT}/SomeDerivedResources \
    -type f -not -name ".*" \
    -not -name "`basename ${INFOPLIST_FILE}`" \
    | xargs -t -I {} \
    cp {} ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/

看起来有点吓人,但是让我们来分解一下:

find -L ${SRCROOT}/SomeDerivedResources

这个命令会遍历我们源代码根目录下的SomeDerivedResources目录(-L参数告诉它要跟随符号链接)。

-type f

仅包含常规文件

-not -name ".*"

忽略以点号开头的文件。
-not -name "`basename ${INFOPLIST_FILE}`"

在我的情况下,我的Info.plist存在于SomeDerivedResources目录中,因此我们需要将该文件从复制到产品中排除。
| xargs -t -I {}

使用-tfind的结果导入到xargs中(将生成的命令回显到stderr,以便在构建日志中显示),使用-I(对每个输入文件运行一次命令),并使用{}作为我们的参数占位符。
cp {} ${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/

最后,将找到的每个文件(由 {} 表示)复制到我们产品的资源目录中。
在键入此内容时,我意识到使用rsync设置而不是cp可以防止每次构建时复制资源。如果您的资源非常大,值得一试。
(另外,文件夹引用对于我的需求无法工作,有几个原因。首先,我的图标位于DerivedResources目录中,在捆绑包的子目录中似乎无法工作。此外,我理想情况下希望能够使用 [UIImage imageNamed:@“MyAwesomeHappyImage.png”] 和 -pathForResource:ofType:(我的某些文件更深地嵌套在我的DerivedResources目录中)。如果您的需求不包含这些限制,我强烈建议您选择文件夹引用路线。)

1
真是太棒了: "${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/" --- 这正是我需要的,而且在苹果文档中找不到。我不知道为什么Xcode4在添加输出文件部分时太懒,不能自动执行这个操作 :( :( - Adam
我正在使用这个脚本,它完美地工作!但是有一个问题...当我们使用这种方法修改.app文件时,似乎苹果不允许您在设备上安装该项目,因为它已被篡改。有什么建议吗? - kevinl
2
@kevinl 你是在Xcode的“运行脚本”构建阶段中运行脚本吗?代码签名发生在这些步骤之后,所以它应该可以正常运行。 - Ben Cochran
@BenCochran 噢,是的。那是问题的一部分。现在一切都正常了,谢谢。 - kevinl
感谢@BenCochran!对于那些在路径中遇到空格问题的人(如果项目/目标名称中有空格,例如“Example Project.app”),您可以尝试:ROOT =“$ {SRCROOT} / SomeDerivedResources” OUTPUT =“$ {CONFIGURATION_BUILD_DIR} / $ {UNLOCALIZED_RESOURCES_FOLDER_PATH} /”find-L“$ {ROOT}”-type f-not-name“.*”| xargs-t-I {} cp {}“$ {OUTPUT}” - Radu Dan
显示剩余4条评论

37

您可以通过为应用程序添加新的构建阶段来完成此操作。

  1. 在Xcode项目浏览器中找到应用程序的目标,并展开它以显示所有构建阶段。

  2. 向您的目标添加一个新的"运行脚本"构建阶段。最简单的方法是右键单击目标,然后选择“添加/新建构建阶段/新建运行脚本构建阶段”

  3. 添加新的构建阶段应该会弹出检查器窗口。在此窗口中,您可以输入整个shell脚本,或者只是要运行脚本的命令行。

  4. 重点在于:在检查器窗口底部,您可以指定输入文件和输出文件。指定输入文件会自动设置依赖项(只有在修改了某些输入文件时才会执行shell脚本)。指定输出文件会自动将依赖关系传播到这些文件。当运行您的shell脚本时,Xcode知道它需要处理那些由shell脚本修改的文件。

  5. 请务必将新的构建阶段拖到阶段列表的顶部,如下图所示。如果您需要将这些资源文件包含在捆绑包中,则顺序很重要。

  6. 保存、构建、提交到存储库,请求加薪,呼吸新鲜空气并度过愉快的一天! :)


7
谢谢!在我的情况下,我不知道输出文件是什么。我希望能够动态地将文件添加到项目中的某个子组中。这种做法可行吗?还是我对你的示例存在误解? - Andrew
2
安德鲁,你找到这个问题的解决方案了吗? - Alastair Stuart
2
还没有,添加脚本的东西非常有用,我现在已经做到了,但我仍然找不到一种自动将文件添加到项目中的方法。有什么想法吗? - Andrew
1
有没有一种方法可以动态地将.h和.m文件包含到Xcode项目中?或者除了Xcode之外,我还能在Xcode项目文件中添加.h或.m文件的其他方法吗? - DShah
6
这些链接已经失效。 - Pup
显示剩余3条评论

12

对于有大量文件的用户,为避免需要重新复制(或重新检查)每个文件,如@Ben Cochran建议的那样(感谢他提供的脚本),以下是使用rsync的方法:

输入图像描述


我遇到了一个问题,需要我的应用程序包含大量由单独的服务提供但每次发布都会更改的资源文件,这个解决方案完美地解决了我的问题。 - Kevin James Hunt
@KevinJamesHunt 我也有类似的需求,我有一组 JS 文件,作为文件夹添加到资源目录中。每次有更改时我都是手动复制和替换。相反,我想要自动化,比如说这些文件在服务器上的某个位置,然后是否有一种方法可以运行脚本,从服务器下载内容并将其复制到资源文件夹中。 - anoop4real

8
基本上,这些文件只需要复制到主要捆绑包中即可。
在这种情况下,只需向项目添加一个文件夹引用(在您的项目文件夹中创建一个文件夹,然后将其拖入您的项目的“资源”组中(在“文件和组”列表中),然后在出现的窗口中选择“为任何添加的文件夹创建文件夹引用”单选按钮),Xcode将在构建时复制文件夹及其所有内容到目标捆绑包中。
只是额外说明:如果使用此方法添加图像子文件夹,则必须使用子文件夹名称作为前缀来使用 `[UIImage imageNamed:]`。例如,如果您有一个名为“Rendezvous.png”的图像,位于名为“MyImages”的子文件夹中:
// this won't work
UIImage * image = [UIImage imageNamed:@"Rendezvous"];
if (image) {
    NSLog(@"Found Rendezvous!");
} else {
    NSLog(@"Didn't find Rendezvous.");
}

// but this will!
image = [UIImage imageNamed:@"MyImages/Rendezvous"];
if (image) {
    NSLog(@"Found MyImages/Rendezvous!");
} else {
    NSLog(@"Didn't find MyImages/Rendezvous.");
}

`


这个方案完全可行,而且更加简单 :) 它唯一改变的是你不能使用像 [UIImage imageNamed:] 这样的函数,因为文件保留在包中的文件夹中。但仍然是一个很好的解决方案。 - Andrew
1
实际上,您仍然可以使用"[UIImage imageNamed:]";您只需要在图像名称中包含子文件夹名称。例如:'[UIImage imageNamed:@"MyImagesFolder/MyImageName"];'。 - geowar
如果您想添加一些代码类(例如.swift),则文件夹解决方案完美运作。顺便说一句,现在当“添加新文件”屏幕出现时,您需要按选项来选择是否使用文件夹或组。 - Zaporozhchenko Oleksandr

5
如果您已经在系统中的某个地方拥有文件,相对于您的源根目录,您可以随时添加“复制文件”阶段。这将允许您指定应从其中复制资源的目录。
您可以将此与先前提供给您的Build Script阶段答案相结合。例如,运行脚本从Subversion检出资产到项目的子目录中,然后跟随一个复制文件阶段,从“$(SRCROOT)/Assets”复制。

很棒的想法。结合上面的例子,正好满足了我当时的需求,下一次更新我的应用程序时我一定会这样做。 - Andrew
@Andrew,能否请你解释一下在XCode 4上如何实现这个功能?非常感谢! - Mihai Fratu
您只能指定目标文件夹,而不能指定源文件夹。 - akc

2

我知道有点晚了,但我刚刚看到了这篇文章,它解释了如何做一些类似于你正在寻找的东西。


0

我成功解决了这个问题:

"Code object is not signed at all"

这个问题在上传到iTunes Connect时可能会遇到。解决方法如下:

我没有将脚本包含在Bundle资源中。

因此,脚本(在这种情况下是Python文件)在构建过程中被执行(它执行它该执行的操作),但未包含在应用程序的bundle中。

如何解决?

打开Build Phases,进入Copy Bundle Resources部分,选择该文件并使用减号(-)删除它。


0
我在使用Ionic Capacitor时遇到了类似的情况。我原本期望的是在“复制捆绑资源”捆绑阶段中包含文件。但我发现Ionic已经打包了一些文件,如果你将你的文件放在这些文件夹中,它也会被包含进去。

enter image description here

你看到App文件夹的包含了吗?这是我们的入口点。
为了将其包含在内,我添加了一个脚本,类似于以下内容:
cp -Rf ./includes/yourfolder/ ./ios/App/App/

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接