使用python的mod_pbxproj 自动化 修改Xcode 工程

81 篇文章 1 订阅
8 篇文章 0 订阅

目前就先贴代码,等我这边项目做完,然后详细的写一篇这个方面的技术博客
建议结合这一篇博客来看工程文件project.pbxproj小结

# coding=utf-8
from mod_pbxproj import XcodeProject
import os
from foundation import *

from mod_pbxproj import *
import plistlib


from pbxproj.pbxextensions import FileOptions

# 修改工程
def changXcodeProject():
    print("开始修改工程配置")
    # load
    projectPath = '/Users/systudiosy/Desktop/TestModFy/TestModFy.xcodeproj/project.pbxproj'
# 打开项目
    project = XcodeProject.load(projectPath)
#添加framework搜寻目录
    project.add_framework_search_paths(paths="/Users/systudiosy/Desktop/frameworks")
#     添加libraey搜寻目录
    project.add_library_search_paths(paths="/Users/systudiosy/Desktop/frameworks")
#     添加头文件
    project.add_header_search_paths("/Users/systudiosy/Desktop/frameworks")
#     添加文件夹
    project.add_folder("My")
#     项目添加文件
#     project.add_file("/Users/systudiosy/Desktop/frameworks/SySDKLib.framework",force=False)
    project.remove_framework_search_paths("/Users/systudiosy/Desktop/frameworks/SySDKLib.framework")
    project.remove_library_search_paths(paths="/Users/systudiosy/Desktop/frameworks")
#     添加other link flag
    project.add_other_ldflags('-ObjC')
    project.add_other_ldflags('-all_load')
#移除链接标识
    # project.remove_other_ldflags('-all_load')

#     备份
    backname =  project.backup()
    print(backname)
    # save
    project.save(projectPath)

    # project.get_or_create_group(projectPath,parent=)

# 修改plist 文件
def changPlist():
    workPath = "/Users/systudiosy/Desktop/frameworks/"
    # os.chdir(workPath)
    print("work:" +os.getcwd())
    plistPath = os.path.join(workPath,"Info.plist")
    # plistPath = "Info.plist"

    if os.path.isfile(plistPath):
        print("路径存在")
        print(plistPath)
    # try:
    #     plist = plistlib.load(plistPath)
    # except  (Exception ):
    #     print("Something bad happened:")
    with open(plistPath, 'rb') as fp:
        plist = plistlib.load(fp,fmt=None,use_builtin_types=True,dict_type=dict)
        plist['NSMotionUsageDescription'] = "使用传感器"
        plist['HelloMM'] = "hehhehehhehehehheheheeh"
        print(plist)
        print(type(plist))

    with open(plistPath,'wb') as fp:
        # sort_keys 是否排序
        plistlib.dump(value=plist,fp=fp, fmt=plistlib.FMT_XML, sort_keys=True, skipkeys=False)
    print(plist)
    # 加载/打开

    # ---------------------------------------------

    # 更新plist

    # ---------------------------------------------
    # plistlib.dump(plist,plistPath)



    # plist['CFBundleDevelopmentRegion'] = 'chinese'
    # plist.writeToFile_atomically_(path, 1)




# 开始打包
def callXcodeArchive():
    # profile = PROVISION_CER[bundleIdIndex][1]
    # sign = PROVISION_CER[bundleIdIndex][2]
    #
    # cmd = "xcodeBuild clean build -project " + appName + "Build/Unity-iPhone.xcodeproj" + " PROVISIONING_PROFILE=\"" + profile + "\" CODE_SIGN_IDENTITY=\"" + sign + "\" " + "ENABLE_BITCODE=NO"
    #
    # if buildMode == "debug" or buildMode == "release":
    #     cmd = cmd + " -configuration Debug"
    # else:
    #     cmd = cmd + " -configuration Release"
    #
    # print
    # cmd
    #
    # if os.system(cmd) != 0:
    #     exit(10)
    #
    # os.chdir(path)
    pass




