pindo 5.6.6 → 5.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -134,6 +134,146 @@ module Pindo
134
134
  build_number >= 1 && build_number <= 2**31 - 1
135
135
  end
136
136
 
137
+ # 使用package_name更新Android应用名称(strings.xml中的app_name)
138
+ # @param project_dir [String] Android项目目录路径
139
+ # @param package_name [String] 工作流的package_name(如:"Test Demo")
140
+ # @return [Boolean] 是否成功更新
141
+ def self.update_app_name_with_packagename(project_dir: nil, package_name: nil)
142
+ raise ArgumentError, "项目目录不能为空" if project_dir.nil?
143
+ raise ArgumentError, "Package Name不能为空" if package_name.nil?
144
+
145
+ # 生成应用名称(去除特殊字符和空格)
146
+ app_name = package_name.gsub(/[^a-zA-Z0-9\s]/, '').gsub(/\s+/, '')
147
+
148
+ begin
149
+ # 创建helper实例以使用基类方法
150
+ helper = self.new
151
+ main_module = helper.get_main_module(project_dir)
152
+
153
+ if main_module.nil?
154
+ ["app", "application", "main"].each do |module_name|
155
+ module_path = File.join(project_dir, module_name)
156
+ if File.directory?(module_path)
157
+ main_module = module_path
158
+ break
159
+ end
160
+ end
161
+ end
162
+
163
+ return false if main_module.nil?
164
+
165
+ # 查找strings.xml文件
166
+ strings_xml_path = File.join(main_module, "src", "main", "res", "values", "strings.xml")
167
+
168
+ unless File.exist?(strings_xml_path)
169
+ Funlog.instance.fancyinfo_error("未找到strings.xml文件")
170
+ return false
171
+ end
172
+
173
+ # 读取并更新strings.xml
174
+ content = File.read(strings_xml_path)
175
+
176
+ # 更新app_name
177
+ if content =~ /<string\s+name="app_name">.*?<\/string>/
178
+ content.gsub!(/<string\s+name="app_name">.*?<\/string>/, "<string name=\"app_name\">#{app_name}</string>")
179
+ File.write(strings_xml_path, content)
180
+ puts " ✓ App Name 已更新为: #{app_name} (来自: #{package_name})"
181
+ return true
182
+ else
183
+ Funlog.instance.fancyinfo_error("strings.xml中未找到app_name字段")
184
+ return false
185
+ end
186
+
187
+ rescue StandardError => e
188
+ Funlog.instance.fancyinfo_error("更新App Name失败: #{e.message}")
189
+ return false
190
+ end
191
+ end
192
+
193
+ # 使用package_name更新Android Application ID(build.gradle中的applicationId)
194
+ # @param project_dir [String] Android项目目录路径
195
+ # @param package_name [String] 工作流的package_name(如:"Test Demo")
196
+ # @return [Boolean] 是否成功更新
197
+ def self.update_applicationid_with_packagename(project_dir: nil, package_name: nil)
198
+ raise ArgumentError, "项目目录不能为空" if project_dir.nil?
199
+ raise ArgumentError, "Package Name不能为空" if package_name.nil?
200
+
201
+ # 生成 Application ID
202
+ app_id_suffix = package_name.gsub(/[^a-zA-Z0-9]/, '').downcase
203
+ application_id = "com.heroneverdie101.#{app_id_suffix}"
204
+
205
+ begin
206
+ # 创建helper实例以使用基类方法
207
+ helper = self.new
208
+ main_module = helper.get_main_module(project_dir)
209
+
210
+ if main_module.nil?
211
+ ["app", "application", "main"].each do |module_name|
212
+ module_path = File.join(project_dir, module_name)
213
+ if File.exist?(File.join(module_path, "build.gradle")) ||
214
+ File.exist?(File.join(module_path, "build.gradle.kts"))
215
+ main_module = module_path
216
+ break
217
+ end
218
+ end
219
+ end
220
+
221
+ return false if main_module.nil?
222
+
223
+ # 查找build.gradle或build.gradle.kts文件
224
+ gradle_file = nil
225
+ if File.exist?(File.join(main_module, "build.gradle"))
226
+ gradle_file = File.join(main_module, "build.gradle")
227
+ elsif File.exist?(File.join(main_module, "build.gradle.kts"))
228
+ gradle_file = File.join(main_module, "build.gradle.kts")
229
+ end
230
+
231
+ return false if gradle_file.nil?
232
+
233
+ # 读取并更新gradle文件
234
+ content = File.read(gradle_file)
235
+
236
+ # 更新applicationId
237
+ if content =~ /applicationId\s+["'][^"']*["']/
238
+ content.gsub!(/applicationId\s+["'][^"']*["']/, "applicationId \"#{application_id}\"")
239
+ elsif content =~ /applicationId\s*=\s*["'][^"']*["']/
240
+ content.gsub!(/applicationId\s*=\s*["'][^"']*["']/, "applicationId = \"#{application_id}\"")
241
+ else
242
+ Funlog.instance.fancyinfo_error("gradle文件中未找到applicationId字段")
243
+ return false
244
+ end
245
+
246
+ File.write(gradle_file, content)
247
+ puts " ✓ Application ID 已更新为: #{application_id} (来自: #{package_name})"
248
+ return true
249
+
250
+ rescue StandardError => e
251
+ Funlog.instance.fancyinfo_error("更新Application ID失败: #{e.message}")
252
+ return false
253
+ end
254
+ end
255
+
256
+ # 使用package_name添加Android Scheme
257
+ # @param project_dir [String] Android项目目录路径
258
+ # @param package_name [String] 工作流的package_name(如:"Test Demo")
259
+ # @return [Boolean] 是否成功添加
260
+ def self.add_scheme_packagename(project_dir: nil, package_name: nil)
261
+ raise ArgumentError, "项目目录不能为空" if project_dir.nil?
262
+ raise ArgumentError, "Package Name不能为空" if package_name.nil?
263
+
264
+ # 从 package_name 生成 scheme(去除特殊字符,转小写)
265
+ scheme_name = package_name.to_s.gsub(/[^a-zA-Z0-9]/, '').downcase
266
+
267
+ # 调用现有的 add_test_scheme 方法
268
+ result = add_test_scheme(project_dir: project_dir, scheme_name: scheme_name)
269
+
270
+ if result
271
+ puts " ✓ 已添加Scheme: #{scheme_name} (来自: #{package_name})"
272
+ end
273
+
274
+ return result
275
+ end
276
+
137
277
  # 添加测试scheme到Android工程
