第6.3节 iOS Agent开发<一>

iOS由于其系统的特殊性,很多操作需要在Mac电脑上完成,所以也就无法部署到容器上。于是将iOS Agent开发成单独的服务,由Django开发,对外提供http请求接口,部署到Mac机器上以响应精准测试平台的请求。

6.3.1 Agent整体架构介绍

1,Agent功能架构图

2,功能模块介绍

(1)OC项目模块
针对 Object-C项目的生成覆盖率相关的操作,包括Clone项目,构建项目(需要构建后的Class文件),上传覆盖率文件(此文件为打包后的zip文件),XcodeCoverage生成覆盖率报告,以及解析覆盖率报告数据(取行覆盖率相关数据),下载覆盖率报告,以便精准测试平台展示。

  • 构建项目生成报告类iOSCovOperations:
python 复制代码
# coding=utf-8
import os,shutil
import zipfile

from iOSOCAndSwiftAgent.UtilsOperation.const import DEBUG_SERVICE


class iOSCovOperations(object):
    """
    iOS覆盖率相关操作
    """
    def getGcnoFilePath(self,propath):
        """获取项目构建后的gcno文件路径"""
        envfilepath=propath+"Pods/XcodeCoverage/env.sh";
        gcnopath=""
        rfile=open(envfilepath)
        line=rfile.readline()
        while line:
            if line.find("OBJECT_FILE_DIR_normal")>-1:
                gcnopath=line[line.index("=")+2:line.rindex("\"")]
                break
            line=rfile.readline()
        gcnopath=gcnopath+"/arm64"
        return gcnopath

    def copygcnofile(self,propath):
        """
        拷贝构建后的文件
        :param propath:
        :return:
        """
        # 4,拷贝构建后的代码到指定路径
        gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
        if os.path.exists(gcnopath):
            shutil.rmtree(gcnopath)
        shutil.copytree(self.getGcnoFilePath(propath),gcnopath)


    def buildPorject(self,propath):
        """构建iOS项目"""
        curpath = os.getcwd();
        scriptpath=""
        print("当前目录是:"+curpath)
        if DEBUG_SERVICE.find("Agent")>-1:
            #写死Agent上的路径
            scriptpath="/Users/****/ScriptFiles/"
        else:
            #本机debug
            scriptpath="/Users/*****/ScriptFiles/"
        os.chdir(propath)
        # 1,pod安装
        os.system("pod install")
        # 2,拷贝构建脚本
        os.system("cp "+scriptpath+"EnterpriseExportOptionsPlist.plist "+propath+"EnterpriseExportOptionsPlist.plist")
        os.system("cp "+scriptpath+"xcodebuild.sh "+propath+"xcodebuild.sh")
        os.system("chmod 777 "+propath+"xcodebuild.sh")
        # 获取项目名称
        proname=""
        for f in os.listdir(propath):
            print("file name:"+f)
            if f.find("xcworkspace")>-1:
                proname=f[0:f.index(".")]
                break
        #3,构建项目
        if len(proname)>0:
            os.system(propath+"xcodebuild.sh "+proname+" &")
        else:
            print("项目中没有项目文件,请检测项目内容是否有遗漏!")

        # # 4,拷贝构建后的代码到指定路径
        # gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
        # if os.path.exists(gcnopath):
        #     shutil.rmtree(gcnopath)
        # shutil.copytree(self.getGcnoFilePath(propath),gcnopath)
        #5,切换回当前目录
        os.chdir(curpath)
        return True

    def createiOSCovReport(self,propath,covdatapath):
        """根据覆盖率数据文件,生成覆盖率执行"""
        #1,拼出gcno文件路径
        gcnopath=propath+"Pods/XcodeCoverage/gcnofolder"
        #2,拷贝构建后的文件到覆盖率文件中
        for fileName in os.listdir(gcnopath):
            srcFile = os.path.join(gcnopath,fileName)
            tarFile = os.path.join(covdatapath,fileName)
            shutil.copyfile(srcFile,tarFile)

        #3,覆盖率报告路径
        covreppath=propath+"Pods/XcodeCoverage/tempreports/"+covdatapath[covdatapath.rindex("/")+1:len(covdatapath)]
        if not os.path.exists(covreppath):
            os.makedirs(covreppath)

        #4,重写env.sh文件内容
        envfile=propath+"Pods/XcodeCoverage/env.sh"
        os.remove(envfile)
        wrfile=open(envfile,"w+")
        #写入BUILT_PRODUCTS_DIR
        wrfile.write("export BUILT_PRODUCTS_DIR=\""+covreppath+"\"\t\n");
        #写入export CURRENT_ARCH=""
        wrfile.write("export CURRENT_ARCH=\"\"\t\n");
        #写入OBJECT_FILE_DIR_normal
        wrfile.write("export OBJECT_FILE_DIR_normal=\""+covdatapath+"\"\t\n");
        #写入OBJROOT
        wrfile.write("export OBJROOT=\"\"\t\n");
        #写入SRCROOT
        wrfile.write("export SRCROOT=\""+propath+"\"\t\n");
        wrfile.close()
        #5,执行生成报告命令
        getcovcmd=propath+"Pods/XcodeCoverage/getcov"
        os.system(getcovcmd)

        return covreppath


    def createXcodeCoverageReport(self,propath,covdatapath):
        """根据覆盖率数据,合并报告生成最终的报告"""
        gedatapath = propath + "Pods/XcodeCoverage/coverage"
        if not os.path.exists(gedatapath):
            os.makedirs(gedatapath)
        xcreppath = propath + "Pods/XcodeCoverage/report"
        if not os.path.exists(xcreppath):
            os.makedirs(xcreppath)
        #遍历覆盖率数据文件夹,分别生成报告
        count=0
        for file in os.listdir(covdatapath):
            if file.find("arm")>-1:
                tempcovpath=covdatapath+"/"+file
                print("数据文件:"+tempcovpath)
                temprep=self.createiOSCovReport(propath,tempcovpath)
                #拷贝生成的Coverage.info文件
                os.system("cp "+temprep+"/lcov/Coverage.info "+gedatapath+"/Coverage"+str(count)+".info")
                count=count+1
        # 生成整体覆盖率的报告
        mercmd=propath+"Pods/XcodeCoverage/mergecov"
        curpath = os.getcwd();
        if DEBUG_SERVICE.find("Agent")>-1:
            #写死Agent上的路径
            scriptpath="/Users/****/ScriptFiles/"
        else:
            #本机debug
            scriptpath="/Users/*****/ScriptFiles/"
        os.system("cp "+scriptpath+"mergecov "+mercmd)
        os.system("chmod 777 "+mercmd)
        os.system(mercmd)
        # 将生成的测试报告打包
        output_filename=propath+"report.zip"
        zipf = zipfile.ZipFile(output_filename, 'w')
        pre_len = len(os.path.dirname(xcreppath))
        for parent, dirnames, filenames in os.walk(xcreppath):
            for filename in filenames:
                pathfile = os.path.join(parent, filename)
                arcname = pathfile[pre_len:].strip(os.path.sep)
                zipf.write(pathfile, arcname)
        zipf.close()
        return xcreppath


    def getCovData(self,reppath):
        """
        获取覆盖率报告中的数据
        :param reppath:
        :return:
        """
        file=open(reppath,"r")
        line=file.readline()
        covlines=""
        totallines=""
        covlinerate=""
        covfuns=""
        totalfuns=""
        covfunrate=""
        while line:
            line=file.readline()
            if line.find("headerCovTableEntry")>-1:
                if len(covlines)==0:
                    covlines=line[line.index(">")+1:line.rindex("<")]
                    continue
                if len(covlines)>0 and len(totallines)==0:
                    totallines=line[line.index(">")+1:line.rindex("<")]
                    continue
                if line.find("%")>-1 and len(covlinerate)==0:
                    covlinerate=line[line.index(">")+1:line.rindex("<")]
                    continue
                if len(covfuns)==0:
                    covfuns=line[line.index(">")+1:line.rindex("<")]
                    continue
                if len(covfuns)>0 and len(totalfuns)==0:
                    totalfuns=line[line.index(">")+1:line.rindex("<")]
                    continue
                if line.find("%")>-1 and len(covfunrate)==0:
                    covfunrate=line[line.index(">")+1:line.rindex("<")]
                    break
        repdata={"totalines":totallines,"covlines":covlines,"covlinerate":covlinerate,"totalfuns":totalfuns,"covfuns":covfuns,"covfunrate":covfunrate}
        return repdata

