cocoapods-privacy 0.5.3 → 0.6.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.
- checksums.yaml +4 -4
- data/README.md +7 -1
- data/lib/cocoapods-privacy/command/confuse/spec.rb +34 -0
- data/lib/cocoapods-privacy/command/install.rb +38 -5
- data/lib/cocoapods-privacy/command/privacy/config.rb +2 -2
- data/lib/cocoapods-privacy/command.rb +17 -2
- data/lib/cocoapods-privacy/common/BBSpec.rb +234 -0
- data/lib/cocoapods-privacy/common/BBSpecManager.rb +166 -0
- data/lib/cocoapods-privacy/common/config.rb +69 -0
- data/lib/cocoapods-privacy/confuse/ConfuseHunter.rb +506 -0
- data/lib/cocoapods-privacy/confuse/ConfuseModule.rb +150 -0
- data/lib/cocoapods-privacy/confuse/ConfuseUtils.rb +107 -0
- data/lib/cocoapods-privacy/confuse/ObjCMethodAPIConverter.rb +194 -0
- data/lib/cocoapods-privacy/confuse/SwiftCallAssembly.rb +24 -0
- data/lib/cocoapods-privacy/confuse/confuse_installer_hook.rb +290 -0
- data/lib/cocoapods-privacy/confuse/confuse_specification_hook.rb +56 -0
- data/lib/cocoapods-privacy/gem_version.rb +1 -1
- data/lib/cocoapods-privacy/privacy/PrivacyHunter.rb +1 -1
- data/lib/cocoapods-privacy/privacy/PrivacyModule.rb +2 -338
- data/lib/cocoapods-privacy/privacy/PrivacyUtils.rb +5 -13
- data/lib/cocoapods-privacy/privacy/privacy_installer_hook.rb +0 -1
- data/lib/cocoapods-privacy/privacy/privacy_specification_hook.rb +4 -1
- metadata +14 -4
- data/lib/cocoapods-privacy/privacy/PrivacyConfig.rb +0 -28
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'digest'
|
2
|
+
require 'cocoapods-privacy/command'
|
3
|
+
|
4
|
+
module ConfuseUtils
|
5
|
+
|
6
|
+
def self.confuse_name
|
7
|
+
"bb_c_o_f_u_s_e.h"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.confuse_pch_name
|
11
|
+
"bb_pre_head_cf.pch"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.confuse_folder
|
15
|
+
"Confuse"
|
16
|
+
end
|
17
|
+
|
18
|
+
# xcode工程地址
|
19
|
+
def self.project_path
|
20
|
+
matching_files = Dir[File.join(Pathname.pwd, '*.xcodeproj')].uniq
|
21
|
+
puts "matching_files = #{matching_files}"
|
22
|
+
matching_files.first
|
23
|
+
end
|
24
|
+
|
25
|
+
# xcode工程地址
|
26
|
+
def self.project_name
|
27
|
+
projectPath = project_path
|
28
|
+
File.basename(projectPath, File.extname(projectPath))
|
29
|
+
end
|
30
|
+
|
31
|
+
# xcode工程主代码目录
|
32
|
+
def self.project_code_fold
|
33
|
+
File.join(Pathname.pwd,project_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.cache_privacy_fold
|
37
|
+
Common::Config.instance.cache_privacy_fold
|
38
|
+
end
|
39
|
+
|
40
|
+
# config.json 文件
|
41
|
+
def self.cache_config_file
|
42
|
+
Common::Config.instance.cache_config_file
|
43
|
+
end
|
44
|
+
|
45
|
+
# 创建默认混淆文件
|
46
|
+
def self.create_confuse_if_empty(file_path,file_content = nil)
|
47
|
+
isCreate = create_file_and_fold_if_no_exit(file_path,file_content)
|
48
|
+
if isCreate
|
49
|
+
puts "【混淆】(初始化)存放地址 => #{file_path}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.confuse_content(defines = nil,name = confuse_name)
|
54
|
+
defines_content = defines.nil? ? '' : defines
|
55
|
+
|
56
|
+
# 文件内容
|
57
|
+
<<~EOS
|
58
|
+
#ifndef #{name.tr('.', '_').upcase}
|
59
|
+
#define #{name.tr('.', '_').upcase}
|
60
|
+
#{defines_content}
|
61
|
+
#endif
|
62
|
+
EOS
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def self.confuse_pch_content()
|
67
|
+
# 文件内容
|
68
|
+
<<~EOS
|
69
|
+
#ifndef #{confuse_pch_name.tr('.', '_').upcase}
|
70
|
+
#define #{confuse_pch_name.tr('.', '_').upcase}
|
71
|
+
#import "#{confuse_name}"
|
72
|
+
#endif
|
73
|
+
EOS
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
# 创建文件,并写入默认值,文件路径不存在会自动创建
|
78
|
+
def self.create_file_and_fold_if_no_exit(file_path,file_content = nil)
|
79
|
+
folder_path = File.dirname(file_path)
|
80
|
+
FileUtils.mkdir_p(folder_path) unless File.directory?(folder_path)
|
81
|
+
|
82
|
+
# 创建文件(如果不存在/或为空)
|
83
|
+
if !File.exist?(file_path) || File.zero?(file_path)
|
84
|
+
File.open(file_path, 'w') do |file|
|
85
|
+
file.write(file_content)
|
86
|
+
end
|
87
|
+
return true
|
88
|
+
end
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
# 使用正则表达式匹配第一个字符前的空格数量
|
95
|
+
def self.count_spaces_before_first_character(str)
|
96
|
+
match = str.match(/\A\s*/)
|
97
|
+
match ? match[0].length : 0
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
# 使用字符串乘法添加指定数量的空格
|
102
|
+
def self.add_spaces_to_string(str, num_spaces)
|
103
|
+
spaces = ' ' * num_spaces
|
104
|
+
"#{spaces}#{str}"
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
@@ -0,0 +1,194 @@
|
|
1
|
+
|
2
|
+
module Confuse
|
3
|
+
class ObjCMethodAPIConverter
|
4
|
+
# Regular expression to match Objective-C method declarations
|
5
|
+
# def initialize
|
6
|
+
@regex = /^[+-]\s*\(\s*([\w\s*]+)\s*\**\s*\)\s*(.+)/
|
7
|
+
@param_regex = /(\w+):\s*\(([^:]+)\)(\w+)/x
|
8
|
+
# end
|
9
|
+
|
10
|
+
# Convert an Objective-C method declaration to a Swift method declaration
|
11
|
+
def self.convert(objc_method_declaration)
|
12
|
+
# puts "objc_method_declaration = #{objc_method_declaration}"
|
13
|
+
# Skip methods containing blocks
|
14
|
+
# return nil if objc_method_declaration.include?("^")
|
15
|
+
|
16
|
+
is_static = objc_method_declaration.start_with?("+")
|
17
|
+
preFuncDes = is_static ? "static " : ""
|
18
|
+
|
19
|
+
|
20
|
+
# Match the method declaration using the regex
|
21
|
+
matches = objc_method_declaration.match(@regex)
|
22
|
+
return nil,nil unless matches
|
23
|
+
|
24
|
+
# Extract components from the matched regex groups
|
25
|
+
return_type = matches[1] || "Void"
|
26
|
+
param_section = matches[2] || ""
|
27
|
+
method_name = matches[2]
|
28
|
+
# puts "return_type = #{return_type}"
|
29
|
+
# puts "param_section = #{param_section}"
|
30
|
+
# puts "method_name = #{method_name}"
|
31
|
+
|
32
|
+
# Convert return type to Swift equivalent
|
33
|
+
return_type = convert_oc_type_to_swift(return_type)
|
34
|
+
|
35
|
+
# Extract parameters from the method declaration
|
36
|
+
params = extract_parameters(param_section)
|
37
|
+
method_name = extract_methodName(param_section,method_name)
|
38
|
+
# puts "params = #{params}"
|
39
|
+
|
40
|
+
# Construct the Swift method declaration
|
41
|
+
swift_method_declaration = "#{preFuncDes}public func #{method_name}(#{params.join(', ')})"
|
42
|
+
swift_method_declaration += " -> #{return_type}" unless return_type == "Void"
|
43
|
+
|
44
|
+
return swift_method_declaration, extract_parameter_names(param_section)
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
# Convert the Objective-C return type to a Swift type
|
50
|
+
def self.convert_oc_type_to_swift(return_type)
|
51
|
+
# 去除类型末尾的指针符号和周围空格,生成基础类型名
|
52
|
+
# base_type = return_type.gsub(/\s*\*+$/, '').strip
|
53
|
+
base_type = return_type.gsub(/(\w+)\s*\*+\z/, '\1').strip
|
54
|
+
# base_type = return_type
|
55
|
+
# puts "base_type = #{return_type}"
|
56
|
+
|
57
|
+
case base_type
|
58
|
+
# Foundation 基础类型
|
59
|
+
when "NSString" then "String"
|
60
|
+
when "NSMutableString" then "String" # Swift 中 String 是值类型
|
61
|
+
when "NSArray" then "Array<Any>"
|
62
|
+
when "NSMutableArray" then "Array<Any>"
|
63
|
+
when "NSSet" then "Set<Any>"
|
64
|
+
when "NSMutableSet" then "Set<Any>"
|
65
|
+
when "NSDictionary" then "Dictionary<AnyHashable, Any>"
|
66
|
+
when "NSMutableDictionary" then "Dictionary<AnyHashable, Any>"
|
67
|
+
when "NSError" then "Error?"
|
68
|
+
when "NSURL" then "URL"
|
69
|
+
when "NSData" then "Data"
|
70
|
+
when "NSNumber" then "NSNumber" # 特殊处理需要结合实际数值类型
|
71
|
+
when "NSDate" then "Date"
|
72
|
+
|
73
|
+
# 基础数值类型
|
74
|
+
when "NSInteger" then "Int"
|
75
|
+
when "NSUInteger" then "UInt"
|
76
|
+
when "CGFloat" then "CGFloat"
|
77
|
+
when "CGPoint" then "CGPoint"
|
78
|
+
when "CGRect" then "CGRect"
|
79
|
+
when "CGSize" then "CGSize"
|
80
|
+
when "BOOL" then "Bool"
|
81
|
+
when "Boolean" then "Bool"
|
82
|
+
when "double" then "Double"
|
83
|
+
when "float" then "Float"
|
84
|
+
when "long" then "Int"
|
85
|
+
when "long long" then "Int64"
|
86
|
+
|
87
|
+
|
88
|
+
# 特殊类型
|
89
|
+
when "id" then "Any"
|
90
|
+
when "Class" then "AnyClass"
|
91
|
+
when "SEL" then "Selector"
|
92
|
+
when "Protocol" then "Protocol"
|
93
|
+
when "instancetype" then "Self"
|
94
|
+
when "void" then "Void"
|
95
|
+
|
96
|
+
# # # 函数指针/Block 类型(需二次处理)
|
97
|
+
# when /void\s*\(\^\)/ then convert_block_to_closure(return_type)
|
98
|
+
# when /(.+?)\s*\(\^\)/ then convert_block_to_closure(return_type)
|
99
|
+
|
100
|
+
# # 指针类型保留原始表示
|
101
|
+
# when /(.+?\s*\*+)/ then return_type
|
102
|
+
|
103
|
+
else
|
104
|
+
# # 处理Block类型
|
105
|
+
if return_type.match(/^\s*(?:void|.+?)\s*\(\^\)/)
|
106
|
+
convert_block_to_closure(return_type)
|
107
|
+
# 处理其他指针类型(去掉指针符号后返回基础类型名)
|
108
|
+
elsif return_type.include?('*')
|
109
|
+
base_type
|
110
|
+
else
|
111
|
+
# 默认保留原类型
|
112
|
+
return_type
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
# Extract parameters from the parameter section
|
118
|
+
def self.extract_parameters(param_section)
|
119
|
+
params = []
|
120
|
+
param_section.scan(@param_regex).each_with_index do |param_info, index|
|
121
|
+
# puts "param_info = #{param_info}"
|
122
|
+
param_define, param_type, param_name = param_info
|
123
|
+
param_type = convert_oc_type_to_swift(param_type.strip)
|
124
|
+
if index == 0
|
125
|
+
params << "#{param_name}: #{param_type}"
|
126
|
+
else
|
127
|
+
params << "#{param_define}: #{param_type}"
|
128
|
+
end
|
129
|
+
end
|
130
|
+
params
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.extract_parameter_names(param_section)
|
134
|
+
names = []
|
135
|
+
param_section.scan(@param_regex).each_with_index do |param_info, index|
|
136
|
+
param_define, param_type, param_name = param_info
|
137
|
+
if index == 0
|
138
|
+
names << param_name
|
139
|
+
else
|
140
|
+
names << param_define
|
141
|
+
end
|
142
|
+
end
|
143
|
+
names
|
144
|
+
end
|
145
|
+
|
146
|
+
|
147
|
+
def self.extract_methodName(param_section, defalut_method_name)
|
148
|
+
method_name = defalut_method_name
|
149
|
+
param_section.scan(@param_regex).each_with_index do |param_info, index|
|
150
|
+
param_define, param_type, param_name = param_info
|
151
|
+
if index == 0
|
152
|
+
method_name = param_define
|
153
|
+
break
|
154
|
+
end
|
155
|
+
end
|
156
|
+
method_name
|
157
|
+
end
|
158
|
+
|
159
|
+
|
160
|
+
# # 测试用例
|
161
|
+
# puts convert_block_to_closure('void (^)()') # 输出: () -> Void
|
162
|
+
# puts convert_block_to_closure('NSInteger (^)(BOOL)') # 输出: (Bool) -> Int
|
163
|
+
# puts convert_block_to_closure('NSString *(^)(NSInteger)') # 输出: (Int) -> String?
|
164
|
+
# puts convert_block_to_closure('void (^)(NSInteger, BOOL)') # 输出: (Int, Bool) -> Void
|
165
|
+
def self.convert_block_to_closure(block_signature)
|
166
|
+
|
167
|
+
# 正则表达式解释:
|
168
|
+
# ^([\w\s\*]+)\s*\(\^\)\s*(?:\((.*?)\))?\s*$
|
169
|
+
# 1. ([\w\s\*]+): 捕获返回值类型(如 void、NSInteger、NSString * 等)。
|
170
|
+
# 2. \(\^\): 匹配 '^' 表示这是一个 block。
|
171
|
+
# 3. (?:\((.*?)\))? : 可选地捕获参数列表(括号中的内容)。
|
172
|
+
if block_signature =~ /^([\w\s\*]+)\s*\(\^\)\s*(?:\((.*?)\))?\s*$/
|
173
|
+
return_type = $1.strip
|
174
|
+
params = $2 ? $2.split(',').map(&:strip) : []
|
175
|
+
|
176
|
+
# 转换返回值类型
|
177
|
+
swift_return_type = convert_oc_type_to_swift(return_type)
|
178
|
+
|
179
|
+
# 转换参数类型
|
180
|
+
swift_params = params.map do |param|
|
181
|
+
param_parts = param.split(' ')
|
182
|
+
param_type =convert_oc_type_to_swift(param_parts.first)
|
183
|
+
"#{param_type}"
|
184
|
+
end.join(", ").gsub("Void","")
|
185
|
+
|
186
|
+
# 构造最终的 Swift 闭包类型
|
187
|
+
result = "@escaping (#{swift_params}) -> #{swift_return_type}"
|
188
|
+
else
|
189
|
+
raise ArgumentError, "Invalid block signature: #{block_signature}"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Confuse
|
2
|
+
class SwiftCallAssembly
|
3
|
+
|
4
|
+
#method_confuse 用来替换掉函数名 儒 BB_Confuse_asdasfas
|
5
|
+
#swift 完整函数 如 @objc public func calculateAreaWithWidth(width: (Bool, String) -> Void, height: CGFloat) -> CGFloat
|
6
|
+
#params 参数名数组 width, height
|
7
|
+
def self.assembly(method_confuse,swift_method_declaration,params)
|
8
|
+
is_return = true
|
9
|
+
is_static = swift_method_declaration.start_with?("static")
|
10
|
+
caller = is_static ? "Self" : "self"
|
11
|
+
returnFlag = is_return ? "return " : ""
|
12
|
+
|
13
|
+
params = params.map.with_index do |param, index|
|
14
|
+
if index == 0
|
15
|
+
param
|
16
|
+
else
|
17
|
+
"#{param}: #{param}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
funcBody = "#{swift_method_declaration} {\n #{returnFlag}#{caller}.#{method_confuse}(#{params.join(', ')})\n}"
|
21
|
+
return funcBody
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require 'active_support/core_ext/string/inflections'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'cocoapods/podfile'
|
4
|
+
require 'cocoapods-privacy/command'
|
5
|
+
|
6
|
+
module Pod
|
7
|
+
# The Installer is responsible of taking a Podfile and transform it in the
|
8
|
+
# Pods libraries. It also integrates the user project so the Pods
|
9
|
+
# libraries can be used out of the box.
|
10
|
+
#
|
11
|
+
# The Installer is capable of doing incremental updates to an existing Pod
|
12
|
+
# installation.
|
13
|
+
#
|
14
|
+
# The Installer gets the information that it needs mainly from 3 files:
|
15
|
+
#
|
16
|
+
# - Podfile: The specification written by the user that contains
|
17
|
+
# information about targets and Pods.
|
18
|
+
# - Podfile.lock: Contains information about the pods that were previously
|
19
|
+
# installed and in concert with the Podfile provides information about
|
20
|
+
# which specific version of a Pod should be installed. This file is
|
21
|
+
# ignored in update mode.
|
22
|
+
# - Manifest.lock: A file contained in the Pods folder that keeps track of
|
23
|
+
# the pods installed in the local machine. This files is used once the
|
24
|
+
# exact versions of the Pods has been computed to detect if that version
|
25
|
+
# is already installed. This file is not intended to be kept under source
|
26
|
+
# control and is a copy of the Podfile.lock.
|
27
|
+
#
|
28
|
+
# The Installer is designed to work in environments where the Podfile folder
|
29
|
+
# is under source control and environments where it is not. The rest of the
|
30
|
+
# files, like the user project and the workspace are assumed to be under
|
31
|
+
# source control.
|
32
|
+
#
|
33
|
+
class Installer
|
34
|
+
autoload :Analyzer, 'cocoapods/installer/analyzer'
|
35
|
+
autoload :InstallationOptions, 'cocoapods/installer/installation_options'
|
36
|
+
autoload :PostInstallHooksContext, 'cocoapods/installer/post_install_hooks_context'
|
37
|
+
autoload :PreInstallHooksContext, 'cocoapods/installer/pre_install_hooks_context'
|
38
|
+
autoload :BaseInstallHooksContext, 'cocoapods/installer/base_install_hooks_context'
|
39
|
+
autoload :PostIntegrateHooksContext, 'cocoapods/installer/post_integrate_hooks_context'
|
40
|
+
autoload :PreIntegrateHooksContext, 'cocoapods/installer/pre_integrate_hooks_context'
|
41
|
+
autoload :SourceProviderHooksContext, 'cocoapods/installer/source_provider_hooks_context'
|
42
|
+
autoload :PodfileValidator, 'cocoapods/installer/podfile_validator'
|
43
|
+
autoload :PodSourceDownloader, 'cocoapods/installer/pod_source_downloader'
|
44
|
+
autoload :PodSourceInstaller, 'cocoapods/installer/pod_source_installer'
|
45
|
+
autoload :PodSourcePreparer, 'cocoapods/installer/pod_source_preparer'
|
46
|
+
autoload :UserProjectIntegrator, 'cocoapods/installer/user_project_integrator'
|
47
|
+
autoload :Xcode, 'cocoapods/installer/xcode'
|
48
|
+
autoload :SandboxHeaderPathsInstaller, 'cocoapods/installer/sandbox_header_paths_installer'
|
49
|
+
autoload :SandboxDirCleaner, 'cocoapods/installer/sandbox_dir_cleaner'
|
50
|
+
autoload :ProjectCache, 'cocoapods/installer/project_cache/project_cache'
|
51
|
+
autoload :TargetUUIDGenerator, 'cocoapods/installer/target_uuid_generator'
|
52
|
+
|
53
|
+
|
54
|
+
# 保hook post_install 方法
|
55
|
+
alias_method :bb_original_run_podfile_post_install_hook, :run_podfile_post_install_hook
|
56
|
+
def run_podfile_post_install_hook
|
57
|
+
bb_original_run_podfile_post_install_hook
|
58
|
+
confuse_pattern = Pod::Config.instance.confuse_pattern
|
59
|
+
# return if confuse_pattern.nil? || confuse_pattern.empty?
|
60
|
+
|
61
|
+
case confuse_pattern
|
62
|
+
when "enable"
|
63
|
+
enable_confuse()
|
64
|
+
when "disable"
|
65
|
+
disable_confuse()
|
66
|
+
else
|
67
|
+
#读取工程plistinfo 中的ISConfuse 配置
|
68
|
+
project_path = ConfuseUtils.project_path()
|
69
|
+
project = Xcodeproj::Project.open(File.basename(project_path))
|
70
|
+
target = project.targets.first
|
71
|
+
plist_path = target.resolved_build_setting('INFOPLIST_FILE', resolve_against: target).first.last
|
72
|
+
plist_path = File.join(File.dirname(project_path), plist_path)
|
73
|
+
plist = Plist.parse_xml(plist_path)
|
74
|
+
puts plist_path
|
75
|
+
|
76
|
+
unless plist.nil?
|
77
|
+
is_confuse = plist['ISConfuse']
|
78
|
+
if is_confuse.nil?
|
79
|
+
# 没有 --confuse 命令和 Info 配置, 不处理
|
80
|
+
elsif is_confuse == true
|
81
|
+
enable_confuse()
|
82
|
+
elsif is_confuse == false
|
83
|
+
disable_confuse()
|
84
|
+
else
|
85
|
+
puts "Invalid value for ISConfuse"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def enable_confuse
|
92
|
+
puts "[混淆]标识添加"
|
93
|
+
self.pod_target_subprojects.each do |p|
|
94
|
+
p.targets.each do |target|
|
95
|
+
target.build_configurations.each do |config|
|
96
|
+
|
97
|
+
# 获取关联的 xcconfig 文件
|
98
|
+
xcconfig_path = config.base_configuration_reference.real_path
|
99
|
+
xcconfig = File.read(xcconfig_path)
|
100
|
+
# puts "xcconfig = #{xcconfig}"
|
101
|
+
|
102
|
+
# 处理 GCC_PREPROCESSOR_DEFINITIONS,确保不重复添加
|
103
|
+
unless xcconfig.include?('BB_Confuse_Enable_Flag=1')
|
104
|
+
# 先查找 GCC_PREPROCESSOR_DEFINITIONS 部分,插入新的宏定义
|
105
|
+
if xcconfig.include?('GCC_PREPROCESSOR_DEFINITIONS')
|
106
|
+
xcconfig.gsub!(/GCC_PREPROCESSOR_DEFINITIONS\s*=\s*(.*?)(\n|$)/) do |match|
|
107
|
+
"#{match.gsub("\n", "")} BB_Confuse_Enable_Flag=1\n"
|
108
|
+
end
|
109
|
+
else
|
110
|
+
# 如果没有找到该行,直接追加到文件末尾
|
111
|
+
xcconfig << "\nGCC_PREPROCESSOR_DEFINITIONS = ${inherited} BB_Confuse_Enable_Flag=1\n"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# 处理 OTHER_SWIFT_FLAGS,确保不重复添加
|
116
|
+
unless xcconfig.include?('-D BB_Confuse_Enable_Flag')
|
117
|
+
# 先查找 OTHER_SWIFT_FLAGS 部分,插入新的编译条件
|
118
|
+
if xcconfig.include?('OTHER_SWIFT_FLAGS')
|
119
|
+
xcconfig.gsub!(/nOTHER_SWIFT_FLAGS\s*=\s*(.*?)(\n|$)/) do |match|
|
120
|
+
"#{match.gsub("\n", "")} -D BB_Confuse_Enable_Flag\n"
|
121
|
+
end
|
122
|
+
else
|
123
|
+
# 如果没有找到该行,直接追加到文件末尾
|
124
|
+
xcconfig << "\nOTHER_SWIFT_FLAGS = ${inherited} -D BB_Confuse_Enable_Flag\n"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
File.write(xcconfig_path, xcconfig)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
def disable_confuse
|
135
|
+
puts "[混淆]标识移除"
|
136
|
+
self.pod_target_subprojects.each do |p|
|
137
|
+
p.targets.each do |target|
|
138
|
+
target.build_configurations.each do |config|
|
139
|
+
# 获取关联的 xcconfig 文件
|
140
|
+
xcconfig_path = config.base_configuration_reference.real_path
|
141
|
+
xcconfig = File.read(xcconfig_path)
|
142
|
+
|
143
|
+
# 移除 GCC_PREPROCESSOR_DEFINITIONS 中的 BB_Confuse_Enable_Flag=1
|
144
|
+
if xcconfig.include?('BB_Confuse_Enable_Flag=1')
|
145
|
+
xcconfig.gsub!(/BB_Confuse_Enable_Flag=1/, '$(inherited)')
|
146
|
+
end
|
147
|
+
|
148
|
+
# 移除 OTHER_SWIFT_FLAGS 中的 -D BB_Confuse_Enable_Flag
|
149
|
+
if xcconfig.include?('-D BB_Confuse_Enable_Flag')
|
150
|
+
xcconfig.gsub!(/-D BB_Confuse_Enable_Flag/, '$(inherited)')
|
151
|
+
end
|
152
|
+
|
153
|
+
# 保存修改后的 xcconfig 文件
|
154
|
+
File.write(xcconfig_path, xcconfig)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
# private
|
162
|
+
# def get_subprojects(project)
|
163
|
+
# # 获取项目中所有文件引用(PBXFileReference)
|
164
|
+
# file_refs = project.objects.select { |obj| obj.isa == 'PBXFileReference' }
|
165
|
+
|
166
|
+
# # 筛选出以 .xcodeproj 结尾的引用路径
|
167
|
+
# subproject_refs = file_refs.select do |ref|
|
168
|
+
# ref.path.to_s.end_with?('.xcodeproj')
|
169
|
+
# end
|
170
|
+
|
171
|
+
# # 转换为实际 Project 对象(需加载)
|
172
|
+
# subproject_refs.map do |ref|
|
173
|
+
# subproject_path = File.expand_path(ref.path, project.project_dir)
|
174
|
+
# Xcodeproj::Project.open(subproject_path)
|
175
|
+
# end
|
176
|
+
# end
|
177
|
+
# def confuse_handle(custom_folds)
|
178
|
+
|
179
|
+
# lib.pod_target_subprojects.flat_map { |p| p.targets }.each do |target|
|
180
|
+
# target.build_configurations.each do |config|
|
181
|
+
# # 为 Objective-C 添加宏定义
|
182
|
+
# current_oc_defs = config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] || ['$(inherited)']
|
183
|
+
# new_oc_defs = current_oc_defs + ['BB_Confuse_Enable_Flag=1']
|
184
|
+
# config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = new_oc_defs.uniq
|
185
|
+
|
186
|
+
# # 为 Swift 添加编译条件
|
187
|
+
# current_swift_flags = config.build_settings['OTHER_SWIFT_FLAGS'] || ['$(inherited)']
|
188
|
+
# new_swift_flags = current_swift_flags + ['-D BB_Confuse_Enable_Flag']
|
189
|
+
# config.build_settings['OTHER_SWIFT_FLAGS'] = new_swift_flags.uniq
|
190
|
+
# end
|
191
|
+
# end
|
192
|
+
|
193
|
+
|
194
|
+
# puts "👇👇👇👇👇👇 Start analysis project confuse 👇👇👇👇👇👇"
|
195
|
+
# # 过滤出自身组件 && 自身没有隐私协议文件的spec
|
196
|
+
# modules = @analysis_result.specifications.select {
|
197
|
+
# |obj| obj.confuse_is_need_search_module
|
198
|
+
# }
|
199
|
+
|
200
|
+
# # 存储本地调试组件
|
201
|
+
# development_folds = []
|
202
|
+
# exclude_folds = []
|
203
|
+
|
204
|
+
# # 获取组件所在工程的pods 目录
|
205
|
+
# pod_folds = modules.map{ |spec|
|
206
|
+
# name = spec.name.split('/').first
|
207
|
+
|
208
|
+
# fold = File.join(@sandbox.root,name)
|
209
|
+
# podspec_file_path_develop = validate_development_pods(name)
|
210
|
+
# # 先验证是否是指向本地的组件(发现有的情况下 组件指向本地Pods 下依旧还是会有该组件,所以这里先判断本地的)
|
211
|
+
# if podspec_file_path_develop
|
212
|
+
# podspec_fold_path = File.dirname(podspec_file_path_develop)
|
213
|
+
# source_files = spec.attributes_hash['source_files']
|
214
|
+
# exclude_files = spec.attributes_hash['exclude_files']
|
215
|
+
# if source_files && !source_files.empty?
|
216
|
+
# if source_files.is_a?(String) && !source_files.empty?
|
217
|
+
# development_folds << File.join(podspec_fold_path,source_files)
|
218
|
+
# elsif source_files.is_a?(Array)
|
219
|
+
# source_files.each do |file|
|
220
|
+
# development_folds << File.join(podspec_fold_path,file)
|
221
|
+
# end
|
222
|
+
# end
|
223
|
+
|
224
|
+
# # 处理exclude_files 排除文件夹
|
225
|
+
# if exclude_files && !exclude_files.empty?
|
226
|
+
# if exclude_files.is_a?(String) && !exclude_files.empty?
|
227
|
+
# exclude_folds << File.join(podspec_fold_path,exclude_files)
|
228
|
+
# elsif exclude_files.is_a?(Array)
|
229
|
+
# exclude_files.each do |file|
|
230
|
+
# exclude_folds << File.join(podspec_fold_path,file)
|
231
|
+
# end
|
232
|
+
# end
|
233
|
+
# end
|
234
|
+
# end
|
235
|
+
# nil
|
236
|
+
# elsif Dir.exist?(fold)
|
237
|
+
# formatter_search_fold(fold)
|
238
|
+
# end
|
239
|
+
# }.compact
|
240
|
+
|
241
|
+
|
242
|
+
# pod_folds += development_folds # 拼接本地调试和远端的pod目录
|
243
|
+
# pod_folds += [formatter_search_fold(ConfuseUtils.project_code_fold)].compact # 拼接工程同名主目录
|
244
|
+
# pod_folds += custom_folds || [] # 拼接外部传入的自定义目录
|
245
|
+
# pod_folds = pod_folds.uniq # 去重
|
246
|
+
|
247
|
+
# if pod_folds.empty?
|
248
|
+
# puts "无组件或工程目录, 请检查工程"
|
249
|
+
# else
|
250
|
+
# # 处理工程混淆
|
251
|
+
# ConfuseModule.load_project(pod_folds,exclude_folds.uniq,self)
|
252
|
+
# end
|
253
|
+
# puts "👆👆👆👆👆👆 End analysis project confuse 👆👆👆👆👆👆"
|
254
|
+
# end
|
255
|
+
|
256
|
+
# private
|
257
|
+
# def formatter_search_fold(fold)
|
258
|
+
# File.join(fold,"**","*.{m,c,swift,mm,h,hap,hpp,cpp}")
|
259
|
+
# end
|
260
|
+
|
261
|
+
# def validate_development_pods(name)
|
262
|
+
# result = nil
|
263
|
+
# development_pods = @sandbox.development_pods
|
264
|
+
# if name && !name.empty? && development_pods && !development_pods.empty?
|
265
|
+
# podspec_file_path = development_pods[name]
|
266
|
+
# if podspec_file_path && !podspec_file_path.empty?
|
267
|
+
# result = podspec_file_path
|
268
|
+
# end
|
269
|
+
# end
|
270
|
+
# result
|
271
|
+
# end
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
# module Pod
|
276
|
+
# module CustomPlugin
|
277
|
+
# class << self
|
278
|
+
# def activate
|
279
|
+
# # 注册 post_install 钩子
|
280
|
+
# HooksManager.register('post_install', 'custom_plugin') do |installer_context|
|
281
|
+
# puts "Custom Plugin post_install hook triggered!"
|
282
|
+
|
283
|
+
# end
|
284
|
+
# end
|
285
|
+
# end
|
286
|
+
# end
|
287
|
+
# end
|
288
|
+
|
289
|
+
# # 激活插件
|
290
|
+
# Pod::CustomPlugin.activate
|
@@ -0,0 +1,56 @@
|
|
1
|
+
|
2
|
+
require 'cocoapods-core/specification/root_attribute_accessors'
|
3
|
+
require 'cocoapods-privacy/command'
|
4
|
+
|
5
|
+
module Pod
|
6
|
+
# The Specification provides a DSL to describe a Pod. A pod is defined as a
|
7
|
+
# library originating from a source. A specification can support detailed
|
8
|
+
# attributes for modules of code through subspecs.
|
9
|
+
#
|
10
|
+
# Usually it is stored in files with `podspec` extension.
|
11
|
+
#
|
12
|
+
class Specification
|
13
|
+
|
14
|
+
# 是否为需要检索组件
|
15
|
+
def confuse_is_need_search_module
|
16
|
+
unless File.exist?(ConfuseUtils.cache_config_file)
|
17
|
+
raise Informative, "无配置文件,run `pod confuse config config_file` 进行配置"
|
18
|
+
end
|
19
|
+
|
20
|
+
#查找source(可能是subspec)
|
21
|
+
git_source = recursive_git_source(self)
|
22
|
+
unless git_source
|
23
|
+
return false
|
24
|
+
end
|
25
|
+
|
26
|
+
# 如果指定了--all 参数,那么忽略黑名单白名单,全部检索
|
27
|
+
return true if Pod::Config.instance.is_confuse_all
|
28
|
+
|
29
|
+
# 判断域名白名单 和 黑名单,确保该组件是自己的组件,第三方sdk不做检索
|
30
|
+
config = Common::Config.instance
|
31
|
+
|
32
|
+
## 规则:
|
33
|
+
# 1、白名单/黑名单是通过组件podspec 中 source 字段的值来匹配,包含关键词即为命中,所有可以是git关键的域名,也可以是完整的git链接
|
34
|
+
# 2、白名单:当白名单为空数组时:默认为全部组件都为白名单!!!; 当白名单不为空时,仅检索白名单数组内的组件
|
35
|
+
git_source_whitelisted = config.source_white_list.empty? ? true : config.source_white_list.any? { |item| git_source.include?(item) }
|
36
|
+
|
37
|
+
## 3、黑名单:在白名单基础上,需要排除的组件
|
38
|
+
git_source_blacklisted = config.source_black_list.any? { |item| git_source.include?(item) }
|
39
|
+
## 4、最终检索的范围:白名单 - 黑名单
|
40
|
+
git_source_whitelisted && !git_source_blacklisted
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
def recursive_git_source(spec)
|
45
|
+
return nil unless spec
|
46
|
+
if spec.source && spec.source.key?(:git)
|
47
|
+
spec.source[:git]
|
48
|
+
elsif spec.source && spec.source.key?(:http)
|
49
|
+
# 如果 Git 源地址不存在,尝试获取 HTTP 源地址
|
50
|
+
spec.source[:http]
|
51
|
+
else
|
52
|
+
recursive_git_source(spec.instance_variable_get(:@parent))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -123,7 +123,7 @@ module PrivacyHunter
|
|
123
123
|
raise Pod::Informative, "无配置文件,run `pod privacy config config_file' 进行配置"
|
124
124
|
end
|
125
125
|
|
126
|
-
template_url =
|
126
|
+
template_url = Common::Config.instance.api_template_url
|
127
127
|
unless template_url && !template_url.empty?
|
128
128
|
raise Pod::Informative, "配置文件中无 `api.template.url` 配置,请补全后再更新配置 `pod privacy config config_file` "
|
129
129
|
end
|