138
278
  # @param project_dir [String] Android项目目录路径
139
279
  # @param scheme_name [String] 要添加的scheme名称
@@ -89,7 +89,7 @@ module Pindo
89
89
 
90
90
  # 检查并确保 Java 版本符合要求 (Java 11+)
91
91
  def ensure_java_version_compliance
92
- puts "\e[36m=== Java 版本检测 ===\e[0m"
92
+ # puts "\e[36m=== Java 版本检测 ===\e[0m"
93
93
 
94
94
  # 检查 Unity Editor 中的 JDK 版本(仅检测,不自动替换)
95
95
  # if check_and_update_unity_jdk
@@ -99,7 +99,7 @@ module Pindo
99
99
  # 仅检测Unity Editor JDK版本,不进行替换
100
100
  unity_root_paths = find_unity_editor_paths
101
101
  if unity_root_paths.any?
102
- puts "\e[36m=== Unity Editor JDK 版本检测 ===\e[0m"
102
+ # puts "\e[36m=== Unity Editor JDK 版本检测 ===\e[0m"
103
103
  unity_root_paths.each do |unity_root|
104
104
  # 构建JDK路径
105
105
  jdk_path = build_jdk_path_from_unity_root(unity_root)
@@ -112,7 +112,7 @@ module Pindo
112
112
  if version_output =~ /version "(\d+)/
