ios打包研究(四)脚本修改配置xcodeproj和mod-pbxproj

3,065 阅读2分钟
  1. xcodeproj ruby操作github
  2. mod-pbxproj python操作github 本文主要讲解xcodeproj

一、加载xxx.project的配置

project_path = 'xxx.xcodeproj'
project = Xcodeproj::Project.open(project_path)

二、修改工程某Target的build setting

project.targets.each do |target|
    #your target name
    if target.name == 'target1'
        target.build_configurations.each do |config|
         # Debug / Release
        if config.name == 'Release'
             #获得build settings
            build_settings = config.build_settings
            #build_settings是一个哈希,里面是一个个配置
            build_settings.each do |key,value|
                print key, " == ", value, "\n"
                # 可在这里进行设置证书等操作,常用的如下:
                # 比如修改bundle id ,测试
                # build_settings[key] = "com.test.demo"
                # 设置授权文件
                # build_settings["CODE_SIGN_ENTITLEMENTS"] = "xxx.entitlements"
                # 设置签名 iPhone Distribution / iPhone Developer
                build_settings["PROVISIONING_PROFILE_SPECIFIER"] = "PROFILENAME"
                build_settings["PRODUCT_BUNDLE_IDENTIFIER"] = "your BUNDLEID"
                build_settings["DEVELOPMENT_TEAM"] = "your TEAMID"
                # ..... 其他的视情况(需求)去查找API
            end
        end
    end
 end

三、依赖和取消依赖Extension

def updateDependecies(mode, project, app_target_name, ext)
        require 'xcodeproj'
        
        # Find project and app target
        puts mode
        xc = project
        app_target = xc.targets.find { |t| t.name == app_target_name }
        
        # Find app extensions' target objects
        target = xc.targets.find { |t| t.name == ext }
        return "Couldn't find a '#{ext}' target in '#{app_target_name}'" if target.nil?
        return "'#{ext}' doesn't seem to be an application extension target" unless target.product_type.include? 'app-extension'
        target
        
        # Find .appex product files
        appex = target.product_reference
        
        # Add or remove dependency on extension targets
        dependency = app_target.dependency_for_target(target)
        puts app_target.dependencies
        if mode == 'add'
            if dependency
                puts "[WARN] App already has dependency on #{target.name}"
                else
                app_target.add_dependency(target)
            end
            else
            if dependency
                app_target.dependencies.delete(dependency)
                else
                puts "[WARN] Couldn't find dependency on #{target.name}"
            end
        end
        
        # Add or remove .appex copy jobs
        embed_extensions_phase = app_target.copy_files_build_phases.find do |copy_phase|
            copy_phase.symbol_dst_subfolder_spec == :plug_ins
        end
        
        return "Couldn't find 'Embed App Extensions' phase" if embed_extensions_phase.nil?
        appex_included = embed_extensions_phase.files_references.include? appex
        
        if mode == 'add'
            if appex_included
                puts "[WARN] App already embeds #{appex.display_name}"
                else
                build_file = embed_extensions_phase.add_file_reference(appex)
                build_file.settings = { "ATTRIBUTES" => ['RemoveHeadersOnCopy'] }
            end
            else
            if appex_included
                embed_extensions_phase.remove_file_reference(appex)
                else
                puts "[WARN] App doesn't seem to embed #{appex.display_name}"
            end
        end
         return "更新依赖完成,update dependency '#{ext}' target in '#{app_target_name}'"
    end

四、向target添加或移除framework

相关知识参考链接

Link binary with libraries system libraries, link them.

Embed Frameworks 3rd party libraries, embed them.

  • 添加或移除系统framework
def exsit_framework?(build_phase,name)
        # next !if build_phase.nil?
        build_phase.files_references.each do |ref|
            if ref.name == "#{name}"
                puts "已经存在 #{name}"
                return true
            end
        end
        puts "不存在 #{name}"
        return false
end

def updateSystemFramework(project,target,name, command)
        require 'xcodeproj'
        puts "#{command} #{name} to #{target}"
        build_phase = target.frameworks_build_phase
        framework_group = project.frameworks_group
        if command == :add
            if self.exsit_framework?(build_phase,name)
                return
            end
            systempath = "System/Library/Frameworks/"
            path = "#{systempath}#{name}"
            file_ref = framework_group.new_reference(path)
            file_ref.name = "#{name}"
            file_ref.source_tree = 'SDKROOT'
            build_file = build_phase.add_file_reference(file_ref)
        else
            build_phase.files_references.each do |ref|
                if ref.name == "#{name}"
                    puts "删除 #{name}"
                    build_phase.remove_file_reference(ref)
                    framework_group.children.delete(ref)                    
                    break
                end
            end 
        end
    end
  • 添加或移除自定义framework 和lib
