Class: Pindo::AndroidProjectHelper

Inherits:
Object
  • Object
show all
Defined in:
lib/pindo/module/android/android_project_helper.rb

Class Method Summary collapse

Class Method Details

.add_unity_namespace(project_path) ⇒ Object



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
# File 'lib/pindo/module/android/android_project_helper.rb', line 120

def add_unity_namespace(project_path)
  # 在 unityLibrary/build.gradle 中添加 namespace(AGP 7.x+ 需要)
  unity_build_gradle = File.join(project_path, "unityLibrary/build.gradle")
  return unless File.exist?(unity_build_gradle)

  content = File.read(unity_build_gradle)

  # 检查是否已经有 namespace
  if content =~ /namespace\s+['"][\w.]+['"]/
    puts "  ✓ unityLibrary 已配置 namespace"
    return
  end

  # 在 android { 块的开始位置添加 namespace
  if content =~ /(android\s*\{)/
    # Unity 默认使用 com.unity3d.player 作为 namespace
    namespace_line = "\n    namespace 'com.unity3d.player'\n"
    content.sub!(/(android\s*\{)/, "\\1#{namespace_line}")

    File.write(unity_build_gradle, content)
    puts "  ✓ 已添加 namespace 到 unityLibrary/build.gradle"
  else
    puts "  ⚠ 无法在 unityLibrary/build.gradle 中找到 android 块"
  end
end

.check_main_local_properties(project_path) ⇒ Object



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/pindo/module/android/android_project_helper.rb', line 146

def check_main_local_properties(project_path)
  # 检查并配置主工程的 local.properties 文件
  main_local_properties = File.join(project_path, "local.properties")

  # 获取期望的 SDK 路径(从 Unity 模块、环境变量或默认路径)
  expected_sdk_dir = get_expected_sdk_dir(project_path)

  unless expected_sdk_dir
    puts "  ⚠ 无法找到有效的 Android SDK 路径"
    return
  end

  if File.exist?(main_local_properties)
    # 文件存在,检查 sdk.dir 是否正确
    puts "  检查主工程 local.properties..."
    content = File.read(main_local_properties)

    if content =~ /sdk\.dir\s*=\s*(.+)/
      current_sdk_dir = $1.strip

      if current_sdk_dir == expected_sdk_dir
        puts "  ✓ SDK 路径正确: #{current_sdk_dir}"
      elsif File.directory?(current_sdk_dir)
        puts "  ✓ SDK 路径有效: #{current_sdk_dir}"
      else
        # SDK 路径无效,更新为期望的路径
        puts "  ⚠ SDK 路径无效: #{current_sdk_dir}"
        puts "  更新为: #{expected_sdk_dir}"
        content.gsub!(/sdk\.dir\s*=\s*.+/, "sdk.dir=#{expected_sdk_dir}")
        File.write(main_local_properties, content)
        puts "  ✓ 已更新 SDK 路径"
      end
    else
      # 文件存在但没有 sdk.dir,添加它
      puts "  ⚠ local.properties 中未找到 sdk.dir"
      File.write(main_local_properties, "#{content}\nsdk.dir=#{expected_sdk_dir}\n")
      puts "  ✓ 已添加 SDK 路径: #{expected_sdk_dir}"
    end
  else
    # 文件不存在,创建它
    puts "  创建主工程 local.properties..."
    File.write(main_local_properties, "sdk.dir=#{expected_sdk_dir}\n")
    puts "  ✓ 已创建 local.properties,SDK 路径: #{expected_sdk_dir}"
  end
end

.find_android_subproject(project_path) ⇒ Object



260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
# File 'lib/pindo/module/android/android_project_helper.rb', line 260

def find_android_subproject(project_path)
  android_dir = File.join(project_path, "Unity")
  return nil unless File.directory?(android_dir)

  main_module = get_main_module(android_dir)
  return nil unless main_module

  src_main = File.join(main_module, "src/main")
  return nil unless File.directory?(src_main)

  manifest = File.join(src_main, "AndroidManifest.xml")
  return nil unless File.exist?(manifest)

  android_dir
end

.get_build_toolsObject



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# File 'lib/pindo/module/android/android_project_helper.rb', line 46

def get_build_tools
  # 获取 gem 资源文件路径
  pindo_dir ||= File.expand_path(ENV['PINDO_DIR'] || '~/.pindo')
  pindo_common_configdir ||= File.join(pindo_dir, "pindo_common_config")
  tools_dir = File.join(pindo_common_configdir, 'android_tools')

  # 检查工具目录是否存在
  unless File.directory?(tools_dir)
    Funlog.error("Android 构建工具目录不存在: #{tools_dir}")
    Funlog.error("请执行以下命令更新 Pindo 配置:")
    Funlog.error("  pindo setup")
    Funlog.error("或手动克隆配置仓库到 ~/.pindo/pindo_common_config")
    return nil
  end

  # 定义必要的工具
  required_tools = {
    bundle_tool: 'bundletool.jar',
    gradlew: 'gradlew',
    gradle_wrapper: 'gradle-wrapper.jar'
  }

  tools = {}
  missing_tools = []

  # 检查每个工具是否存在
  required_tools.each do |key, filename|
    path = File.join(tools_dir, filename)
    if File.exist?(path)
      tools[key] = path
    else
      missing_tools << filename
    end
  end

  # 如果有缺失的工具,提供友好的错误信息
  unless missing_tools.empty?
    Funlog.error("缺少以下 Android 构建工具:")
    missing_tools.each do |tool|
      Funlog.error("  - #{tool}")
    end
    Funlog.error("")
    Funlog.error("解决方案:")
    Funlog.error("  1. 执行 'pindo setup' 更新配置")
    Funlog.error("  2. 或手动下载缺失的工具到: #{tools_dir}")
    Funlog.error("")
    Funlog.error("如果问题持续存在,请检查:")
    Funlog.error("  - 网络连接是否正常")
    Funlog.error("  - Git 仓库是否可访问")
    Funlog.error("  - 目录权限是否正确")
    return nil
  end

  tools
end

.get_expected_sdk_dir(project_path) ⇒ Object



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
# File 'lib/pindo/module/android/android_project_helper.rb', line 192

def get_expected_sdk_dir(project_path)
  # 优先使用 Android Studio 的 SDK 路径(主工程使用)
  android_studio_sdk = File.expand_path("~/Library/Android/sdk")
  return android_studio_sdk if File.directory?(android_studio_sdk)

  # 尝试从环境变量获取
  sdk_dir = ENV['ANDROID_HOME'] || ENV['ANDROID_SDK_ROOT']
  return sdk_dir if sdk_dir && File.directory?(sdk_dir)

  # 尝试从 Unity 模块的 local.properties 获取 SDK 路径
  unity_local_properties = File.join(project_path, "Unity/local.properties")

  if File.exist?(unity_local_properties)
    unity_content = File.read(unity_local_properties)
    if unity_content =~ /sdk\.dir\s*=\s*(.+)/
      sdk_dir = $1.strip
      return sdk_dir if File.directory?(sdk_dir)
    end
  end

  # 最后尝试 Unity 内置的 SDK 路径
  unity_sdk = "/Applications/Unity/Hub/Editor/2022.3.61f1/PlaybackEngines/AndroidPlayer/SDK"
  return unity_sdk if File.directory?(unity_sdk)

  nil
end

.get_main_module(project_path) ⇒ Object



219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/pindo/module/android/android_project_helper.rb', line 219

def get_main_module(project_path)
  settings_gradle_path = File.join(project_path, "settings.gradle")
  settings_gradle_kts_path = File.join(project_path, "settings.gradle.kts")

  # 优先使用 settings.gradle.kts,如果不存在则使用 settings.gradle
  if File.exist?(settings_gradle_kts_path)
    settings_gradle_path = settings_gradle_kts_path
  elsif !File.exist?(settings_gradle_path)
    return nil
  end

  content = File.read(settings_gradle_path)
  # 兼容 include ':app' 和 include(":app")
  modules = content.scan(/include\s*\(?\s*['\"]?([:\w\-]+)['\"]?\s*\)?/).flatten

  main_module = modules.find do |m|
    module_name = m.split(':').last
    gradle_path = File.join(project_path, module_name, "build.gradle")
    gradle_kts_path = File.join(project_path, module_name, "build.gradle.kts")

    # 优先使用 build.gradle.kts,如果不存在则使用 build.gradle
    if File.exist?(gradle_kts_path)
      gradle_path = gradle_kts_path
    end

    if File.exist?(gradle_path)
      gradle_content = File.read(gradle_path)
      gradle_content.include?("apply plugin: 'com.android.application") ||
        gradle_content.include?("id 'com.android.application") ||
        (gradle_content.include?("plugins {") && gradle_content.include?("com.android.application"))
    end
  end
  return nil unless main_module

  module_name = main_module.split(':').last
  File.join(project_path, module_name)
end

.modify_il2cpp_config(project_path) ⇒ Object



102
103
104
105
106
107
108
109
110
111
# File 'lib/pindo/module/android/android_project_helper.rb', line 102

def modify_il2cpp_config(project_path)
  # 设置Il2CppOutputProject可执行权限
  system("chmod", "-R", "777",
  File.join(project_path, "unityLibrary/src/main/Il2CppOutputProject"))

  il2cpp_config_path = File.join(project_path, "unityLibrary/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/il2cpp-config.h")
  content = File.read(il2cpp_config_path)
  content.gsub!("il2cpp::vm::Exception::Raise", "//il2cpp::vm::Exception::Raise")
  File.write(il2cpp_config_path, content)
end

.remove_desktop_google_service(project_path) ⇒ Object



113
114
115
116
117
118
# File 'lib/pindo/module/android/android_project_helper.rb', line 113

def remove_desktop_google_service(project_path)
  # 删除google-services-desktop.json
  desktop_google_service_path = File.join(project_path,
    "unityLibrary/src/main/assets/google-services-desktop.json")
  File.delete(desktop_google_service_path) if File.exist?(desktop_google_service_path)
end

.unity_android_project?(project_path) ⇒ Boolean

Returns:

  • (Boolean)


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/pindo/module/android/android_project_helper.rb', line 6

def unity_android_project?(project_path)
  # 检查 unityLibrary 模块是否存在
  unity_library_path = File.join(project_path, "unityLibrary")
  return false unless File.directory?(unity_library_path)

  # 检查 unityLibrary 的 build.gradle 或 build.gradle.kts 是否存在
  unity_gradle_path = File.join(unity_library_path, "build.gradle")
  unity_gradle_kts_path = File.join(unity_library_path, "build.gradle.kts")
  if File.exist?(unity_gradle_kts_path)
    unity_gradle_path = unity_gradle_kts_path
  elsif !File.exist?(unity_gradle_path)
    return false
  end

  # 检查 build.gradle 中是否包含 Unity 特有的配置
  content = File.read(unity_gradle_path)
  content.include?("com.android.library") && content.include?("BuildIl2Cpp")
end

.unity_as_lib_android_project?(project_path) ⇒ Boolean

Returns:

  • (Boolean)


25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/pindo/module/android/android_project_helper.rb', line 25

def unity_as_lib_android_project?(project_path)
  # Unity 作为 lib 的判断条件简化版:
  # 1. 不是独立的 Unity 导出工程
  return false if unity_android_project?(project_path)

  # 2. 检查是否存在 Unity 目录
  unity_dir = File.join(project_path, "Unity")
  return false unless File.directory?(unity_dir)

  # 3. 检查 Unity 目录下是否有 unityLibrary 目录
  unity_library_dir = File.join(unity_dir, "unityLibrary")
  return false unless File.directory?(unity_library_dir)

  # 4. 检查 Unity/unityLibrary 目录下是否有 build.gradle 或 build.gradle.kts
  gradle_path = File.join(unity_library_dir, "build.gradle")
  gradle_kts_path = File.join(unity_library_dir, "build.gradle.kts")

  File.exist?(gradle_path) || File.exist?(gradle_kts_path)
end