113
113
  major_version = $1.to_i
114
114
  if major_version >= 11
115
- puts "\e[32m✓ Unity Editor JDK 版本 #{major_version} 符合要求: #{jdk_path}\e[0m"
115
+ # puts "\e[32m✓ Unity Editor JDK 版本 #{major_version} 符合要求: #{jdk_path}\e[0m"
116
116
  else
117
117
  puts "\e[33m⚠ Unity Editor JDK 版本 #{major_version} 不符合要求 (需要 Java 11+): #{jdk_path}\e[0m"
118
118
  end
@@ -132,14 +132,14 @@ module Pindo
132
132
 
133
133
  # 查找当前可用的 Java 命令
134
134
  current_java = find_java_command
135
- puts "当前 Java 命令: #{current_java}"
135
+ # puts "当前 Java 命令: #{current_java}"
136
136
 
137
137
  # 验证当前 Java 版本
138
138
  if verify_java_version(current_java)
139
139
  version_output = `"#{current_java}" -version 2>&1`
140
140
  if version_output =~ /version "(\d+)/
141
141
  major_version = $1.to_i
142
- puts "\e[32m✓ Java 版本 #{major_version} 符合要求 (需要 Java 11+)\e[0m"
142
+ # puts "\e[32m✓ Java 版本 #{major_version} 符合要求 (需要 Java 11+)\e[0m"
143
143
  return true
144
144
  end
145
145
  end
@@ -11,7 +11,8 @@ module Pindo
11
11
  class ComplianceResult
12
12
  attr_accessor :target_sdk_compliant, :target_sdk_version, :elf_alignment_compliant,
13
13
  :unaligned_libs, :total_libs, :compliance_issues, :warnings,
14
- :size_compliant, :aab_size_mb, :base_size_mb, :base_percent
14
+ :size_compliant, :aab_size_mb, :base_size_mb, :base_percent,
15
+ :unity_patch_compliant, :unity_xrsdk_patched, :unity_override_patched
15
16
 
16
17
  def initialize
17
18
  @target_sdk_compliant = false
@@ -25,10 +26,13 @@ module Pindo
25
26
  @aab_size_mb = 0
26
27
  @base_size_mb = 0
27
28
  @base_percent = 0
29
+ @unity_patch_compliant = false
30
+ @unity_xrsdk_patched = false
31
+ @unity_override_patched = false
28
32
  end
29
33
 
30
34
  def compliant?
31
- @target_sdk_compliant && @elf_alignment_compliant && @size_compliant
35
+ @target_sdk_compliant && @elf_alignment_compliant && @size_compliant && @unity_patch_compliant
32
36
  end
33
37
 
34
38
  def add_issue(issue)
@@ -79,6 +83,9 @@ module Pindo
79
83
  # 检测 ELF 对齐
80
84
  check_elf_alignment_compliance(temp_dir, result)
81
85
 
86
+ # 检测 Unity 漏洞修复
87
+ check_unity_patch_compliance(temp_dir, result)
88
+
82
89
  # 输出检测结果
83
90
  print_compliance_summary(result)
84
91
 
@@ -643,6 +650,15 @@ module Pindo
643
650
  puts "\e[31m✗ ELF 对齐: 发现 #{result.unaligned_libs.length} 个未对齐的共享库\e[0m"
644
651
  end
645
652
 
653
+ # Unity 漏洞检测结果
654
+ if result.unity_patch_compliant
655
+ puts "\e[32m✓ Unity 漏洞修复: 已正确应用 Unity 漏洞修复\e[0m"
656
+ elsif result.unity_xrsdk_patched || result.unity_override_patched
657
+ puts "\e[33m⚠ Unity 漏洞修复: 部分漏洞修复已应用,但可能不完整\e[0m"
658
+ else
659
+ puts "\e[31m✗ Unity 漏洞修复: 未检测到 Unity 漏洞修复或修复不完整\e[0m"
660
+ end
661
+
646
662
  # 总体合规状态
