zoukankan      html  css  js  c++  java
  • Unity导出xcode后自动化导入第三方SDK

    最近因为在给项目接入第三方SDK,遇到了一个比较烦人的事情就是,每次出包都要重新根据第三方SDK说明设置xcode,每次最少花20分钟来设置,如果出错的话就不一定是20分钟的事了,所以我决定要做一个自动化处理脚本。

    在网上查了好多资料,用比对工具一步一步的比较project.pbxproj文件的不同,真是眼睛盯瞎了的感觉。

    伯乐在线上看到了一篇关于project.pbxproj文件的说明。

    关于操作project.pbxproj文件有一下几个第三方库来参考

    • Xcodeproj CocoaPods 写的 Ruby 解析库,用于修改引入 CocoaPods 的工程文件并保存为 XML 格式。CocoaPods 本身是很强大的,还可以用来操作 Xcode workspaces (.xcworkspace), configuration files (.xcconfig) 和 Xcode Scheme files (.xcscheme).
    • mod-pbxproj 强大的 Python 解析库,支持一定的修改操作,可输出 OpenStep 格式,但是顺序和注释内容无法完美还原,有些鸡肋。
    • xUnique 用 Python 写的统一多设备生成的 UUID 的工具,主要用途是统一工程在多设备上生成的 UUID,避免工程文件冲突。
    • pbxplorer Ruby 写的解析库。
    • node-xcode Cordova 基于它管理 Xcode 工程

    我用到了mod-pbxproj库里面的提供的一些方法来实现项目需求

    由于个人python水平还在初级阶段,不过也正在补充自己,代码写的可能比较烂,但是以解决实际问题为主

    #!/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
    from mod_pbxproj import XcodeProject
    import re
    import platform
    
    
    _channel = "ios_yh"
    _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:
                with open(jp) as jf:
                    self.json_data = json.load(jf)
    
                    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):
            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 :
    bundle_id = %s version = %s 
    xcode_file_list = %s 
    xcode_folder_list = %s
    
    " % (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 根目录
            self.from_path = frompath
            # to 根目录
            self.to_path = topath
    
            # 需要 copy 的文件
            self.file_from_path_list = filefromls
            self.file_to_path_list = filetols
    
            # 需要 copy 的目录
            self.folder_from_list = folderfromls
            self.folder_to_path_list = foldertols
    
            # 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, 'Unity-iPhone.xcodeproj/project.pbxproj.xml')
            else:
                self.xcode_pbxproj_path = os.path.join(xpath, 'Unity-iPhone.xcodeproj/project.pbxproj')
    
            # 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()
    
        #项目路径(需要配置的路径)
        _path = "/Users/admin/Desktop/ballClent"
        if platform.system() == "Windows":
            _path = "D:/work/ballClient/trunk"
    
        # 其他路径
        _channel_path = "%s/%s/%s" % (_path, "iosChannel/", _channel)
        _channel_param_path = "%s/%s.json" % (_channel_path, _channel)
        _xcode_path = "%s/%s" % (_path, "Build/Output/IOS")
    
        # 解析配置文件
        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 "
    add file to xcode : "
        xcode.addfileToXcode()
        print "
    add folder to xcode : "
        xcode.addfolderToXcode()
        print "
    add 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()
    

     通过下面Json来自动化处理每个渠道SDK的导入

    {
        "bundleId": "com.*.*", 
        "version": "1.0.0", 
        "file": [
            {
                "file_name": "UnitySdkInterface.mm", 
                "file_path": "Libraries/Plugins/iOS",
    			"type": "replace"
            }, 
            {
                "file_name": "UnityAppController.mm", 
                "file_path": "Classes",
    			"type": "replace"
            }, 
            {
                "file_name": "YHGameSdk.h", 
                "file_path": "",
    			"type": "copy"
            }, 
            {
                "file_name": "YHGameSdk.m", 
                "file_path": "",
    			"type": "copy"
            },
    		{
                "file_name": "Info.plist", 
                "file_path": "",
    			"type": "replace"
            }
        ], 
        "resource": [
            {
                "dir_name": "galaxyJointSDK",
    			"dir_path": "",
    			"type": "copy"
            }
        ],
    	"base_framework": [
    		{
    			"path": "System/Library/Frameworks/MessageUI.framework",
    			"weak": "True"
    		},
    		{
    			"path": "usr/lib/libc++.tbd",
    			"weak": "False"
    		},
    		{
    			"path": "usr/lib/libz.tbd",
    			"weak": "False"
    		},
    		{
    			"path": "usr/lib/libsqlite3.tbd",
    			"weak": "False"
    		}
    	],
    	"other_framework": [
    	
    	]
    }
    

     Unity 导出xcode之后在执行此脚本,传递参数channel之后即可根据配置自动化处理。目录是我们项目自己的目录。

    在此记录一下自己成果,为跟我一样迷茫的小伙伴们一起分享。如果有问题请留言。

    支持原创,转载请注明作者出处我的博客http://home.cnblogs.com/u/fastHro/

  • 相关阅读:
    MvcApplication 中方法的那点事
    Html 中阻止事件冒泡的三种方法比较
    WPF中 ItemsSource 和DataContext不同点
    解决:Visual Studio 启动就报错退出
    webapi是如何绑定参数的(How WebAPI does Parameter Binding)
    %cd% 和%~dp0%的区别及cd跨盘符切换路径问题
    win10中matlabR2015b安装libsvm
    MATLAB2015b链接MinGW编译器
    网易内推编程题:异或运算求混合颜料的最小种类
    小易喜欢的单词
  • 原文地址:https://www.cnblogs.com/fastHro/p/6086533.html
Copyright © 2011-2022 走看看