美文网首页
学习Xcodeproj

学习Xcodeproj

作者: 独孤流 | 来源:发表于2022-05-02 17:26 被阅读0次

Xcodeproj源码: https://github.com/CocoaPods/Xcodeproj
xcodeproj文档:https://www.rubydoc.info/search/gems/xcodeproj
pbxprojHelper: https://github.com/yulingtianxia/pbxprojHelper
ruby库xcodeproj使用心得
Xcodeproj: 使用 ruby 自由的修改Xcode 工程文件
FileUtils
Dir文件遍历
Ruby调用shell脚本总结

利用Xcodeproj自动生成三方没有提供的模拟器版本
完整demo: https://github.com/eye1234456/PodSample/blob/main/auto_mix_simulator_sdk/auto_create_xcodeproj_archive_framework.rb
https://github.com/eye1234456/PodSample/blob/main/auto_mix_simulator_sdk/archive_tool_auto.sh

#!/usr/bin/ruby
require 'xcodeproj'
require "FileUtils"

# 解析framework并读取公共的header,生成对应的文件
def create_header_impl(basePath,framework_name)
    # 添加.h .m文件 如下
    project_dir = "#{basePath}/#{framework_name}"
    source_dir = "#{project_dir}/#{framework_name}"
    old_framework_header_dir = "#{basePath}/#{framework_name}.framework/Headers"
    puts "basePath: #{basePath}"
    puts "project_dir: #{project_dir}"
    puts "source_dir: #{source_dir}"
    puts "old_framework_header_dir: #{old_framework_header_dir}"

    # 清空旧数据
    if File.directory?(project_dir) && Dir.exist?(project_dir)
        FileUtils.rm_rf(project_dir)
    end
    # 创建项目文件
    FileUtils.mkdir_p(project_dir)
    # 创建项目源文件
    FileUtils.mkdir_p(source_dir)
    ####################
    Dir.foreach(old_framework_header_dir) { |file_path| 
        new_header_file_path = File.join(source_dir, File.basename(file_path))
        
        # 复制文件
        if file_path.end_with?(".h") 
            old_header = "#{old_framework_header_dir}/#{file_path}"
            puts "old header : #{file_path}"
            puts "new header : #{new_header_file_path}"
            FileUtils.cp(old_header, new_header_file_path)
        end
        
    }
end

# 创建一个xxx.xcodeproj文件
def auto_create_project(old_framework_path)
    # puts "================="
    # 添加.h .m文件 如下
    basePath = File.dirname(old_framework_path) #当前根路径
    framework_name = File.basename(old_framework_path, ".*")  #=> "TTTPlayerKit"
    project_name = framework_name
    project_dir = "#{basePath}/#{project_name}"
    source_dir = "#{project_dir}/#{project_name}"
    project_path = "#{project_dir}/#{project_name}.xcodeproj"
    old_framework_header_dir = "#{old_framework_path}/Headers"
    puts "project_dir: #{project_dir}"
    puts "source_dir: #{source_dir}"
    puts "project_path: #{project_path}"
    puts "old_framework_header_dir: #{old_framework_header_dir}"
    
    ########## 创建project类  核心逻辑###########
    
    if File.exist?(project_path) 
        # 已经存在就打开
        puts "already exists #{project_path}, open"
        project = Xcodeproj::Project.open(project_path)
    else
        # 不存在就创建
        puts "not exists #{project_path}, need create"
        project = Xcodeproj::Project.new(project_path)
    end

    # 获取target
    if project.targets.size > 0 && project.targets.include?(project_name) 
        # 已经存在了,则是打开一个文件
        puts "already exists target #{project_name}, get"
        target = project.targets.select do |t|
            t == project_name
        end
    else
    # 不存在,就创建
    puts "not exists target #{project_name}, need create"
    target = project.new_target(:framework, project_name, :ios, "9.0")
    end


    # 创建group
    #找到要插入的group (参数中true表示如果找不到group,就创建一个group)
    groupName = project_name
    group = project.main_group.find_subpath(File.join(groupName),true)
    #set一下sorce_tree
    # group.set_source_tree('SOURCE_ROOT')
    group.set_source_tree('SOURCE_ROOT')

    # 需要天机的文件路径

    # puts header_arr
    Dir.foreach(source_dir) do |file_path|
        
        header_file_path = "#{source_dir}/#{file_path}"
        if header_file_path.end_with?(".h") 
            file_ref = group.new_file(header_file_path)
            # 要加到Headers public里,framework特有
            header = target.headers_build_phase.add_file_reference(file_ref)
            # 设置访问权限为'public', 这样导出的framework才可以访问到
            header.settings = { 'ATTRIBUTES' => ['Public'] }
        elsif header_file_path.end_with?(".m")
            # .m文件要加到项目里去
            file_ref = group.new_file(header_file_path)
            target.source_build_phase.add_file_reference(file_ref, true)
        end

    end
    # 保存
    project.save()
end