647
663
  puts "\n\e[1m--- 总体合规状态 ---\e[0m"
648
664
  if result.compliant?
@@ -664,5 +680,284 @@ module Pindo
664
680
 
665
681
  puts "================================"
666
682
  end
683
+
684
+ # 检测 Unity 漏洞合规性
685
+ def self.check_unity_patch_compliance(temp_dir, result)
686
+ puts "\n\e[1m--- Unity 漏洞检测 ---\e[0m"
687
+
688
+ # 检查是否存在 Unity 相关文件
689
+ unity_files = find_unity_files(temp_dir)
690
+
691
+ if unity_files.empty?
692
+ puts "\e[36m信息: 未检测到 Unity 相关文件,跳过 Unity 漏洞检测\e[0m"
693
+ result.unity_patch_compliant = true
694
+ return
695
+ end
696
+
697
+ puts "检测到 Unity 项目,开始检查漏洞修复..."
698
+
699
+ # 检查 libunity.so 文件
700
+ libunity_result = check_libunity_patch(temp_dir)
701
+
702
+ # 检查 boot.config 文件
703
+ boot_config_result = check_boot_config_patch(temp_dir)
704
+
705
+ # 综合判断
706
+ if libunity_result && boot_config_result
707
+ result.unity_patch_compliant = true
708
+ result.unity_xrsdk_patched = true
709
+ result.unity_override_patched = true
710
+ puts "\e[32m✓ Unity 漏洞检测: 通过\e[0m"
711
+ else
712
+ result.unity_patch_compliant = false
713
+ if !libunity_result
714
+ result.add_issue("Unity libunity.so 漏洞未修复")
715
+ end
716
+ if !boot_config_result
717
+ result.add_issue("Unity boot.config 漏洞未修复")
718
+ end
719
+ puts "\e[31m✗ Unity 漏洞检测: 未通过\e[0m"
720
+ end
721
+ end
722
+
723
+ # 查找 Unity 相关文件
724
+ def self.find_unity_files(temp_dir)
725
+ unity_files = []
726
+
727
+ # 查找 libunity.so 文件
728
+ lib_dirs = [
729
+ "#{temp_dir}/lib",
730
+ "#{temp_dir}/libs",
731
+ "#{temp_dir}/base/lib", # AAB文件结构
732
+ "#{temp_dir}/base/libs" # AAB文件结构
733
+ ]
734
+ lib_dirs.each do |lib_dir|
735
+ if Dir.exist?(lib_dir)
736
+ found_so_files = Dir.glob("#{lib_dir}/**/libunity.so")
737
+ unity_files += found_so_files
738
+ end
739
+ end
740
+
741
+ # 查找 boot.config 文件
742
+ boot_config_paths = [
743
+ "#{temp_dir}/assets/bin/Data/boot.config",
744
+ "#{temp_dir}/base/assets/bin/Data/boot.config",
745
+ "#{temp_dir}/base/bin/Data/boot.config"
746
+ ]
747
+
748
+ boot_config_paths.each do |path|
749
+ if File.exist?(path)
750
+ unity_files << path
751
+ break
752
+ end
753
+ end
754
+
755
+ unity_files
756
+ end
757
+
758
+ # 检查是否使用 il2cpp
759
+ def self.uses_il2cpp?(temp_dir)
760
+ # 检查是否存在 libil2cpp.so 文件
761
+ lib_dirs = [
762
+ "#{temp_dir}/lib",
763
+ "#{temp_dir}/libs",
764
+ "#{temp_dir}/base/lib", # AAB文件结构
765
+ "#{temp_dir}/base/libs" # AAB文件结构
766
+ ]
767
+
768
+ lib_dirs.each do |lib_dir|
769
+ if Dir.exist?(lib_dir)
770
+ il2cpp_files = Dir.glob("#{lib_dir}/**/libil2cpp.so")
771
+ return true if il2cpp_files.any?
772
+ end
773
+ end
774
+
775
+ false
776
+ end
777
+
778
+ # 检查 libunity.so 漏洞修复
779
+ def self.check_libunity_patch(temp_dir)
780
+ lib_dirs = [
781
+ "#{temp_dir}/lib",
782
+ "#{temp_dir}/libs",
783
+ "#{temp_dir}/base/lib", # AAB文件结构
784
+ "#{temp_dir}/base/libs" # AAB文件结构
785
+ ]
786
+ xrsdk_changed = false
787
+ override_disabled = false
788
+ override_found = false
789
+ uses_il2cpp = uses_il2cpp?(temp_dir)
790
+
791
+ lib_dirs.each do |lib_dir|
792
+ next unless Dir.exist?(lib_dir)
793
+
794
+ libunity_files = Dir.glob("#{lib_dir}/**/libunity.so")
795
+
796
+ libunity_files.each do |so_file|
797
+ puts "检查文件: #{File.basename(so_file)}"
798
+
799
+ # 检查 xrsdk 字符串修改
800
+ if check_xrsdk_patch(so_file)
801
+ xrsdk_changed = true
802
+ puts " \e[32m✓ xrsdk-pre-init-library 字符串已正确修改\e[0m"
803
+ else
804
+ puts " \e[31m✗ xrsdk-pre-init-library 字符串未正确修改\e[0m"
805
+ end
806
+
807
+ # 检查 overrideMonoSearchPath 禁用(仅在使用 Mono 时检查)
808
+ if uses_il2cpp
809
+ puts " \e[36m信息: 使用 IL2CPP,跳过 overrideMonoSearchPath 检测\e[0m"
810
+ override_disabled = true # IL2CPP 不需要检查 overrideMonoSearchPath
811
+ else
812
+ override_result = check_override_patch(so_file)
813
+ if override_result[:found]
814
+ override_found = true
815
+ if override_result[:disabled]
816
+ override_disabled = true
817
+ puts " \e[32m✓ overrideMonoSearchPath 已正确禁用\e[0m"
818
+ else
819
+ puts " \e[31m✗ overrideMonoSearchPath 未正确禁用\e[0m"
820
+ end
821
+ else
822
+ puts " \e[36m信息: 未找到 overrideMonoSearchPath 字符串\e[0m"
823
+ end
824
+ end
825
+ end
826
+ end
827
+
828
+ # 如果没有找到 overrideMonoSearchPath 或使用 IL2CPP,认为是正常的
829
+ if !override_found || uses_il2cpp
830
+ override_disabled = true
831
+ end
832
+
833
+ xrsdk_changed && override_disabled
834
+ end
835
+
836
+ # 检查 xrsdk 字符串修补
837
+ def self.check_xrsdk_patch(so_file)
838
+ # 检查是否还存在原始的 xrsdk 字符串
839
+ has_original = false
840
+ has_modified = false
841
+
842
+ begin
843
+ # 使用 strings 命令检查文件内容
844
+ strings_output = `strings "#{so_file}" 2>/dev/null`
845
+
846
+ if strings_output.include?("xrsdk-pre-init-library")
847
+ has_original = true
848
+ end
849
+
850
+ if strings_output.include?("8rsdk-pre-init-library")
851
+ has_modified = true
852
+ end
853
+
854
+ # 如果存在修改后的字符串且不存在原始字符串,说明修补成功
855
+ has_modified && !has_original
856
+
857
+ rescue => e
858
+ puts " \e[33m警告: 检查 #{so_file} 时出错: #{e.message}\e[0m"
859
+ false
860
+ end
861
+ end
862
+
863
+ # 检查 overrideMonoSearchPath 禁用
864
+ def self.check_override_patch(so_file)
865
+ result = { found: false, disabled: false }
866
+
867
+ begin
868
+ # 读取文件内容
869
+ file_content = File.binread(so_file)
870
+
871
+ # 查找 overrideMonoSearchPath 字符串
872
+ override_pattern = "overrideMonoSearchPath"
873
+ pattern_pos = file_content.index(override_pattern)
874
+
875
+ if pattern_pos
876
+ result[:found] = true
877
+
878
+ # 检查字符串前一个字节是否为 0xC0
879
+ if pattern_pos > 0
880
+ prev_byte = file_content[pattern_pos - 1].ord
881
+ if prev_byte == 0xC0
882
+ result[:disabled] = true
883
+ end
884
+ end
885
+ end
886
+
887
+ rescue => e
888
+ puts " \e[33m警告: 检查 #{so_file} 时出错: #{e.message}\e[0m"
889
+ end
890
+
891
+ result
892
+ end
893
+
894
+ # 检查 boot.config 漏洞修复
895
+ def self.check_boot_config_patch(temp_dir)
896
+ # 尝试多个可能的boot.config路径
897
+ boot_config_paths = [
898
+ "#{temp_dir}/assets/bin/Data/boot.config", # 标准APK路径
899
+ "#{temp_dir}/base/assets/bin/Data/boot.config", # AAB base模块路径
900
+ "#{temp_dir}/base/bin/Data/boot.config" # AAB简化路径
901
+ ]
902
+
903
+ boot_config_path = nil
904
+ boot_config_paths.each do |path|
905
+ if File.exist?(path)
906
+ boot_config_path = path
907
+ break
908
+ end
909
+ end
910
+
911
+ unless boot_config_path
912
+ puts " \e[33m信息: 未找到 boot.config 文件\e[0m"
913
+ return true # 没有 boot.config 文件,认为是正常的
914
+ end
915
+
916
+ puts "检查文件: #{File.basename(boot_config_path)}"
917
+
918
+ begin
919
+ content = File.read(boot_config_path)
920
+
921
+ # 检查是否存在未修改的字符串
922
+ original_count = content.scan(/xrsdk-pre-init-library/).length
923
+ modified_count = content.scan(/8rsdk-pre-init-library/).length
924
+
925
+ if original_count > 0
926
+ puts " \e[31m✗ boot.config 中仍存在 #{original_count} 个未修改的 xrsdk-pre-init-library\e[0m"
927
+ end
928
+
929
+ if modified_count > 0
930
+ puts " \e[32m✓ boot.config 中发现 #{modified_count} 个修改后的 8rsdk-pre-init-library\e[0m"
931
+ end
932
+
933
+ # 检查是否还有其他 xrsdk 相关字符串
934
+ other_xrsdk_count = content.scan(/xrsdk/).length
935
+ if other_xrsdk_count > 0
936
+ puts " \e[36m信息: boot.config 中发现 #{other_xrsdk_count} 个其他 xrsdk 相关字符串\e[0m"
937
+ end
938
+
939
+ # 如果没有 xrsdk 相关字符串,认为是正常的
940
+ if other_xrsdk_count == 0
941
+ puts " \e[32m✓ boot.config 检查结果: 通过(未使用 XR SDK,无需修补)\e[0m"
942
+ return true
943
+ end
944
+
945
+ # 如果存在修改后的字符串且不存在未修改的字符串,说明修补成功
946
+ if modified_count > 0 && original_count == 0
947
+ puts " \e[32m✓ boot.config 检查结果: 通过(已正确替换 #{modified_count} 个字符串)\e[0m"
948
+ return true
949
+ elsif original_count > 0
950
+ puts " \e[31m✗ boot.config 检查结果: 未通过(存在未修改的字符串)\e[0m"
951
+ return false
952
+ else
953
+ puts " \e[31m✗ boot.config 检查结果: 未通过(未找到修改后的字符串)\e[0m"
954
+ return false
955
+ end
956
+
957
+ rescue => e
958
+ puts " \e[33m警告: 检查 boot.config 时出错: #{e.message}\e[0m"
959
+ false
960
+ end
961
+ end
667
962
  end
668
963
  end