if __name__ == '__main__':
    iosopr=iOSCovOperations()
    propath="/Users/****/ghdropmenudemo/"
covdatapath="/Users/****/ghdropmenudemo/Pods/XcodeCoverage/tempcovdata"
  
    iosopr.getCovData(propath+"Pods/XcodeCoverage/report/index.html")

此方案主要在构建项目上比较耗时,可以采取在公司打包平台打包后上传构建文件,以节省时间;同时上传的覆盖率数据文件也较大,由于公司的项目是Swift的,这个模块也没有再继续优化,使用测试Demo验证,相关功能没有问题

相关推荐
开开心心loky3 小时前
[iOS] OC高级编程 - 引用计数 (1)
macos·ios·objective-c·cocoa
2501_915106323 小时前
iOS 混淆与机器学习模型保护 在移动端保密权重与推理逻辑的实战指南(iOS 混淆、模型加密、ipa 加固)
android·人工智能·机器学习·ios·小程序·uni-app·iphone
低调小一3 小时前
从Android到iOS:启动监控实现的跨平台技术对比
android·ios·cocoa
2501_915909063 小时前
iOS 26 耗电检测实战攻略,如何测电量掉速、定位高耗能模块与优化策略(适用于 uni-app 原生 App)
android·ios·小程序·uni-app·cocoa·iphone·webview
2501_915921433 小时前
iOS 26 性能测试实战,如何评估启动速度、CPUGPU 负载、帧率与系统资源适配(uni-app 与 iOS 原生应用性能方案)
android·ios·小程序·uni-app·cocoa·iphone·webview
天堂罗恋歌6 小时前
iOS PPBluetoothKit接入无法找到头文件问题
ios·objective-c·xcode·app store
Winter_Sun灬7 小时前
老的ios项目在新的mac M1上编译运行遇到的问题及整理
macos·ios
猪哥帅过吴彦祖10 小时前
Flutter 系列教程:Dart 语言快速入门 (下)
前端·flutter·ios