Class: Pindo::XcodeBuildConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/pindo/module/xcode/xcodebuildconfig.rb

Class Method Summary collapse

Class Method Details

.add_single_scheme(plist_dict, scheme_value) ⇒ Boolean

添加单个scheme到plist字典中

Parameters:

  • plist_dict (Hash)

    Info.plist字典

  • scheme_value (String)

    scheme值

Returns:

  • (Boolean)

    是否添加了新scheme



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/pindo/module/xcode/xcodebuildconfig.rb', line 70

def self.add_single_scheme(plist_dict, scheme_value)
    return false if scheme_value.nil? || scheme_value.empty?

    # 检查是否已存在
    return false if plist_dict["CFBundleURLTypes"].any? { |item| item["CFBundleURLName"] == scheme_value }

    # 创建新的URL Type
    url_type = {
        "CFBundleTypeRole" => "Editor",
        "CFBundleURLName" => scheme_value,
        "CFBundleURLSchemes" => [scheme_value]
    }

    plist_dict["CFBundleURLTypes"] << url_type
    return true
end

.add_url_schemes(project_dir: nil, scheme_name: nil) ⇒ Boolean

添加URL Schemes到iOS工程的Info.plist

Parameters:

  • project_dir (String) (defaults to: nil)

    iOS项目目录路径

  • scheme_name (String) (defaults to: nil)

    要添加的scheme名称(可选)

Returns:

  • (Boolean)

    是否成功添加

Raises:

  • (ArgumentError)


14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/pindo/module/xcode/xcodebuildconfig.rb', line 14

def self.add_url_schemes(project_dir: nil, scheme_name: nil)
    raise ArgumentError, "项目目录不能为空" if project_dir.nil?

    project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
    return false if project_fullname.nil?

    info_plist_path = nil
    bundleid_scheme_name = nil

    project_obj = Xcodeproj::Project.open(project_fullname)
    project_obj.targets.each do |target|
        if target.product_type.to_s.eql?("com.apple.product-type.application")
            temp_info_file = target.build_configurations.first.build_settings['INFOPLIST_FILE']
            if temp_info_file && !temp_info_file.empty?
                info_plist_path = File.join(project_dir, temp_info_file)
            end
            bundleid_scheme_name = target.build_configurations.first.build_settings['PRODUCT_BUNDLE_IDENTIFIER']
            break  # 找到第一个application target即可
        end
    end

    return false unless info_plist_path && File.exist?(info_plist_path)

    info_plist_dict = Xcodeproj::Plist.read_from_path(info_plist_path)
    info_plist_dict["CFBundleURLTypes"] ||= []
    schemes_added = []

    # 添加基于项目名的scheme
    if scheme_name && !scheme_name.empty?
        scheme_value = scheme_name.to_s.gsub(/[^a-zA-Z0-9]/, '').downcase
        if add_single_scheme(info_plist_dict, scheme_value)
            schemes_added << scheme_value
        end
    end

    # 添加基于Bundle ID的scheme
    if bundleid_scheme_name && !bundleid_scheme_name.empty?
        bundleid_scheme_value = bundleid_scheme_name.gsub(/[^a-zA-Z0-9]/, '').downcase
        if add_single_scheme(info_plist_dict, bundleid_scheme_value)
            schemes_added << bundleid_scheme_value
        end
    end

    # 保存修改
    if schemes_added.any?
        Xcodeproj::Plist.write_to_path(info_plist_dict, info_plist_path)
        schemes_added.each { |s| puts "  ✓ 已添加URL Scheme: #{s}" }
    end

    return true
end

.update_entitlements_config(project_dir: nil, config_file: nil) ⇒ Boolean

更新entitlements配置根据entitlements文件内容,同步更新config.json中的配置如果entitlements中没有icloud或app group,则从config.json中移除对应配置

Parameters:

  • project_dir (String) (defaults to: nil)

    项目目录路径

  • config_file (String) (defaults to: nil)

    config.json文件路径

Returns:

  • (Boolean)

    是否成功更新

Raises:

  • (ArgumentError)


186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
# File 'lib/pindo/module/xcode/xcodebuildconfig.rb', line 186

