pindo 5.0.4 → 5.0.5
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/lib/pindo/base/githelper.rb +1 -1
- data/lib/pindo/command/android/autobuild.rb +121 -0
- data/lib/pindo/command/android/build.rb +113 -0
- data/lib/pindo/command/android/debug.rb +60 -14
- data/lib/pindo/command/android.rb +5 -2
- data/lib/pindo/command/ios/autobuild.rb +6 -0
- data/lib/pindo/command/ios/build.rb +7 -1
- data/lib/pindo/command/unity/apk.rb +69 -6
- data/lib/pindo/command/utils/renewcert.rb +2 -2
- data/lib/pindo/module/android/apk_helper.rb +91 -0
- data/lib/pindo/module/android/base_helper.rb +293 -0
- data/lib/pindo/module/android/build_helper.rb +112 -0
- data/lib/pindo/module/android/gradle_helper.rb +48 -0
- data/lib/pindo/module/android/so_helper.rb +18 -0
- data/lib/pindo/module/build/buildhelper.rb +50 -37
- data/lib/pindo/module/build/unityhelper.rb +16 -16
- data/lib/pindo/module/pgyer/pgyerhelper.rb +14 -11
- data/lib/pindo/module/xcode/xcodehelper.rb +73 -73
- data/lib/pindo/version.rb +1 -1
- metadata +30 -3
@@ -0,0 +1,293 @@
|
|
1
|
+
module Pindo
|
2
|
+
module BaseAndroidHelper
|
3
|
+
|
4
|
+
def get_build_tools
|
5
|
+
# 获取 gem 资源文件路径
|
6
|
+
|
7
|
+
pindo_dir ||= File.expand_path(ENV['PINDO_DIR'] || '~/.pindo')
|
8
|
+
pindo_common_configdir ||= File.join(pindo_dir, "pindo_common_config")
|
9
|
+
tools_dir = File.join(pindo_common_configdir, 'android_tools')
|
10
|
+
|
11
|
+
# 如果开发环境找不到,尝试在 gem 安装目录找
|
12
|
+
unless File.directory?(tools_dir)
|
13
|
+
raise "缺少必要的构建工具: #{tools_dir},请执行pindo setup更新pindo配置"
|
14
|
+
end
|
15
|
+
|
16
|
+
# 检查必要的工具是否存在
|
17
|
+
required_tools = {
|
18
|
+
bundle_tool: 'bundletool.jar',
|
19
|
+
gradlew: 'gradlew',
|
20
|
+
gradle_wrapper: 'gradle-wrapper.jar'
|
21
|
+
}
|
22
|
+
|
23
|
+
tools = {}
|
24
|
+
required_tools.each do |key, filename|
|
25
|
+
path = File.join(tools_dir, filename)
|
26
|
+
unless File.exist?(path)
|
27
|
+
raise "缺少必要的构建工具: #{filename},请执行pindo setup更新pindo配置"
|
28
|
+
end
|
29
|
+
tools[key] = path
|
30
|
+
end
|
31
|
+
|
32
|
+
tools
|
33
|
+
end
|
34
|
+
|
35
|
+
def modify_il2cpp_config(project_path)
|
36
|
+
# 设置Il2CppOutputProject可执行权限
|
37
|
+
system("chmod", "-R", "777",
|
38
|
+
File.join(project_path, "unityLibrary/src/main/Il2CppOutputProject"))
|
39
|
+
|
40
|
+
il2cpp_config_path = File.join(project_path, "unityLibrary/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/il2cpp-config.h")
|
41
|
+
content = File.read(il2cpp_config_path)
|
42
|
+
content.gsub!("il2cpp::vm::Exception::Raise", "//il2cpp::vm::Exception::Raise")
|
43
|
+
File.write(il2cpp_config_path, content)
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove_desktop_google_service(project_path)
|
47
|
+
# 删除google-services-desktop.json
|
48
|
+
desktop_google_service_path = File.join(project_path,
|
49
|
+
"unityLibrary/src/main/assets/google-services-desktop.json")
|
50
|
+
File.delete(desktop_google_service_path) if File.exist?(desktop_google_service_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
# def get_app_name(project_path)
|
54
|
+
# strings_xml_path = File.join(project_path, "app/src/main/res/values/strings.xml")
|
55
|
+
|
56
|
+
# unless File.exist?(strings_xml_path)
|
57
|
+
# strings_xml_path = File.join(project_path, "unityLibrary/src/main/res/values/strings.xml")
|
58
|
+
# unless File.exist?(strings_xml_path)
|
59
|
+
# return nil
|
60
|
+
# end
|
61
|
+
# end
|
62
|
+
|
63
|
+
# xml_content = File.read(strings_xml_path)
|
64
|
+
# doc = Nokogiri::XML(xml_content)
|
65
|
+
# doc.at_xpath("//string[@name='app_name']")&.text
|
66
|
+
# end
|
67
|
+
|
68
|
+
def get_main_module(project_path)
|
69
|
+
settings_gradle_path = File.join(project_path, "settings.gradle")
|
70
|
+
return nil unless File.exist?(settings_gradle_path)
|
71
|
+
|
72
|
+
content = File.read(settings_gradle_path)
|
73
|
+
modules = content.scan(/include\s+['"]([^'"]+)['"]/).flatten
|
74
|
+
|
75
|
+
main_module = modules.find do |m|
|
76
|
+
module_name = m.split(':').last
|
77
|
+
gradle_path = File.join(project_path, module_name, "build.gradle")
|
78
|
+
if File.exist?(gradle_path)
|
79
|
+
File.read(gradle_path).include?("apply plugin: 'com.android.application'") ||
|
80
|
+
File.read(gradle_path).include?("id 'com.android.application'")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
return nil unless main_module
|
84
|
+
|
85
|
+
module_name = main_module.split(':').last
|
86
|
+
File.join(project_path, module_name)
|
87
|
+
end
|
88
|
+
|
89
|
+
def get_keystore_config(project_path, debug = false)
|
90
|
+
main_module = get_main_module(project_path)
|
91
|
+
return nil unless main_module
|
92
|
+
|
93
|
+
gradle_path = File.join(main_module, "build.gradle")
|
94
|
+
return nil unless File.exist?(gradle_path)
|
95
|
+
|
96
|
+
content = File.read(gradle_path)
|
97
|
+
|
98
|
+
# 直接读取整个文件内容,不使用正则表达式截取 android 块
|
99
|
+
puts "读取 build.gradle 文件"
|
100
|
+
|
101
|
+
# 查找 signingConfigs 块的开始和结束位置
|
102
|
+
signing_configs_start = content.index(/signingConfigs\s*\{/)
|
103
|
+
return nil unless signing_configs_start
|
104
|
+
|
105
|
+
# 从开始位置查找匹配的闭合大括号
|
106
|
+
open_braces = 0
|
107
|
+
signing_configs_end = nil
|
108
|
+
|
109
|
+
content[signing_configs_start..-1].each_char.with_index do |char, i|
|
110
|
+
if char == '{'
|
111
|
+
open_braces += 1
|
112
|
+
elsif char == '}'
|
113
|
+
open_braces -= 1
|
114
|
+
if open_braces == 0
|
115
|
+
signing_configs_end = signing_configs_start + i
|
116
|
+
break
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
return nil unless signing_configs_end
|
122
|
+
|
123
|
+
# 提取完整的 signingConfigs 块
|
124
|
+
signing_configs_block = content[signing_configs_start..signing_configs_end]
|
125
|
+
|
126
|
+
|
127
|
+
# 查找配置名称,如 Android_Sign
|
128
|
+
config_name_match = signing_configs_block.match(/signingConfigs\s*\{\s*(\w+)\s*\{/)
|
129
|
+
config_name = config_name_match ? config_name_match[1] : nil
|
130
|
+
return nil unless config_name
|
131
|
+
|
132
|
+
# 检查 buildTypes 中使用的签名配置
|
133
|
+
config_type = debug ? 'debug' : 'release'
|
134
|
+
build_type_match = content.match(/buildTypes\s*\{.*?#{config_type}\s*\{(.*?)}/m)
|
135
|
+
if build_type_match && build_type_match[1] =~ /signingConfig\s+signingConfigs\.(\w+)/
|
136
|
+
config_name = $1
|
137
|
+
end
|
138
|
+
|
139
|
+
# 提取特定配置块的内容
|
140
|
+
config_start = signing_configs_block.index(/#{config_name}\s*\{/)
|
141
|
+
return nil unless config_start
|
142
|
+
|
143
|
+
# 从配置开始位置查找匹配的闭合大括号
|
144
|
+
open_braces = 0
|
145
|
+
config_end = nil
|
146
|
+
|
147
|
+
signing_configs_block[config_start..-1].each_char.with_index do |char, i|
|
148
|
+
if char == '{'
|
149
|
+
open_braces += 1
|
150
|
+
elsif char == '}'
|
151
|
+
open_braces -= 1
|
152
|
+
if open_braces == 0
|
153
|
+
config_end = config_start + i
|
154
|
+
break
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
return nil unless config_end
|
160
|
+
|
161
|
+
# 提取完整的配置块
|
162
|
+
config_block = signing_configs_block[config_start..config_end]
|
163
|
+
|
164
|
+
puts "解析 signing config:"
|
165
|
+
puts "=" * 50
|
166
|
+
puts config_block
|
167
|
+
puts "=" * 50
|
168
|
+
|
169
|
+
# 从配置块中提取各项参数
|
170
|
+
store_file_match = config_block.match(/storeFile\s+file\(["']?\${([^}]+)}["']?\)/m)
|
171
|
+
store_password_match = config_block.match(/storePassword\s+["']?\${([^}]+)}["']?/m)
|
172
|
+
key_alias_match = config_block.match(/keyAlias\s+["']?\${([^}]+)}["']?/m)
|
173
|
+
key_password_match = config_block.match(/keyPassword\s+["']?\${([^}]+)}["']?/m)
|
174
|
+
|
175
|
+
# 如果使用了外部变量,尝试从 ext_signing.gradle 或其他配置文件中获取实际值
|
176
|
+
if store_file_match || store_password_match || key_alias_match || key_password_match
|
177
|
+
ext_values = get_ext_values(project_path)
|
178
|
+
puts "尝试从 ext values 中获取"
|
179
|
+
|
180
|
+
# 获取 store_file 并处理 $rootDir 路径
|
181
|
+
store_file = store_file_match ? ext_values[store_file_match[1]] : nil
|
182
|
+
if store_file && store_file.include?('$rootDir')
|
183
|
+
# 替换 $rootDir 为项目根目录的绝对路径
|
184
|
+
# 查找项目根目录(包含settings.gradle的目录)
|
185
|
+
root_dir = project_path
|
186
|
+
while root_dir && !File.exist?(File.join(root_dir, "settings.gradle"))
|
187
|
+
parent_dir = File.dirname(root_dir)
|
188
|
+
# 防止无限循环
|
189
|
+
break if parent_dir == root_dir
|
190
|
+
root_dir = parent_dir
|
191
|
+
end
|
192
|
+
|
193
|
+
store_file = store_file.gsub('$rootDir', root_dir)
|
194
|
+
puts "处理后的 store_file 路径: #{store_file}"
|
195
|
+
end
|
196
|
+
|
197
|
+
keystore_config = {
|
198
|
+
store_file: store_file,
|
199
|
+
store_password: store_password_match ? ext_values[store_password_match[1]] : nil,
|
200
|
+
key_alias: key_alias_match ? ext_values[key_alias_match[1]] : nil,
|
201
|
+
key_password: key_password_match ? ext_values[key_password_match[1]] : nil
|
202
|
+
}
|
203
|
+
|
204
|
+
# 确保所有值都不为 nil
|
205
|
+
if keystore_config.values.any?(&:nil?)
|
206
|
+
puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
|
207
|
+
end
|
208
|
+
|
209
|
+
return keystore_config
|
210
|
+
else
|
211
|
+
# 直接从配置块中提取硬编码的值
|
212
|
+
store_file = config_block.match(/storeFile\s+file\(['"]([^'"]+)['"]\)/m)&.[](1)
|
213
|
+
store_password = config_block.match(/storePassword\s+['"]([^'"]+)['"]/m)&.[](1)
|
214
|
+
key_alias = config_block.match(/keyAlias\s+['"]([^'"]+)['"]/m)&.[](1)
|
215
|
+
key_password = config_block.match(/keyPassword\s+['"]([^'"]+)['"]/m)&.[](1)
|
216
|
+
|
217
|
+
keystore_config = {
|
218
|
+
store_file: store_file,
|
219
|
+
store_password: store_password,
|
220
|
+
key_alias: key_alias,
|
221
|
+
key_password: key_password
|
222
|
+
}
|
223
|
+
|
224
|
+
# 确保所有值都不为 nil
|
225
|
+
if keystore_config.values.any?(&:nil?)
|
226
|
+
puts "警告: 部分 keystore 配置为 nil: #{keystore_config}"
|
227
|
+
end
|
228
|
+
|
229
|
+
return keystore_config
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
# 新增方法:从 ext 配置文件中获取变量值
|
234
|
+
def get_ext_values(project_path)
|
235
|
+
ext_values = {}
|
236
|
+
|
237
|
+
# 查找可能的 ext 配置文件
|
238
|
+
ext_files = [
|
239
|
+
File.join(project_path, "buildScripts/cfg/ext_signing.gradle"),
|
240
|
+
File.join(project_path, "gradle.properties"),
|
241
|
+
File.join(project_path, "local.properties")
|
242
|
+
]
|
243
|
+
|
244
|
+
ext_files.each do |file_path|
|
245
|
+
next unless File.exist?(file_path)
|
246
|
+
|
247
|
+
content = File.read(file_path)
|
248
|
+
|
249
|
+
# 解析 ext.KEY = "VALUE" 格式
|
250
|
+
content.scan(/ext\.(\w+)\s*=\s*["']([^"']+)["']/m).each do |key, value|
|
251
|
+
ext_values[key] = value
|
252
|
+
end
|
253
|
+
|
254
|
+
# 解析 KEY=VALUE 格式
|
255
|
+
content.scan(/^(\w+)\s*=\s*["']?([^"'\n]+)["']?/m).each do |key, value|
|
256
|
+
ext_values[key] = value
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
ext_values
|
261
|
+
end
|
262
|
+
|
263
|
+
def unity_android_project?(project_path)
|
264
|
+
# 检查 unityLibrary 模块是否存在
|
265
|
+
unity_library_path = File.join(project_path, "unityLibrary")
|
266
|
+
return false unless File.directory?(unity_library_path)
|
267
|
+
|
268
|
+
# 检查 unityLibrary 的 build.gradle 是否存在
|
269
|
+
unity_gradle_path = File.join(unity_library_path, "build.gradle")
|
270
|
+
return false unless File.exist?(unity_gradle_path)
|
271
|
+
|
272
|
+
# 检查 build.gradle 中是否包含 Unity 特有的配置
|
273
|
+
content = File.read(unity_gradle_path)
|
274
|
+
content.include?("com.android.library") && content.include?("BuildIl2Cpp")
|
275
|
+
end
|
276
|
+
|
277
|
+
def find_android_subproject(project_path)
|
278
|
+
android_dir = File.join(project_path, "Unity")
|
279
|
+
return nil unless File.directory?(android_dir)
|
280
|
+
|
281
|
+
main_module = get_main_module(android_dir)
|
282
|
+
return nil unless main_module
|
283
|
+
|
284
|
+
src_main = File.join(main_module, "src/main")
|
285
|
+
return nil unless File.directory?(src_main)
|
286
|
+
|
287
|
+
manifest = File.join(src_main, "AndroidManifest.xml")
|
288
|
+
return nil unless File.exist?(manifest)
|
289
|
+
|
290
|
+
android_dir
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require_relative 'base_helper'
|
3
|
+
require_relative 'gradle_helper'
|
4
|
+
require_relative 'so_helper'
|
5
|
+
require_relative 'apk_helper'
|
6
|
+
|
7
|
+
module Pindo
|
8
|
+
class AndroidBuildHelper
|
9
|
+
include BaseAndroidHelper
|
10
|
+
include GradleHelper
|
11
|
+
include SoHelper
|
12
|
+
include ApkHelper
|
13
|
+
include Singleton
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def share_instance
|
17
|
+
instance
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def auto_build_apk(project_dir, debug = false, ignore_sub = false)
|
22
|
+
# 检查 gradle.properties 中是否设置了 Java Home
|
23
|
+
gradle_properties_path = File.join(project_dir, "gradle.properties")
|
24
|
+
if File.exist?(gradle_properties_path)
|
25
|
+
puts "检查 gradle.properties 中的 Java Home 设置..."
|
26
|
+
content = File.read(gradle_properties_path)
|
27
|
+
java_home_match = content.match(/org\.gradle\.java\.home\s*=\s*(.+)/)
|
28
|
+
if java_home_match && !java_home_match[1].empty?
|
29
|
+
java_home_path = java_home_match[1].strip
|
30
|
+
puts "找到 Java Home 路径: #{java_home_path}"
|
31
|
+
# 设置环境变量
|
32
|
+
ENV['JAVA_HOME'] = java_home_path
|
33
|
+
ENV['PATH'] = "#{java_home_path}/bin:#{ENV['PATH']}"
|
34
|
+
puts "已设置 JAVA_HOME 环境变量为: #{java_home_path}"
|
35
|
+
puts "Java 版本信息:"
|
36
|
+
system("java -version")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# 检查
|
41
|
+
if !ignore_sub
|
42
|
+
sub_android_dir = find_android_subproject(project_dir)
|
43
|
+
if sub_android_dir
|
44
|
+
prepare_proj(sub_android_dir)
|
45
|
+
# 构建 AAB 文件
|
46
|
+
unless build_so_library(sub_android_dir)
|
47
|
+
raise RuntimeError, "编译SO库失败:"
|
48
|
+
end
|
49
|
+
copy_so_files(sub_android_dir, project_dir)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
prepare_proj(project_dir)
|
54
|
+
build_apk(project_dir, debug)
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_application_id(project_path)
|
58
|
+
main_module = get_main_module(project_path)
|
59
|
+
return nil unless main_module
|
60
|
+
|
61
|
+
# 尝试从 build.gradle 获取
|
62
|
+
gradle_path = File.join(main_module, "build.gradle")
|
63
|
+
if File.exist?(gradle_path)
|
64
|
+
content = File.read(gradle_path)
|
65
|
+
if content =~ /applicationId\s+['"]([^'"]+)['"]/
|
66
|
+
return $1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# 如果 build.gradle 中没有,尝试从 AndroidManifest.xml 获取
|
71
|
+
manifest_path = File.join(main_module, "src", "main", "AndroidManifest.xml")
|
72
|
+
if File.exist?(manifest_path)
|
73
|
+
require 'nokogiri'
|
74
|
+
doc = Nokogiri::XML(File.read(manifest_path))
|
75
|
+
package = doc.at_xpath('//manifest/@package')&.value
|
76
|
+
return package if package
|
77
|
+
end
|
78
|
+
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
|
82
|
+
def dsign(project_path, debug)
|
83
|
+
keystore_config = get_keystore_config(project_path, debug)
|
84
|
+
|
85
|
+
ks = keystore_config[:store_file]
|
86
|
+
puts "读取 keystore path = #{ks}"
|
87
|
+
ks_pass = keystore_config[:store_password]
|
88
|
+
puts "读取 keystore pass = #{ks_pass}"
|
89
|
+
key_alias = keystore_config[:key_alias]
|
90
|
+
puts "读取 key alias = #{key_alias}"
|
91
|
+
key_pass = keystore_config[:key_password]
|
92
|
+
puts "读取 key pass = #{key_pass}"
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
def prepare_proj(project_dir)
|
98
|
+
raise ArgumentError, "项目目录不能为空" if project_dir.nil?
|
99
|
+
raise ArgumentError, "项目目录不存在" unless File.directory?(project_dir)
|
100
|
+
|
101
|
+
check_gradle_files(project_dir)
|
102
|
+
if unity_android_project?(project_dir)
|
103
|
+
update_build_gradle(project_dir)
|
104
|
+
update_gradle_version(project_dir)
|
105
|
+
modify_il2cpp_config(project_dir)
|
106
|
+
remove_desktop_google_service(project_dir)
|
107
|
+
end
|
108
|
+
rescue StandardError => e
|
109
|
+
raise Informative, "准备项目失败: #{e.message}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'base_helper'
|
2
|
+
|
3
|
+
module Pindo
|
4
|
+
module GradleHelper
|
5
|
+
include BaseAndroidHelper
|
6
|
+
|
7
|
+
def check_gradle_files(project_path)
|
8
|
+
# 检查是否存在 gradlew 文件 如果没有则执行复制操作
|
9
|
+
gradlew_path = File.join(project_path, "gradlew")
|
10
|
+
if File.exist?(gradlew_path)
|
11
|
+
puts "gradlew file already exists, skip copying."
|
12
|
+
else
|
13
|
+
# 复制gradle相关文件
|
14
|
+
gradlew_content = File.read(get_build_tools[:gradlew])
|
15
|
+
File.write(gradlew_path, gradlew_content)
|
16
|
+
end
|
17
|
+
# 设置gradlew可执行权限
|
18
|
+
system("chmod", "777", gradlew_path)
|
19
|
+
|
20
|
+
wrapper_jar_path = File.join(project_path, "gradle/wrapper/gradle-wrapper.jar")
|
21
|
+
if File.exist?(wrapper_jar_path)
|
22
|
+
puts "gradle-wrapper.jar file already exists, skip copying."
|
23
|
+
else
|
24
|
+
FileUtils.mkdir_p(File.dirname(wrapper_jar_path))
|
25
|
+
gradle_wrapper_content = File.read(get_build_tools[:gradle_wrapper])
|
26
|
+
File.write(wrapper_jar_path, gradle_wrapper_content)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_build_gradle(project_path)
|
31
|
+
# 更新build.gradle
|
32
|
+
build_gradle_path = File.join(project_path, "build.gradle")
|
33
|
+
content = File.read(build_gradle_path)
|
34
|
+
content.gsub!("classpath 'com.android.tools.build:gradle:4.0.1'",
|
35
|
+
"classpath 'com.android.tools.build:gradle:4.2.2'")
|
36
|
+
File.write(build_gradle_path, content)
|
37
|
+
end
|
38
|
+
|
39
|
+
def update_gradle_version(project_path)
|
40
|
+
# 更新gradle wrapper版本
|
41
|
+
wrapper_path = File.join(project_path, "gradle/wrapper/gradle-wrapper.properties")
|
42
|
+
content = File.read(wrapper_path)
|
43
|
+
content.gsub!("gradle-6.1.1-bin.zip", "gradle-7.2-bin.zip")
|
44
|
+
File.write(wrapper_path, content)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Pindo
|
2
|
+
module SoHelper
|
3
|
+
|
4
|
+
def build_so_library(project_path)
|
5
|
+
# 编译so库
|
6
|
+
Dir.chdir(project_path) do
|
7
|
+
system("./gradlew unityLibrary:BuildIl2CppTask")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def copy_so_files(source_path, target_path)
|
12
|
+
# 复制so文件到正确的目录
|
13
|
+
src_dir = File.join(source_path, "unityLibrary/src/main/assets")
|
14
|
+
dst_dir = File.join(target_path, "unityLibrary/src/main/assets")
|
15
|
+
FileUtils.cp_r(src_dir, dst_dir) if File.directory?(src_dir)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,11 +1,12 @@
|
|
1
1
|
require 'singleton'
|
2
2
|
require 'fileutils'
|
3
3
|
require 'xcodeproj' # 用于iOS项目检查
|
4
|
-
|
4
|
+
require_relative '../android/base_helper'
|
5
5
|
module Pindo
|
6
6
|
|
7
7
|
class BuildHelper
|
8
8
|
include Singleton
|
9
|
+
include BaseAndroidHelper
|
9
10
|
include Pindo::Githelper
|
10
11
|
|
11
12
|
class << self
|
@@ -14,6 +15,23 @@ module Pindo
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
18
|
+
def delete_libtarget_firebase_shell(project_path)
|
19
|
+
if File.directory?(File.join(project_path, 'Unity')) && File.exist?(File.join(project_path, 'Unity', 'Unity-iPhone.xcodeproj'))
|
20
|
+
unity_project_path = File.join(project_path, 'Unity', 'Unity-iPhone.xcodeproj')
|
21
|
+
xcdoe_unitylib_project = Xcodeproj::Project::open(unity_project_path)
|
22
|
+
xcdoe_unitylib_project.targets.each do |target|
|
23
|
+
if target.name == 'Unity-iPhone'
|
24
|
+
target.shell_script_build_phases.each do |phase|
|
25
|
+
if phase.name.eql?("Crashlytics Run Script")
|
26
|
+
target.remove_build_phase(phase)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
xcdoe_unitylib_project.save()
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
17
35
|
def check_check_and_install_cliff(project_path)
|
18
36
|
if is_git_directory?(local_repo_dir: project_path)
|
19
37
|
current_git_root_path = git_root_directory(local_repo_dir: project_path)
|
@@ -39,7 +57,7 @@ module Pindo
|
|
39
57
|
build_ios.log
|
40
58
|
feishu.json
|
41
59
|
CHANGELOG.md
|
42
|
-
|
60
|
+
|
43
61
|
# Platform specific directories
|
44
62
|
/GoodPlatform/iOS/config.json
|
45
63
|
/GoodPlatform/iOS/*
|
@@ -81,7 +99,7 @@ module Pindo
|
|
81
99
|
commit_message = "docs: 添加日志变更配置".encode('UTF-8')
|
82
100
|
git!(%W(-C #{current_git_root_path} commit -m #{commit_message}))
|
83
101
|
git!(%W(-C #{current_git_root_path} push origin #{current_branch}))
|
84
|
-
|
102
|
+
|
85
103
|
else
|
86
104
|
Funlog.instance.fancyinfo_error("当前目录不是git仓库,请在git仓库根目录下执行此命令")
|
87
105
|
raise Informative, "当前目录不是git仓库,请在git仓库根目录下执行此命令"
|
@@ -109,33 +127,33 @@ module Pindo
|
|
109
127
|
def check_is_need_add_tag?(project_path)
|
110
128
|
tag_action_parms = nil
|
111
129
|
is_need_add_tag = false
|
112
|
-
|
130
|
+
|
113
131
|
if is_git_directory?(local_repo_dir: project_path)
|
114
132
|
current_git_root_path = git_root_directory(local_repo_dir: project_path)
|
115
133
|
latest_tag = get_latest_version_tag(project_dir: current_git_root_path)
|
116
|
-
|
134
|
+
|
117
135
|
unless is_tag_at_head?(git_root_dir: current_git_root_path, tag_name: latest_tag)
|
118
136
|
cli = HighLine.new
|
119
137
|
menu_options = {
|
120
|
-
"新增版本号,打新Tag" => -> {
|
138
|
+
"新增版本号,打新Tag" => -> {
|
121
139
|
tag_action_parms = []
|
122
|
-
:new_tag
|
140
|
+
:new_tag
|
123
141
|
},
|
124
|
-
"将上次的Tag删除重新打Tag" => -> {
|
142
|
+
"将上次的Tag删除重新打Tag" => -> {
|
125
143
|
tag_action_parms = []
|
126
144
|
tag_action_parms << "--retag"
|
127
|
-
:recreate_tag
|
145
|
+
:recreate_tag
|
128
146
|
},
|
129
|
-
"不需要Tag继续编译且上传,手动修改上传备注" => -> {
|
147
|
+
"不需要Tag继续编译且上传,手动修改上传备注" => -> {
|
130
148
|
puts ""
|
131
|
-
:continue_without_tag
|
149
|
+
:continue_without_tag
|
132
150
|
},
|
133
|
-
"终止退出编译" => -> {
|
151
|
+
"终止退出编译" => -> {
|
134
152
|
raise Informative, "终止退出编译!"
|
135
|
-
:exit
|
153
|
+
:exit
|
136
154
|
}
|
137
155
|
}
|
138
|
-
|
156
|
+
|
139
157
|
result = cli.choose do |menu|
|
140
158
|
menu.header = "当前代码并没有打Tag,上传的Changelog需要Tag"
|
141
159
|
menu.prompt = "请选中打Tag的方式, 请输入选项(1/2/3...):"
|
@@ -143,11 +161,11 @@ module Pindo
|
|
143
161
|
menu.choice(option) { action.call }
|
144
162
|
end
|
145
163
|
end
|
146
|
-
|
164
|
+
|
147
165
|
is_need_add_tag = !tag_action_parms.nil?
|
148
166
|
end
|
149
167
|
end
|
150
|
-
|
168
|
+
|
151
169
|
return [is_need_add_tag, tag_action_parms]
|
152
170
|
end
|
153
171
|
|
@@ -156,10 +174,10 @@ module Pindo
|
|
156
174
|
project_settings_path = File.join(project_path, "ProjectSettings")
|
157
175
|
assets_path = File.join(project_path, "Assets")
|
158
176
|
packages_path = File.join(project_path, "Packages")
|
159
|
-
|
177
|
+
|
160
178
|
# Unity工程必须包含这些目录和文件
|
161
|
-
File.directory?(project_settings_path) &&
|
162
|
-
File.directory?(assets_path) &&
|
179
|
+
File.directory?(project_settings_path) &&
|
180
|
+
File.directory?(assets_path) &&
|
163
181
|
File.directory?(packages_path) &&
|
164
182
|
File.exist?(File.join(project_settings_path, "ProjectSettings.asset"))
|
165
183
|
end
|
@@ -168,22 +186,22 @@ module Pindo
|
|
168
186
|
# 检查iOS工程的关键文件
|
169
187
|
xcodeproj_files = Dir.glob(File.join(project_path, "*.xcodeproj"))
|
170
188
|
workspace_files = Dir.glob(File.join(project_path, "*.xcworkspace"))
|
171
|
-
|
189
|
+
|
172
190
|
# 至少要有.xcodeproj文件或.xcworkspace文件
|
173
191
|
return false if xcodeproj_files.empty? && workspace_files.empty?
|
174
|
-
|
192
|
+
|
175
193
|
if !xcodeproj_files.empty?
|
176
194
|
# 检查.xcodeproj内部结构
|
177
195
|
project_file = File.join(xcodeproj_files.first, "project.pbxproj")
|
178
196
|
return true if File.exist?(project_file)
|
179
197
|
end
|
180
|
-
|
198
|
+
|
181
199
|
if !workspace_files.empty?
|
182
200
|
# 检查.xcworkspace内部结构
|
183
201
|
contents_file = File.join(workspace_files.first, "contents.xcworkspacedata")
|
184
202
|
return true if File.exist?(contents_file)
|
185
203
|
end
|
186
|
-
|
204
|
+
|
187
205
|
false
|
188
206
|
end
|
189
207
|
|
@@ -191,28 +209,23 @@ module Pindo
|
|
191
209
|
# 检查Android工程的关键文件和目录
|
192
210
|
gradle_file = File.exist?(File.join(project_path, "build.gradle"))
|
193
211
|
settings_gradle = File.exist?(File.join(project_path, "settings.gradle"))
|
194
|
-
|
195
|
-
|
212
|
+
|
213
|
+
main_module = get_main_module(project_path)
|
214
|
+
|
196
215
|
# Android Studio项目结构
|
197
|
-
if gradle_file && settings_gradle &&
|
198
|
-
app_gradle = File.exist?(File.join(
|
199
|
-
app_manifest = File.exist?(File.join(
|
216
|
+
if gradle_file && settings_gradle && main_module
|
217
|
+
app_gradle = File.exist?(File.join(main_module, "build.gradle"))
|
218
|
+
app_manifest = File.exist?(File.join(main_module, "src", "main", "AndroidManifest.xml"))
|
200
219
|
return true if app_gradle && app_manifest
|
201
220
|
end
|
202
|
-
|
203
|
-
# 传统Eclipse项目结构
|
204
|
-
if File.directory?(File.join(project_path, "src"))
|
205
|
-
manifest = File.join(project_path, "AndroidManifest.xml")
|
206
|
-
return true if File.exist?(manifest)
|
207
|
-
end
|
208
|
-
|
221
|
+
|
209
222
|
false
|
210
223
|
end
|
211
224
|
|
212
225
|
def project_type(project_path)
|
213
226
|
raise ArgumentError, "项目路径不能为空" if project_path.nil? || project_path.empty?
|
214
227
|
raise ArgumentError, "项目路径不存在: #{project_path}" unless File.directory?(project_path)
|
215
|
-
|
228
|
+
|
216
229
|
return :unity if unity_project?(project_path)
|
217
230
|
return :ios if ios_project?(project_path)
|
218
231
|
return :android if android_project?(project_path)
|
@@ -276,4 +289,4 @@ module Pindo
|
|
276
289
|
end
|
277
290
|
end
|
278
291
|
|
279
|
-
end
|
292
|
+
end
|