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 :\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 根目录
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 "\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()
通过下面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/
Unity导出xcode后自动化导入第三方SDK的更多相关文章
- iOS - error:unrecognized selector sent to class 导入第三方SDK .a后不识别,运行崩溃
今天将app统计的.a静态库包含到一个app应用中,调试时报下面的错误: *** Terminating app due to uncaught exception 'NSInvalidArgumen ...
- 【iOS】Xcode 使用 CocoaPods 导入第三方库后没有提示
Github 上下载的开源项目,运行后出现的 [iOS]build diff: /../Podfile.lock: No such file or directory 解决后,又出现了这个问题. 解决 ...
- unity 引入 ios 第三方sdk
原地址:http://blog.csdn.net/u012085988/article/details/17785023 unity开发中ios应用时,要想成功引入第三方sdk,首先得知道c#与obj ...
- Unity2018.4.7导出Xcode工程报错解决方案
1. unity导出xcode工程有两种模式,一种为模拟器运行的工程,一种为真机运行的工程,这里遇到的错误,都是导出模拟器运行工程时报的错误. 错误1: unity UnityMetalSupport ...
- iOS将Unity导出的Xcode工程导入到另一个Xcode项目, 及常见报错的解决方法
demo下载地址 http://pan.baidu.com/s/1pLcpKpl 1.Unity导出工程时设置bundle id要与项目一致 2.修改bit code为NO 3.删除Main.stor ...
- unity 引入 android第三方sdk
unity中调用java代码中介绍了unity调用android java代码的一些基础.引入android开发第三方sdk的操作跟调用java代码的操作相似,只是多了一步引入第三方jar. unit ...
- unity导出工程导入到iOS原生工程中详细步骤
一直想抽空整理一下unity原生工程导入iOS原生工程中的详细步骤.做iOS+vuforia+unity开发这么长时间了.从最初的小小白到现在的小白.中间趟过了好多的坑.也有一些的小小收货.做一个喜欢 ...
- Unity接第三方SDK时遇到的坑
1.大部分SDK的方法需要在线程中执行,一般会放在主线程里执行,安卓中主线程一般用于UI渲染. this.runOnUiThread(new Runnable() { @Override public ...
- Xcode导入第三方库
Xcode导入第三方库,例如TapkuLibrary iOS开源框架Tapku下载地址:https://github.com/devinross/tapkulibrary.git 1.创建你的工程项目 ...
随机推荐
- getline函数彻底说明
因为之前每次使用这个函数都要在网上查一遍,觉得很麻烦,这次就认真地整理一下,希望写完之后就记住. getline函数其实有两个: 一个是全局函数,include<cstring>, 原型是 ...
- Javac 手动编译时,出现乱码或编码格式问题
使用Javac进行手动编译时,出现乱码或编码格式问题,原因如下:现象:编译时出现乱码或编译错误 即使改成UTF-8仍然会出错 原因如下:某些编辑器会往utf8文件中添加utf8标记(editplus称 ...
- Spring 3种注入方式
spring的三种注入方式: 接口注入(不推荐) getter,setter方式注入(比较常用) 构造器注入(死的应用) 关于getter和setter方式的注入: autowire="de ...
- 套题 codeforces 361
A题((Mike and Cellphone) 看起来好像需要模拟数字键位的运动,可是,只要判断出那些必然YES的数字组合不就好了么 #include <cstdio> #include ...
- 关于css3媒体查询和响应式布局
响应式设计 响应式设计可根据所显示的屏幕大小而改变, 它呈现的每个屏幕看起来并不相同.按照可用的屏幕属性,响应式设计提供了 UI 的最佳效果. 例如,如果网站布局上有一个占据 25% 的屏幕宽度的侧边 ...
- (转) silverlight 样式学习
原文地址:http://www.cnblogs.com/Joetao/articles/2074727.html <UserControl x:Class="StyleDemo.Mai ...
- Percona Server 5.6.13-61.0 首个 GA 版本发布
Percona Server 5.6 的首个 GA 版本发布了,版本号是 5.6.13-61.0 ,该版本基于 MySQL 5.6.13 改进内容包括: New Features: Percona S ...
- ie8下使用knockoutjs遇到的一个模板异常
ViewModel中有一个数组,代码大概如下: function ReportViewModel(){ var self = this; self.extendedProperties = ko.ob ...
- Java多线程18:线程池
使用线程池与不使用线程池的差别 先来看一下使用线程池与不适应线程池的差别,第一段代码是使用线程池的: public static void main(String[] args) { long sta ...
- Java对象表示方式2:XStream实现对对象的XML化
上一篇文章讲到了使用Java原生的序列化的方式来表示一个对象.总结一下这种对象表示方式的优缺点: 1.纯粹的Java环境下这种方式可以很好地工作,因为它是Java自带的,也不需要第三方的Jar包的支持 ...