原文: http://blog.sina.com.cn/s/blog_4a628f030101b411.html
自用筆記,口胡莫怪
最近鼓搗用Unity開發IOS app,對每次生成Project都要在Xcode下手動添加Framework文件甚煩,查了下,可以用Postprocessbuildplayer解決
Postprocessbuildplayer(無後綴名),放在工程文件下Assets/Editor下,Unity在編譯最後會自動執行這個腳本文件
以下以ARToolKit所需添加的Framework文件為例:(參看這裡)
——————————————————————————————————————————————
#!/usr/bin/python
import sys
import os
# Constants
FRAMEWORK_NAME = 0
FRAMEWORK_ID = 1
FRAMEWORK_FILEREFID = 2
RESFILE_NAME = 0
RESFILE_ID = 1
RESFILE_FILEREFID = 2
RESFILE_LASTKNOWNTYPE = 3
# These ids have been generated by creating a project using Xcode then
# extracting the values from the generated project.pbxproj. The format of this
# file is not documented by Apple so the correct algorithm for generating these
# ids is unknown
ACCELERATE_ID = '4A24A46A17244C9F00953BF8'
ACCELERATE_FILEREFID = '4A24A46917244C9F00953BF8'
AUDIOTOOLBOX_ID = '567B626A114A9F340000AA1F'
AUDIOTOOLBOX_FILEREFID = '8358D1B70ED1CC3700E3A684'
AVFOUNDATION_ID = '7F36C11313C5C673007FBDD9'
AVFOUNDATION_FILEREFID = '7F36C11013C5C673007FBDD9'
COREGRAPHICS_ID = '56B7959B1442E0F20026B3DD'
COREGRAPHICS_FILEREFID = '56B7959A1442E0F20026B3DD'
COREMEDIA_ID = '7F36C11113C5C673007FBDD9'
COREMEDIA_FILEREFID = '7F36C10E13C5C673007FBDD9'
COREVIDEO_ID = '7F36C11213C5C673007FBDD9'
COREVIDEO_FILEREFID = '7F36C10F13C5C673007FBDD9'
OPENGLES_ID = '567B6265114A9F340000AA1F'
OPENGLES_FILEREFID = '83B256E10E62FEA000468741'
QUARTZCORE_ID = '567B6266114A9F340000AA1F'
QUARTZCORE_FILEREFID = '83B2570A0E62FF8A00468741'
# List of all the frameworks to be added to the project
frameworks = [["Accelerate.framework", ACCELERATE_ID, ACCELERATE_FILEREFID], \
["AudioToolbox.framework", AUDIOTOOLBOX_ID, AUDIOTOOLBOX_FILEREFID], \
["AVFoundation.framework", AVFOUNDATION_ID, AVFOUNDATION_FILEREFID], \
["CoreGraphics.framework", COREGRAPHICS_ID,COREGRAPHICS_FILEREFID], \
["CoreMedia.framework", COREMEDIA_ID, COREMEDIA_FILEREFID], \
["CoreVideo.framework", COREVIDEO_ID, COREVIDEO_FILEREFID], \
["OpenGLES.framework", OPENGLES_ID, OPENGLES_FILEREFID], \
["QuartzCore.framework", QUARTZCORE_ID, QUARTZCORE_FILEREFID]]
# List of data files to be added to the app bundle
resfiles = []
# Adds a line into the PBXBuildFile section
def add_build_file(pbxproj, id, name, fileref):
subsection = 'Resources'
if name[-9:] == 'framework':
subsection = 'Frameworks'
print "Adding build file " + name + '\n'
pbxproj.write('\t\t' + id + ' = {isa = PBXBuildFile; fileRef = ' + fileref + ' ; };\n')
#Adds a line to the PBXFileReference to add a resource file
def add_res_file_reference(pbxproj, id, name, last_known_file_type):
print "Adding data file reference " + name + "\n"
pbxproj.write('\t\t' + id + ' = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = ' + last_known_file_type + '; name = ' + name + '; path = Data/Raw/' + name + '; sourceTree = SOURCE_ROOT; };\n')
# Adds a line into the PBXFileReference section to add a framework
def add_framework_file_reference(pbxproj, id, name):
print "Adding framework file reference " + name + '\n'
pbxproj.write('\t\t' + id + ' = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ' + name + '; path = System/Library/Frameworks/' + name + '; sourceTree = SDKROOT; };\n')
# Adds a line into the PBXFrameworksBuildPhase section
def add_frameworks_build_phase(pbxproj, id, name):
print "Adding build phase " + name + '\n'
pbxproj.write('\t\t\t\t' + id + ' ,\n')
# Adds a line into the PBXResourcesBuildPhase section
def add_resources_build_phase(pbxproj, id, name):
print "Adding build phase " + name + '\n'
pbxproj.write('\t\t\t\t' + id + ' ,\n')
# Adds a line into the PBXGroup section
def add_group(pbxproj, id, name):
print "Add group " + name + '\n'
pbxproj.write('\t\t\t\t' + id + ' ,\n')
# Returns a list of all the files already in a pbxproj
# lines - a list of all the lines read in from a pbxproj
def read_existing_files(lines):
begin_pbxbuildfile_section = False
existing_files = []
i = 0
line = lines[i]
while line[3:6] != 'End':
if not begin_pbxbuildfile_section:
begin_pbxbuildfile_section = (line[3:21] == 'Begin PBXBuildFile')
else:
existing_files.append(line.split()[2])
i = i + 1
line = lines[i]
return existing_files
# Processes the given xcode project to add or change the supplied parameters
# xcodeproj_filename - filename of the Xcode project to change
# frameworks - list of Apple standard frameworks to add to the project
# resfiles - list resource files added to the project
def process_pbxproj(xcodeproj_filename, frameworks, resfiles):
# Open up the file generated by Unity and read into memory as
# a list of lines for processing
pbxproj_filename = xcodeproj_filename + '/project.pbxproj'
pbxproj = open(pbxproj_filename, 'r')
lines = pbxproj.readlines()
pbxproj.close()
# Work out which of the resfiles exist and remove them if they don't, this
# is because if using frame markers there may not be a qcar-resources.dat
resfiles = [x for x in resfiles if os.path.exists(xcodeproj_filename + '/../Data/Raw/' + x[RESFILE_NAME])]
# Next open up an empty project.pbxproj for writing and iterate over the old
# file copying the original file and inserting anything extra we need
pbxproj = open(pbxproj_filename, 'w')
# As we iterate through the list we'll record which section of the
# project.pbxproj we are currently in
section = ''
# We use these booleans to decide whether we have already added the list of
# build files to the link line. This is needed because there could be multiple
# build targets and they are not named in the project.pbxproj
frameworks_build_added = False
res_build_added = False
# Build a list of the files already added to the project. Then use it to
# avoid adding anything to the project twice
existing_files = read_existing_files(lines)
filtered_frameworks = []
for framework in frameworks:
if framework[0] not in existing_files:
filtered_frameworks.append(framework)
frameworks = filtered_frameworks
for resfile in resfiles:
if resfile[0] in existing_files:
resfiles.remove(resfile)
# Now iterate through the project adding any new lines where needed
i = 0
for i in range(0, len(lines)):
line = lines[i]
pbxproj.write(line)
# Each section starts with a comment such as
# '
if line[3:8] == 'Begin':
section = line.split(' ')[2]
if section == 'PBXBuildFile':
for framework in frameworks:
add_build_file(pbxproj, framework[FRAMEWORK_ID], framework[FRAMEWORK_NAME], framework[FRAMEWORK_FILEREFID])
for resfile in resfiles:
add_build_file(pbxproj, resfile[RESFILE_ID], resfile[RESFILE_NAME], resfile[RESFILE_FILEREFID])
if section == 'PBXFileReference':
for framework in frameworks:
add_framework_file_reference(pbxproj, framework[FRAMEWORK_FILEREFID], framework[FRAMEWORK_NAME])
for resfile in resfiles:
add_res_file_reference(pbxproj, resfile[RESFILE_FILEREFID], resfile[RESFILE_NAME], resfile[RESFILE_LASTKNOWNTYPE])
if line[3:6] == 'End':
section = ''
if section == 'PBXFrameworksBuildPhase':
if line.strip()[0:5] == 'files':
if not frameworks_build_added:
for framework in frameworks:
add_frameworks_build_phase(pbxproj, framework[FRAMEWORK_ID], framework[FRAMEWORK_NAME])
frameworks_build_added = True
# The PBXResourcesBuildPhase section is what appears in XCode as 'Link
# Binary With Libraries'. As with the frameworks we make the assumption the
# first target is always 'Unity-iPhone' as the name of the target itself is
# not listed in project.pbxproj
if section == 'PBXResourcesBuildPhase':
if line.strip()[0:5] == 'files':
if not res_build_added:
for resfile in resfiles:
add_resources_build_phase(pbxproj,resfile[RESFILE_ID], resfile[RESFILE_NAME])
res_build_added = True
# The PBXGroup is the section that appears in XCode as 'Copy Bundle Resources'.
if section == 'PBXGroup':
if (line.strip()[0:8] == 'children') and (lines[i-2].strip().split(' ')[2] == 'CustomTemplate'):
for resfile in resfiles:
add_group(pbxproj, resfile[RESFILE_FILEREFID], resfile[RESFILE_NAME])
for framework in frameworks:
add_group(pbxproj, framework[FRAMEWORK_FILEREFID], framework[FRAMEWORK_NAME])
pbxproj.close()
# Script start
print "Starting PostProcessBuildPlayer with the following arguments..."
i = 0
for args in sys.argv:
print str(i) +': ' + args
i += 1
# Check this is an iOS build before running
if sys.argv[2] == "iPhone":
xcodeproj_full_path_name = sys.argv[1] + '/Unity-iPhone.xcodeproj'
process_pbxproj(xcodeproj_full_path_name, frameworks, resfiles)
—————————————————————————————————————————————
說明:文件的ID和FILEREFID需要用Xcode先正確生成一次工程,之後找到工程文件夾下的 Unity-iPhone.xcodeproj,右鍵 Show Package Contents ,用 TextEdit 打開其下的 project.pbxproj ,尋找要添加的文件名即可
上面的程序就是通過腳本直接生成 project.pbxproj 以達成直接添加所需文件和庫的目的
蛇足提示:ID和FILEREFID長得像但其實不一樣。。。某人二逼兮兮一晚上都運行不對就是因為眼瞎了。。。
以上