def updateCustomFramework(project,target, path,name,command)

        # Get useful variables
        frameworks_group = project.groups.find { |group| group.display_name == 'Frameworks' }
        frameworks_build_phase = target.build_phases.find { |build_phase| build_phase.to_s == 'FrameworksBuildPhase' }
        embed_frameworks_build_phase = nil
        target.build_phases.each do |phase|
            if phase.display_name == 'Embed Frameworks'
                embed_frameworks_build_phase = phase
            end
            # puts phase
        end
        if command == :add
            # Add new "Embed Frameworks" build phase to target
            if embed_frameworks_build_phase.nil?
                embed_frameworks_build_phase = project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)
                embed_frameworks_build_phase.name = 'Embed Frameworks'
                embed_frameworks_build_phase.symbol_dst_subfolder_spec = :frameworks
                target.build_phases << embed_frameworks_build_phase
            end
           
            # Add framework search path to target
            ['Debug', 'Release'].each do |config|
                paths = ['$(inherited)', path]
                orgpath = target.build_settings(config)['FRAMEWORK_SEARCH_PATHS']
                if orgpath.nil?
                    puts "路径为空----------"
                    target.build_settings(config)['FRAMEWORK_SEARCH_PATHS'] = paths
            else
                    puts "路径非空----------"
                    paths.each do |p|
                        if !orgpath.include?(p)
                            orgpath << p
                        end 
                    end
                end
            end

            # Add framework to target as "Embedded Frameworks"
            framework_ref = frameworks_group.new_file("#{path}#{name}")
            exsit = false
            embed_frameworks_build_phase.files_references.each do |ref|
                if ref.name = name
                    exsit = true
                end
            end
            if !exsit
                build_file = embed_frameworks_build_phase.add_file_reference(framework_ref)
                frameworks_build_phase.add_file_reference(framework_ref)
                build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy'] }
            end
        else
            frameworks_build_phase.files_references.each do |ref|

                if ref.name == "#{name}"
                    puts "删除 #{name}"
                    frameworks_build_phase.remove_file_reference(ref)
                    embed_frameworks_build_phase.remove_file_reference(ref)
                    break
                end
            end
        end

    end

五、是否开启SystemCapabilities

例如:AccessWiFi

注:像group等功能需要修改xxx.entitlements

#从外面传入的参数
wifiFlag = ARGV[0]
project.objects.each do |obj|
    if obj.isa == "PBXProject"
        systemCapabilities = obj.attributes["TargetAttributes"][ta.uuid]["SystemCapabilities"]
        puts systemCapabilities
        systemCapabilities["com.apple.AccessWiFi"] = {"enabled":"#{wifiFlag}"}
    end
end

六、直接修改plist

# encoding: utf-8
#!/usr/bin/ruby

# XXXX 改为自己的工程名称
puts "进入"
require 'xcodeproj'
project_path = './IOS.xcodeproj'
project = Xcodeproj::Project.open(project_path) #打开工程文件

plist_path = './IOS/Supporting Files/Info.plist'
plistHash = Xcodeproj::Plist.read_from_path(plist_path) #读取工程plist配置文件
puts("修改前IMAPPMIOS-Info.plist=",plistHash)
#传过来的参数 ARGV
if ARGV.size != 4
    puts "修改失败"
    else
    
    names = Array.new
    names = plistHash['CFBundleURLTypes']
        names.delete_at(1)
        names.delete_at(1)
        plistHashitems = names.at(3)
        weixinArror = plistHashitems['CFBundleURLSchemes']
        weixinArror.pop
        weixinArror.push('wxf8aece62e88666c8')
        plistHash['CFBundleURLTypes'] = names
 
    
#        end
#        if ARGV[1] != "appBundleStr"
#            plistHash['CFBundleIdentifier'] = ARGV[1] #bundle id
#        end
#        if ARGV[2] != "ShortVersionString"
#            plistHash['CFBundleShortVersionString'] = ARGV[2] #bundle version
#        end
#        if ARGV[3] != "appVersionStr"
#            plistHash['CFBundleVersion'] = ARGV[3] #内部版本号
#        end

    
    
#    plistHash['CFBundleDisplayName'] = ARGV[0] #app显示名称
#    plistHash['CFBundleIdentifier'] = ARGV[1] #bundle id
#    plistHash['CFBundleVersion'] = ARGV[2] #bundle version
    puts("修改后IMAPPMIOS-Info.plist=",plistHash)

    Xcodeproj::Plist.write_to_path(plistHash, plist_path)  #覆盖修改工程plist配置文件
    puts "修改成功"
end

摘自 juejin.cn/post/684490…

感谢原文作者 asml

更多内容请看原文

原文后面几种情况暂未遇到。