def testAddFile():
    projectPath = "/Users/systudiosy/Desktop/TestModFy/TestModFy.xcodeproj/project.pbxproj"
    project = XcodeProject.load(projectPath)
    file_options = FileOptions(weak=True)
    filePath = "/Users/systudiosy/Desktop/EZW_SDKs/EZW_pay_sdk/EzwSDK.framework"
    target_name = "TestModFy"
    project.add_file(path=filePath,parent=None,tree=None,target_name=target_name,force=False,file_options=file_options)
    project.remove_files_by_path(filePath)
    project.backup()
    project.save(projectPath)

if __name__ == '__main__':
    # testAddFile()
    # changXcodeProject()
    changPlist()
    # open project
    projectPath = '/Users/systudiosy/Desktop/TestModFy/TestModFy.xcodeproj/project.pbxproj'
    absProjectPath = os.path.abspath(projectPath)
    #
    project = XcodeProject.load(absProjectPath)
    #
    project.add_file("/Users/systudiosy/Desktop/Quick1/1.png")
    #
    new_group = project.get_or_create_group('myGroup')
    #
    project.add_file("/Users/systudiosy/Desktop/Quick1/1.png",parent=new_group)
    #
    project.add_file("/Users/systudiosy/Desktop/frameworks/SySDKLib.framework",tree="SDKROOT")
#
    project.add_file('usr/lib/libz.dylib', tree='SDKROOT')


    project.backup()
    # project.add_framework_search_paths("",recursive=False)
    # project.save("/Users/systudiosy/Desktop/frameworks")  # IMPORTANT, DONT USE THE OLD VERSION!







关于mod_pbxproj文档

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Author: fasthro
# @Date:   2016-11-15 11:21:33
# @Last Modified by:   fasthro
# @Last Modified time: 2016-11-15 11:21:57
import shutil
import os
import json
import re
import platform
# from mod_pbxproj.mod_pbxproj import XcodeProject
from pbxproj import *
import plistlib
import shutil
# 修改工程
from pbxproj.pbxextensions import FileOptions, TreeType

_channel = "TT"
_bundleId = "com.ebo.ball"
_version = "1.0.0"


# # 设置编码
# import sys
#
# reload(sys)
# sys.setdefaultencoding("utf-8")


