目录
其中dstSubfolderSpec=10意思是Frameworks
知识点:@executable_path/Frameworks
错误分析
上面的原因就是说:这个库没有被加载,哪个库呢,@rpath/xxx.framework 这个库。
首先看这个路径下这个库是否存在。
@rpath
@rpath是在xcode中设置的RunpathSearchPaths,这里可以设置多个路径,会依次查找(和Windows下的PATH变量差不多了):
所以先看自己的xcode的工程中有没有设置rpath
如果设置,看看这个路径下有没有需要的动态库,比如上面图中设置的是rpath=executable_path/Frameworks,就看看打出的app中点查看包内容里的Frameworks目录中有没有xxx动态库。如果没有需要在BuildPhases中进行设置拷贝进去:
(dyld: Library not loaded这个要加载说明这个是动态库,是需要拷贝到包里的,所以看看build BuildPhases中有没有添加这个库)
知识点:动态库 vs 静态库。
动态库就是动态链接的,是不会生成到可执行文件里面的。
所以如果说可执行文件app的包内容里面,包含了一个framework的,那么他肯定是一个动态库了。
静态库是生成到了包内容里面的那个可执行文件里面去了。
解决方法
一:在xcode界面中进行设置
1.第一步 添加 xxx.framework:
2. 第二步:
二:使用py脚本进行设置
把需要设置的 xxx.framework 配置到某个配置文件中
<key>EmbedFrameworks</key>
<array>
<string>xxx</string>
</array>
在py文件中读取这个配置文件进行处理
。。。。。
elif current_config == 'EmbedFrameworks':
ref_files = []
for framwork_need_add in dic_channel_config[current_config]:
tFiles = proj.get_files_by_name(framwork_need_add + '.framework')
print 'Embed Frameworks:' + framwork_need_add + '.framework'
for f in tFiles:
ref_files.append(f)
proj.add_EmbeedFrames(ref_files,'10',('CodeSignOnCopy', 'RemoveHeadersOnCopy'))
proj.add_build_config('LD_RUNPATH_SEARCH_PATHS' , '$(inherited) @executable_path/Frameworks')
。。。。。
其中 add_EmbeedFrames 函数的实现:
def add_EmbeedFrames(self,refFiles,dstSubfolderSpec,attrs):
result = []
targets = self.get_build_phases('PBXNativeTarget') + self.get_build_phases('PBXAggregateTarget')
if len(targets) != 0 :
build_fileIds = []
for file_ref in refFiles:
build_file = PBXBuildFile.Create(file_ref)
build_file.set_attributes(attrs)
self.objects[build_file.id]=build_file
build_fileIds.append(build_file.id)
buildActionMask = '0'
buildPhases = [g for g in self.objects.values() if g.get('isa') == 'PBXCopyFilesBuildPhase']
for bp in buildPhases:
buildActionMask = bp['buildActionMask']
copy_Files_Build_Phase = PBXCopyFilesBuildPhase.Create("Embed Frameworks",build_fileIds,dstSubfolderSpec,buildActionMask)
for t in targets:
for buildPhase in t['buildPhases']:
if self.objects[buildPhase].get('isa') == 'PBXCopyFilesBuildPhase':
t['buildPhases'].add(copy_Files_Build_Phase.id)
self.objects[copy_Files_Build_Phase.id] = copy_Files_Build_Phase
result.append(copy_Files_Build_Phase)
return result
其中dstSubfolderSpec=10意思是Frameworks
Anyone had success with Copy Files build phases in Xcode 4 templates - Stack Overflow
# dstSubfolderSpec property value used in a PBXCopyFilesBuildPhase object.
'BUILT_PRODUCTS_DIR': 16, # Products Directory
: 1, # Wrapper
: 6, # Executables: 6
: 7, # Resources
: 15, # Java Resources
: 10, # Frameworks
: 11, # Shared Frameworks
: 12, # Shared Support
: 13, # PlugIns
Xcode工程文件project.pbxproj小结
Xcode工程文件project.pbxproj小结 - 简书
blog.csdn.net/bobbob32/article/details/84648848
https://github.com/kronenthaler/mod-pbxproj
ps:
将脚本加入到xcode工程中某个文件中
group的添加(xcode中文件夹的概念就是组的概念)
https://github.com/kronenthaler/mod-pbxproj/wiki
获取最上层的Frameworks,然后一层一层的往下加
frameworks=proj.get_or_create_group('Frameworks')
plugins=proj.get_or_create_group('Plugins',parent=frameworks)
ios=proj.get_or_create_group('IOS',parent=plugins)
aaaasdk_ios=proj.get_or_create_group('AAAASDK_iOS',parent=ios)
thirdpartyImport=proj.get_or_create_group('ThirdPartyImport',parent=aaaasdk_ios)
xxxxsdk=proj.get_or_create_group('XXXXSDK',parent=thirdpartyImport)
proj.add_file(current_project_path + '/Frameworks/Plugins/IOS/AAAASDK_iOS/ThirdPartyImport/XXXXSDK/' + framwork_need_add + '.framework', parent=xxxxsdk, tree='SOURCE_ROOT')
三:使用C#进行设置
如何在C#中设置xcode工程的设置
https://docs.unity3d.com/ScriptReference/iOS.Xcode.Extensions.PBXProjectExtensions.AddAppExtension.html
知识点:@executable_path/Frameworks
@executable_path 指的是可执行程序所在的路径 ,可执行程序就是可以运行的经过了编译链接以后生成的那个文件,直观的看的话windows下就是exe后缀的,linux下之前说过是.out或者没有后缀的。在动态库中基本上不使用这个path。
@loader_path 这个变量表示每一个被加载的 binary (包括App, dylib, framework,plugin等) 所在的目录。如果是应用程序的loader_path,则和@executable_path
一样,如果是Framework
或者plugin的
,则和Framework
或者plugin
相关。
比如对于一个插件,这个插件需要加载依赖其他的动态库-A库,当加载这个插件的时候,loader_path就变成了这个插件所在的位置,而动态库设置的installpath如果设置的是相对于@loader_path来说的,那么无论这个插件在哪里都没有关系。但是如果这个动态库设置的是相对于@executable_path的话,插件的位置就只能固定了。
install name:开发动态库时候设置的一个值,推荐中rpath来设置install name ——mac上可执行文件加载动态库是依照动态库的install name(是一个路径)来查找动态库,找到加载,找不到报错,因为rpath可以设置多个值灵活。具体是在程序链接的时候install name 会被拷贝到应用程序中,当程序运行过程中需要动态链接器去加载libfoo.dylib
的时候,动态链接器将会从应用程序中找到这个install Name,根据install name去查找这个库,找不到就报错。
使用Xcode开发动态库及Framework时,需要为其设置Install path。在设置Install path时,可能会使用到以下几个路径:
- 1)绝对路径: 绝对路径,通常用于设置固定目录下的Framework、动态库。
- 2)@executable_path:执行路径,通常用于设置直接在Application中加载的FrameWork、动态库。
- 3)@loader_path: 加载路径,通常用于设置需要在插件中加载的FrameWork、动态库。
- 4)@rpath: 运行路径,通常用于设置动态库的Install Name,需要同时在调用应用中设置好rpath。
设置成@rpath的好处:
比如 XPSSO.dylib 被两个 .app 使用, 且被包含的路径不同。比如:
softA.app/Contents/MacOS/dylib/XPSSO.dylib
softB.app/Contents/MacOS/Frameworks/XPSSO.dylib
将 XPSSO.dylib 的 INSTALL_PATH 设置成 @loader_path/../dylib 或 @loader_path/../Frameworks 都只能满足其中一个 .app 的需求. 要解决这个问题, 就可以用 @rpath. 将 XPSSO.dylib 的 INSTALL_PATH 设置成 @rpath, 然后在编译 softA.app, softB.app 时分别指定 @rpath 为 @loader_path/../dylib, @loader_path/../Frameworks, 问题得到了解决
命令行工具
otool
otool -L xxx:查看使用的动态库有哪些,依赖了哪些动态库
otool -D xxx:查看其install name
其他参数直接键入otool 回车查看
file
Framework是动态库还是静态库
file xxx
使用命令查看
如果是动态库就会遇到上面的错误,需要进行设置。如果是静态库就不需要了。