def self.update_entitlements_config(project_dir: nil, config_file: nil)
    raise ArgumentError, "项目目录不能为空" if project_dir.nil?
    raise ArgumentError, "配置文件路径不能为空" if config_file.nil?

    project_fullname = Dir.glob(File.join(project_dir, "/*.xcodeproj")).max_by {|f| File.mtime(f)}
    return false if project_fullname.nil?

    entitlements_plist_path = nil
    project_obj = Xcodeproj::Project.open(project_fullname)

    project_obj.targets.each do |target|
        if target.product_type.to_s.eql?("com.apple.product-type.application")
            temp_entitlements_file = target.build_configurations.first.build_settings['CODE_SIGN_ENTITLEMENTS']
            if temp_entitlements_file && !temp_entitlements_file.empty?
                entitlements_plist_path = File.join(project_dir, temp_entitlements_file)
            end
            break # 找到第一个application target即可
        end
    end

    # 处理entitlements配置
    if entitlements_plist_path && File.exist?(entitlements_plist_path)
        config_json = nil
        if File.exist?(config_file)
            config_json = JSON.parse(File.read(config_file))
        end

        return false if config_json.nil?

        entitlements_plist_dict = Xcodeproj::Plist.read_from_path(entitlements_plist_path)

        # 如果entitlements中没有icloud配置,从config.json中移除
        if entitlements_plist_dict["com.apple.developer.icloud-container-identifiers"].nil?
            if config_json["app_info"] && config_json["app_info"]['app_icloud_id']
                config_json["app_info"].delete('app_icloud_id')
            end
        end

        # 如果entitlements中没有app group配置,从config.json中移除
        if entitlements_plist_dict["com.apple.security.application-groups"].nil?
            if config_json["app_info"] && config_json["app_info"]['app_group_id']
                config_json["app_info"].delete('app_group_id')
            end
        end

        # 保存更新后的config.json
        File.open(config_file, "w") do |f|
            f.write(JSON.pretty_generate(config_json))
        end

        return true
    end

    return false
end

.update_ios_project_version(project_dir: nil, version: nil, build_number: nil) ⇒ Boolean

更新iOS工程版本号

Parameters:

  • project_dir (String) (defaults to: nil)

    iOS项目目录路径

  • version (String) (defaults to: nil)

    版本号

  • build_number (Integer) (defaults to: nil)

    Build号

Returns:

  • (Boolean)

    是否成功更新

Raises:

  • (ArgumentError)


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/pindo/module/xcode/xcodebuildconfig.rb', line 92

def self.update_ios_project_version(project_dir: nil, version: nil, build_number: nil)
    raise ArgumentError, "项目目录不能为空" if project_dir.nil?
    raise ArgumentError, "版本号不能为空" if version.nil?
    raise ArgumentError, "Build号不能为空" if build_number.nil?

    Funlog.instance.fancyinfo_start("正在更新iOS工程版本信息...")

    begin
        # 查找.xcodeproj文件
        xcodeproj_path = find_xcodeproj(project_dir)

        if xcodeproj_path.nil?
            Funlog.instance.fancyinfo_error("未找到Xcode项目文件")
            return false
        end

        # 打开Xcode项目
        project = Xcodeproj::Project.open(xcodeproj_path)

        # 更新所有application类型target的版本号
        updated_targets = []
        project.targets.each do |target|
            # 只处理application类型的target
            if target.product_type.to_s.eql?("com.apple.product-type.application")
                target.build_configurations.each do |config|
                    # 更新版本号
                    config.build_settings['MARKETING_VERSION'] = version
                    config.build_settings['CURRENT_PROJECT_VERSION'] = build_number.to_s

                    # 兼容旧的设置方式,通过Info.plist更新
                    if config.build_settings['INFOPLIST_FILE']
                        info_plist_path = File.join(project_dir, config.build_settings['INFOPLIST_FILE'])
                        if File.exist?(info_plist_path)
                            update_info_plist(info_plist_path, version, build_number.to_s)
                        end
                    end
                end
                updated_targets << target.name
            end
        end

        # 保存项目
        project.save

        if updated_targets.empty?
            Funlog.instance.fancyinfo_error("未找到需要更新的application target")
            return false
        else
            Funlog.instance.fancyinfo_success("iOS版本更新完成!")
            puts "  ✓ 版本号已更新: #{version}"
            puts "  ✓ Build号已更新: #{build_number}"
            puts "  ✓ 更新的Target: #{updated_targets.join(', ')}"
            return true
        end

    rescue StandardError => e
        Funlog.instance.fancyinfo_error("更新iOS版本失败: #{e.message}")
        return false
    end
end