# 解析
class ParseChannelParam:
    def __init__(self, jp):
        self.json_data = None
        self.json_file_data = None
        self.json_resource_data = None
        self.json_base_framework_data = None
        self.json_other_framework_data = None
        self.bundle_id = None
        self.version = None

        # 文件列表
        self.file_list = []
        # xcode 文件目录
        self.file_path_list = []
        # 文件类型
        self.file_type_list = []
        # xcode 文件列表
        self.xcode_file_list = []

        # 文件夹列表
        self.folder_list = []
        # xcode 文件夹目录
        self.folder_path_list = []
        # 目录类型
        self.folder_type_list = []
        # xcode 文件夹列表
        self.xcode_folder_list = []

        # framework
        self.base_frameworks = []
        self.base_weak_frameworks = []

        self.other_frameworks = []
        self.other_weak_frameworks = []

        # 解析
        self.parse(jp)

        # 写入文件列表
        self.writfilelist()

        # 写入文件夹列表
        self.writfolderlist()

        # 写入other
        self.writeother()

    def parse(self, jp):
        try:
            print(jp)
            with open(jp) as jf:
                self.json_data = json.load(jf)
                print(self.json_data)
                self.json_file_data = self.json_data["file"]
                self.json_resource_data = self.json_data["resource"]
                self.json_base_framework_data = self.json_data["base_framework"]
                self.json_other_framework_data = self.json_data["other_framework"]

        except:
            print("parse json error")

            pass

    def writfilelist(self):
        if self.json_file_data is not None:
            l = len(self.json_file_data)
            if l > 0:
                for index in range(0, l):
                    self.file_list.append(self.json_file_data[index]["file_name"])
                    self.file_path_list.append(self.json_file_data[index]["file_path"])
                    self.file_type_list.append(self.json_file_data[index]["type"])

        for index in range(len(self.file_path_list)):
            if self.file_type_list[index] == 'copy':
                self.xcode_file_list.append(os.path.join(self.file_path_list[index], self.file_list[index]))

    def writfolderlist(self):
        if self.json_resource_data is not None:
            l = len(self.json_resource_data)
            if l > 0:
                for index in range(0, l):
                    self.folder_list.append(self.json_resource_data[index]["dir_name"])
                    self.folder_path_list.append(self.json_resource_data[index]["dir_path"])
                    self.folder_type_list.append(self.json_resource_data[index]["type"])

        for index in range(len(self.folder_path_list)):
            if self.folder_type_list[index] == 'copy':
                self.xcode_folder_list.append(os.path.join(self.folder_path_list[index], self.folder_list[index]))

    def writeother(self):
        print(self.json_data)
        self.bundle_id = self.json_data["bundleId"]
        self.version = self.json_data["version"]

        if self.json_base_framework_data is not None:
            for index in range(len(self.json_base_framework_data)):
                self.base_frameworks.append(self.json_base_framework_data[index]["path"])
                self.base_weak_frameworks.append(self.json_base_framework_data[index]["weak"])

        if self.json_other_framework_data is not None:
            for index in range(len(self.json_other_framework_data)):
                self.other_frameworks.append(self.json_other_framework_data[index]["path"])
                self.other_weak_frameworks.append(self.json_other_framework_data[index]["weak"])

    def __str__(self):
        return "ParseChannelParam :\nbundle_id = %s version = %s \nxcode_file_list = %s \nxcode_folder_list = %s\n\n" % (
        self.bundle_id, self.version, str(self.xcode_file_list), str(self.xcode_folder_list))


# 打包之前准备工作
class PreparatoryWork:
    def __init__(self, frompath, topath, filefromls, filetols, folderfromls, foldertols):


        # from 根目录
        # /Users/systudiosy/Desktop/TestAllChannls/TT
        self.from_path = frompath
        # /Users/systudiosy/Desktop/TestTargetsFoMy/
        # to 根目录
        self.to_path = topath

        # 需要 copy 的文件
        self.file_from_path_list = filefromls
        self.file_to_path_list = filetols

        # 需要 copy 的目录
        self.folder_from_list = folderfromls
        print("folder_from_list:===>")
        print(folderfromls)
        print("\n")
        self.folder_to_path_list = foldertols
        print("foldertols:===>")
        print(foldertols)
        print("\n")

        # copy
        self.copy(filefromls, filetols)
        self.copy(folderfromls, foldertols)

    def copy(self, fs, ts):

        for index in range(len(fs)):
            frompath = os.path.join(self.from_path, fs[index])
            topath_temp = os.path.join(self.to_path, ts[index])
            topath = os.path.join(topath_temp, fs[index])

            # 如果已经存在就删除
            if os.path.exists(topath):
                if os.path.isdir(topath):
                    shutil.rmtree(topath)
                else:
                    os.remove(topath)

            if os.path.isfile(frompath):
                print("copy %s -> %s" % (frompath, topath))
                shutil.copy(frompath, topath)
            else:
                print("copy %s -> %s" % (frompath, topath))
                shutil.copytree(frompath, topath)


