转:Postprocessbuildplayer自動連接Framework文件

原文:  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長得像但其實不一樣。。。某人二逼兮兮一晚上都運行不對就是因為眼瞎了。。。

以上

posted @ 2013-08-21 09:04  火之梦魇  阅读(901)  评论(0编辑  收藏  举报