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.
@@ -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
- app_dir = File.directory?(File.join(project_path, "app"))
195
-
212
+
213
+ main_module = get_main_module(project_path)
214
+
196
215
  # Android Studio项目结构
197
- if gradle_file && settings_gradle && app_dir
198
- app_gradle = File.exist?(File.join(project_path, "app", "build.gradle"))
199
- app_manifest = File.exist?(File.join(project_path, "app", "src", "main", "AndroidManifest.xml"))
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