##########打包并合并framework###########
def auto_make_archive(base_path, project_scheme_name, configuration)
   
   # 项目路径
    project_dir_path = "#{base_path}/#{project_scheme_name}"
    # FileUtils.cd(project_dir_path)
    # .xcodeproj路径
    xcodeproj_path = "#{project_dir_path}/#{project_scheme_name}.xcodeproj"
    # 临时存放文件的文件夹名字
    temp_archive_folder_name = "#{project_scheme_name}_#{project_scheme_name}_XCFramework"
    temp_archive_folder_path = "#{project_dir_path}/#{temp_archive_folder_name}/simulator.xcarchive"
   
    # set path for iOS device archive
    # 删除之前生成的xcframework的文件夹
    # 创建临时文件
    FileUtils.rm_rf(temp_archive_folder_path)
    FileUtils.mkdir_p(temp_archive_folder_path)
        
    # 创建simulator的framework
    sh_archive = %/
        xcodebuild archive \
        -project "#{xcodeproj_path}" \
        -scheme "#{project_scheme_name}" \
        -configuration "#{configuration}" \
        -destination="iOS Simulator" \
        -archivePath "#{temp_archive_folder_path}" \
        -sdk iphonesimulator clean build \
        SKIP_INSTALL=NO \
        BUILD_LIBRARIES_FOR_DISTRIBUTION=YES
    /
    puts sh_archive
    exec(sh_archive)

end

def auto_combine_framework(base_path, project_scheme_name, configuration)
    # 生成xcframework
    project_dir_path = "#{base_path}/#{project_scheme_name}"
    temp_archive_folder_name = "#{project_scheme_name}_#{project_scheme_name}_XCFramework"
    # 生成的xcframework
    
    export_dir_path = "#{base_path}/export"
    # 生成xcframework的路劲
    export_xcframework_path = "#{export_dir_path}/#{project_scheme_name}.xcframework"
    # 生成真机、模拟器二和一的路劲
    export_mix_framework_path = "#{export_dir_path}/#{project_scheme_name}.framework"

    # 创建导出文件地址
    FileUtils.rm_rf(export_dir_path)
    FileUtils.mkdir_p(export_dir_path)

    # set path for iOS simulator archive
    # 生成的模拟器的库的文件
    simulator_archive_path = "#{project_dir_path}/#{temp_archive_folder_name}/simulator.xcarchive"
    simulator_framework_path = "#{simulator_archive_path}/Products/Library/Frameworks/#{project_scheme_name}.framework"
    iphone_framework_path = "#{base_path}/#{project_scheme_name}.framework"

    sh_xcframework = %/
    xcodebuild -create-xcframework \
    -framework #{simulator_framework_path} \
    -framework #{iphone_framework_path} \
    -output "#{export_xcframework_path}"
    /
    puts sh_xcframework
    exec(sh_xcframework)
    # 生成真机模拟器二合一framework
    

    # 先复制一个真机的版本到目标
    # sh_mix_framework = %/
    # cp -rf #{iphone_framework_path} #{export_mix_framework_path}\
    # lipo -create \
    # #{simulator_framework_path}/#{project_scheme_name} \
    # #{export_mix_framework_path}/#{project_scheme_name} \
    # -output #{export_mix_framework_path}/#{project_scheme_name}
    # /
    # exec(sh_mix_framework)
    exec("open #{export_dir_path}")
end

#######调用#######
def create_framework_project(old_framework_path)
    basePath = File.dirname(old_framework_path) #当前根路径
    framework_name = File.basename(old_framework_path, ".*")
    puts "old_framework_path: #{old_framework_path}"
    puts "basePath: #{basePath}"
    puts "framework_name: #{framework_name}"
    # 1、解析旧的framework,并复制对应的文件
    create_header_impl(basePath,framework_name)
    # 2、创建项目
    auto_create_project(old_framework_path)
    # 3、生成xrchive
    # auto_make_archive(basePath, framework_name, "Debug")
    # 4、合并成xcframework
    # auto_combine_framework(basePath, framework_name, "Debug")
    # exec("sh #{basePath}/archive_tool_auto.sh")
end

old_framework_path = "/xxx/xxxx/xxx/AAA.framework"
create_framework_project(old_framework_path)

另外添加使用shell脚本打包合并

#!/bin/bash