# Xcode *.pbxproj 相关设置
class Xcode:
    """
    ·xpath : xcode 根目录
    ·folders : 需要添加的文件夹列表
    ·files : 需要添加的文件列表
    """

    def __init__(self, xpath=None, folders=[], files=[]):

        # xcode project path
        self.xcode_project_path = xpath

        # xcode pbxproj path
        if platform.system() == "Windows":
            self.xcode_pbxproj_path = os.path.join(xpath, 'TestTargetsFoMy-TT.xcodeproj/project.pbxproj.xml')
        else:
            self.xcode_pbxproj_path = os.path.join(xpath, 'TestTargetsFoMy-TT.xcodeproj/project.pbxproj')
        print("XcodeProjectPath=%s"%(self.xcode_pbxproj_path))
        # need add folders
        self.folders = folders

        # need add files
        self.files = files

        self.project = None

        if self.xcode_pbxproj_path is not None:
            pstr_xml = self.xcode_pbxproj_path[len(self.xcode_pbxproj_path) - 4: len(self.xcode_pbxproj_path)]
            pstr_proj = self.xcode_pbxproj_path[len(self.xcode_pbxproj_path) - 8: len(self.xcode_pbxproj_path)]
            if pstr_xml == '.xml':
                self.project = XcodeProject.LoadFromXML(self.xcode_pbxproj_path)
            elif pstr_proj == '.pbxproj':
                self.project = XcodeProject.load(self.xcode_pbxproj_path)
            else:
                print("xcode load error path = [%s]" % self.xcode_pbxproj_path)

        if self.project is None:
            print("Xcode load error")
        else:
            pass

        # temp file list
        self.temp_files = None
        self.temp_folder = None

    def addfileToXcode(self):
        self.addfiles(self.files)

    def addfolderToXcode(self):
        self.addfolders(self.folders)

    # 导入文件设置 -fno-objc-arc
    def set_file_seting(self, f_path, flag):
        if self.project:
            f_id = self.project.get_file_id_by_path(f_path)
            files = self.project.get_build_files(f_id)

            for f in files:
                f.add_compiler_flag(flag)

    # 添加文件夹
    def addfolders(self, folders):
        if self.project:
            self.temp_files = []
            for dpp in folders:
                dp = os.path.join(self.xcode_project_path, dpp)
                if os.path.exists(dp):
                    print
                    "add folder to xcode path = [%s]" % dp
                    self.project.add_folder(dp)

                    # add folder file to xcode
                    self.getfilesdir(dp)

                else:
                    print("add folder path = [%s] is not exist!" % dp)

            print("add folder file : ")
            if len(self.temp_files) > 0:
                self.addfiles(self.temp_files)

    def getfilesdir(self, dp):
        for f in os.listdir(dp):
            f_p = os.path.join(dp, f)
            if os.path.isfile(f_p):
                self.temp_files.append(f_p)
            else:
                cp = re.compile(r".bundle|.framework")
                gp = cp.search(f_p)
                if gp is not None:
                    self.temp_files.append(f_p)
                else:
                    self.getfilesdir(f_p)

    def addfiles(self, files):
        if self.project:
            for fpp in files:
                fp = os.path.join(self.xcode_project_path, fpp)
                if os.path.exists(fp):
                    print("add file to xcode path = [%s]" % fp)
                    self.project.add_file_if_doesnt_exist(fp)

                else:
                    print("add file path = [%s] is not exist!" % fp)

            for fp in files:
                comp = re.compile('.m$|.mm$')
                match = comp.search(fp)
                if match:
                    print("file [ *.m or *.mm ] seting flag set -fno-objc-arc path [ %s ]" % fp)
                    self.set_file_seting(fp, '-fno-objc-arc')

    def addframework(self, frameworks=[], weaks=[], isbase=True):
        if self.project:
            framework_parent = self.project.get_or_create_group('Frameworks')
            for index in range(len(frameworks)):
                fw = frameworks[index]
                we = weaks[index]

                comp = re.compile('.framework$')
                match = comp.search(fw)

                tree = None
                sr = "other"

                if isbase == True:
                    tree = "SDKROOT"
                    sr = "base"

                weak = we == "True"

                if match:
                    print(
                    "add %s framework [ %s ] weak = %s" % (sr, fw, we))

                    self.project.add_file_if_doesnt_exist(fw, parent=framework_parent, weak=weak, tree=tree)
                else:
                    print(
                    "add %s libraries [ %s ]" % (sr, fw))

                    self.project.add_file_if_doesnt_exist(fw, parent=framework_parent, weak=False, tree=tree)

    def save(self, fp=None):
        if self.project:
            if fp is not None:
                self.project.save(fp)
            else:
                self.project.save()
            print( "save project")



if __name__ == "__main__":

    # path
    # _path = os.getcwd()

    # 项目路径(需要配置的路径)
    # /Users/systudiosy/Desktop/TestTargetsFoMy/TestTargetsFoMy-1.xcodeproj
    _path = "/Users/systudiosy/Desktop/TestAllChannls"
    # /TT
    if platform.system() == "Windows":
        _path = "D:/work/ballClient/trunk"

    # 其他路径
    # /Users/systudiosy/Desktop/TestAllChannls/TT
    _channel_path = "%s/%s" % (_path, _channel)
    _channel_param_path = "%s/%s_channal.json" % (_channel_path, _channel)
    # /Users/systudiosy/Desktop/TestTargetsFoMy/TestTargetsFoMy.xcodeproj
    _xcode_path = "/Users/systudiosy/Desktop/TestTargetsFoMy/"


    # 解析配置文件
    parseJson = ParseChannelParam(_channel_param_path)
    print(parseJson)

    print("Preparatory Work : ")
    # 根据配置拷贝和替换文件
    preparat = PreparatoryWork(_channel_path, _xcode_path, parseJson.file_list, parseJson.file_path_list,
                               parseJson.folder_list, parseJson.folder_path_list)

    # 根据配置文件设置xcode
    xcode = Xcode(_xcode_path, parseJson.xcode_folder_list, parseJson.xcode_file_list)
    print("\nadd file to xcode : ")
    xcode.addfileToXcode()
    print("\nadd folder to xcode : ")
    xcode.addfolderToXcode()
    print("\nadd system framework to xcode : ")
    print(parseJson.base_frameworks)
    xcode.addframework(parseJson.base_frameworks, parseJson.base_weak_frameworks, True)
    xcode.addframework(parseJson.other_frameworks, parseJson.other_weak_frameworks, False)

    if platform.system() == "Windows":
        xcode.save("project.pbxproj")
    else:
        xcode.save()

喜欢博主的土豪朋友们扫描屏幕下方二维码金额随意,感谢大家支持,增加写作动力
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了实现自动化配置Xcode工程的签名证书和bitcode开关,我们可以使用Python语言和XcodeProject库。以下是一个简单的示例程序,可以自动配置Xcode工程的签名证书和bitcode开关: ```python import XcodeProject #设置文件路径和签名证书信息 project_path = '/path/to/project' signing_identity = 'iPhone Distribution: Company Name' provisioning_profile = '/path/to/provisioning/profile.mobileprovision' #读取工程文件 project = XcodeProject.load(project_path) #修改签名证书信息 for target in project.targets: for configuration in target.buildConfigurations: configuration.buildSettings['CODE_SIGN_IDENTITY'] = signing_identity configuration.buildSettings['PROVISIONING_PROFILE_SPECIFIER'] = provisioning_profile #修改bitcode开关 for target in project.targets: for configuration in target.buildConfigurations: configuration.buildSettings['ENABLE_BITCODE'] = 'NO' #保存修改后的工程文件 project.save() ``` 这段程序首先设置了Xcode工程文件的路径和签名证书信息。然后使用XcodeProject库读取了Xcode工程文件,遍历每个target和build configuration,查找并修改了签名证书和bitcode开关。最后,将修改后的工程文件保存回原始文件中。 请注意,这仅是一个示例程序,实际的自动化配置功能可能需要更多的细节处理和错误处理。此外,由于Xcode project的配置文件格式较为复杂,需要进行一定的了解和研究才能进行自动化配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值