packaging(){
    # set framework folder name
    # 工程名称(Project的名字)
    PROJECT_NAME=$1
    # scheme名称
    SCHEME_NAME=$2
    Configuration=$3
    # 项目所在的文件
    PROJECT_DIR=$4
    # 创建的真机的库的地址
    IPHONE_Framework_folder=$5
    IPHONE_Framework_PATH="${IPHONE_Framework_folder}/${SCHEME_NAME}.framework"
    # 导出的xcframework 和 合并的framework的文件夹
    EXPORT_FOLDER_PATH=$6

    xcodeproj_path="${PROJECT_DIR}/${PROJECT_NAME}.xcodeproj"
    # 临时存放文件的文件夹名字
    FRAMEWORK_FOLDER_NAME="${PROJECT_NAME}_${SCHEME_NAME}_XCFramework"
    TEMP_FRAMEWORK_DIR="${PROJECT_DIR}/${FRAMEWORK_FOLDER_NAME}"
    # 生成的xcframework
    
    # 生成xcframework的路劲
    EXPORT_XCFRAMEWORK_PATH="${EXPORT_FOLDER_PATH}/${SCHEME_NAME}.xcframework"
    # 生成真机、模拟器二和一的路劲
    EXPORT_MIX_FRAMEWORK_PATH="${EXPORT_FOLDER_PATH}/${SCHEME_NAME}.framework"
    # set path for iOS simulator archive
    # 生成的模拟器的库的文件
    SIMULATOR_ARCHIVE_PATH="${TEMP_FRAMEWORK_DIR}/simulator.xcarchive"
    # set path for iOS device archive
    # 生成的真机的库的文件
    IOS_DEVICE_ARCHIVE_PATH="${TEMP_FRAMEWORK_DIR}/iOS.xcarchive"
    # 删除之前生成的xcframework的文件夹
    # 创建临时文件
    rm -rf "${TEMP_FRAMEWORK_DIR}"
    mkdir "${TEMP_FRAMEWORK_DIR}"
    # 创建导出文件地址
    rm -rf "${EXPORT_FOLDER_PATH}"
    mkdir "${EXPORT_FOLDER_PATH}"


    echo '==================start================'
    total_startTime_s=`date +%s`
    
    echo '开始模拟器archive'
    archive_simulator_startTime_s=`date +%s`
        
    # 创建simulator的framework
    xcodebuild archive \
    -project ${xcodeproj_path} \
    -scheme ${SCHEME_NAME} \
    -configuration ${Configuration} \
    -destination="iOS Simulator" \
    -archivePath "${SIMULATOR_ARCHIVE_PATH}" \
    -sdk iphonesimulator clean build \
    SKIP_INSTALL=NO \
    BUILD_LIBRARIES_FOR_DISTRIBUTION=YES

    archive_simulator_endTime_s=`date +%s`
    echo "模拟器archive时长:$[$archive_simulator_endTime_s - $archive_simulator_startTime_s]"
    echo '结束模拟器archive'


    #Creating XCFramework
    # 创建的模拟器库的地址
    SIMULATOR_Framework_PATH="${SIMULATOR_ARCHIVE_PATH}/Products/Library/Frameworks/${SCHEME_NAME}.framework"


    # 生成xcframework
    echo '开始合成xcframework'
    create_xcframework_startTime_s=`date +%s`

    xcodebuild -create-xcframework \
    -framework ${SIMULATOR_Framework_PATH} \
    -framework ${IPHONE_Framework_PATH} \
    -output "${EXPORT_XCFRAMEWORK_PATH}"

    create_xcframework_endTime_s=`date +%s`
    echo "合成xcframework时长:$[$create_xcframework_endTime_s - $create_xcframework_startTime_s]"
    echo '结束合成xcframework'

    # 生成真机模拟器二合一framework
    echo '开始合成framework'
    create_mix_framework_startTime_s=`date +%s`

    # 先复制一个真机的版本到目标
    cp -rf ${IPHONE_Framework_PATH} ${EXPORT_MIX_FRAMEWORK_PATH}
    # 将真机和模拟器合并成一个
    lipo -create \
    "${SIMULATOR_Framework_PATH}/${SCHEME_NAME}" \
    "${IPHONE_Framework_PATH}/${SCHEME_NAME}" \
    -output "${EXPORT_MIX_FRAMEWORK_PATH}/${SCHEME_NAME}"

    create_mix_framework_endTime_s=`date +%s`
    echo "合成framework时长:$[$create_mix_framework_endTime_s - $create_mix_framework_startTime_s]"
    echo '结束合成framework'

    rm -rf "${TEMP_FRAMEWORK_DIR}"
    total_endTime_s=`date +%s`
    echo '==================end================'
    echo "总共时长:$[$total_endTime_s - $total_startTime_s]"

    open "${EXPORT_FOLDER_PATH}"
}

#函数调用
# $1 工程名  $2 scheme名字  $3 Release还是Debug $4项目文件地址 $5真机framework地址 $6导出文件夹地址
# source xxxx.sh
# packaging "HelloSDK" "AAASDK"  "Release"
packaging_archive(){
    sdkName=$1
    pwd_path="/xxx/xxx/xxx"
    
    PROJECT_DIR="${pwd_path}/${sdkName}"
    # $1 工程名  $2 scheme名字  $3 Release还是Debug $4项目文件地址 $5真机framework地址 $6导出文件夹地址
    iphone_framework_path="${pwd_path}"
    export_path_folder="${pwd_path}/export"
    packaging ${sdkName} ${sdkName} "Debug" "${PROJECT_DIR}" "${iphone_framework_path}" "${export_path_folder}"
}
# 打包
packaging_archive "AAA"

相关文章

网友评论

      本文标题:学习Xcodeproj

      本文链接:https://www.haomeiwen.com/subject/litvyrtx.html