Module: Pindo::KeystoreHelper
- Defined in:
- lib/pindo/module/android/keystore_helper.rb
Constant Summary collapse
- ENV_RELEASE_KEYSTORE_PATH =
与工程约定一致:Gradle 内用 RELEASE_* 环境变量 + 本地 ?: 回退;pindo 拉取 JPS 后写入当前进程 ENV(不落盘明文)
"RELEASE_KEYSTORE_PATH"- ENV_RELEASE_KEYSTORE_PASSWORD =
"RELEASE_KEYSTORE_PASSWORD"- ENV_RELEASE_KEY_ALIAS =
"RELEASE_KEY_ALIAS"- ENV_RELEASE_KEY_PASSWORD =
"RELEASE_KEY_PASSWORD"- FIELD_CRYPTO_ALGORITHM =
"aes-128-gcm"- FIELD_CRYPTO_KEY =
"WNldU35bhG!8TQtg"- FIELD_CRYPTO_IV_LENGTH =
12- FIELD_CRYPTO_TAG_LENGTH =
16
Class Method Summary collapse
-
.apply_keystore_config(project_dir, build_type = "debug", bundle_id:) ⇒ Boolean
将签名配置应用到 Android 工程.
-
.cleanup_managed_signing_env! ⇒ Object
清理本次写入到进程 ENV 的签名变量(避免后续任务误继承).
-
.cleanup_managed_signing_paths! ⇒ Object
打包结束后由 AndroidBuildHelper.ensure 调用,删除本次落到工程 signing/ 下的 JKS.
-
.get_android_sign_config(bundle_id:) ⇒ Hash
从 JPS 获取 Android 签名配置(必须成功,否则抛出异常).
-
.get_keystore_config_from_project(project_path, debug = false, workflow_build_type: nil) ⇒ Hash?
从工程的 build.gradle 中读取已有的 keystore 配置.
-
.resolve_keystore_paths(config) ⇒ Hash
解析 keystore 文件路径.
-
.restore_managed_signing_config! ⇒ Object
打包结束后恢复本次被修改的 Gradle 签名配置(仅恢复被本次任务改动过的文件).
-
.validate_sign_config(config) ⇒ Boolean
验证签名配置格式.
Class Method Details
.apply_keystore_config(project_dir, build_type = "debug", bundle_id:) ⇒ Boolean
将签名配置应用到 Android 工程
默认(与工程手写的 RELEASE_* 约定一致):只拉取 JPS、拷贝 jks 到项目 signing/,并设置当前进程RELEASE_KEYSTORE_PATH / RELEASE_KEYSTORE_PASSWORD / RELEASE_KEY_ALIAS / RELEASE_KEY_PASSWORD,不修改 build.gradle。RELEASE_KEYSTORE_PATH 使用 jks 的绝对路径,便于 app 子模块内 ‘file(System.getenv(…))` 引用。
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 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 156 def apply_keystore_config(project_dir, build_type = "debug", bundle_id:) raise ArgumentError, "项目目录不能为空" if project_dir.nil? raise ArgumentError, "build_type 必须是 debug 或 release" unless ["debug", "release"].include?(build_type) raise ArgumentError, "bundle_id 不能为空" if bundle_id.blank? reset_managed_signing_paths! reset_managed_gradle_backups! reset_managed_env_keys! main_module = Pindo::AndroidProjectHelper.get_main_module(project_dir) unless main_module Funlog.error("无法找到主模块") return false end gradle_file = find_gradle_file(main_module) unless gradle_file Funlog.error("无法找到 build.gradle 文件") return false end sign_config = get_android_sign_config(bundle_id: bundle_id) copy_keystore_to_project(project_dir, build_type, sign_config[build_type]) # JPS 下载的临时 jks(系统临时目录下 pindo_jks),拷贝进工程后即可删除 tmp_jks = sign_config[build_type]["storeFile"].to_s if File.exist?(tmp_jks) tmp_exp = File.(tmp_jks) tmp_root_exp = File.(File.join(Dir.tmpdir, "pindo_jks")) under_pindo_tmp = tmp_exp == tmp_root_exp || tmp_exp.start_with?(tmp_root_exp + File::SEPARATOR) FileUtils.rm_f(tmp_jks) if under_pindo_tmp end cfg = sign_config[build_type] rel_plain = cfg["relative_store_file"].to_s.sub(%r{\A\$rootDir/?}, "").delete_prefix("/") if rel_plain.empty? raise "JPS keystore 未拷贝到工程 signing/(无法解析路径),Gradle 将回退到 build.gradle 中的本地 jks;请检查 JPS 证书是否下载成功" end if gradle_file.end_with?(".kts") ensure_keystore_config_kts(gradle_file, project_dir, build_type, sign_config, bundle_id: bundle_id) else ensure_keystore_config_groovy(gradle_file, project_dir, build_type, sign_config, bundle_id: bundle_id) end # 注意:部分 Unity 导出工程/多模块工程的 Gradle rootProject 目录可能不是 project_dir, # 相对路径(如 signing/xxx.jks)会被解析到错误的模块目录下(如 launcher/signing/...)。 # 这里改为导出绝对路径,确保与 keystore 创建/拷贝目录保持一致。 keystore_abs = File.(File.join(project_dir, rel_plain)) export_jps_release_signing_env!(cfg, keystore_path_for_env: keystore_abs) true end |
.cleanup_managed_signing_env! ⇒ Object
清理本次写入到进程 ENV 的签名变量(避免后续任务误继承)
140 141 142 143 144 145 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 140 def cleanup_managed_signing_env! keys = @pindo_managed_env_keys || [] keys.each { |k| ENV.delete(k.to_s) if k } ensure @pindo_managed_env_keys = [] end |
.cleanup_managed_signing_paths! ⇒ Object
打包结束后由 AndroidBuildHelper.ensure 调用,删除本次落到工程 signing/ 下的 JKS
118 119 120 121 122 123 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 118 def cleanup_managed_signing_paths! (@pindo_managed_signing_paths || []).each do |p| FileUtils.rm_f(p) if p && File.exist?(p) end @pindo_managed_signing_paths = [] end |
.get_android_sign_config(bundle_id:) ⇒ Hash
从 JPS 获取 Android 签名配置(必须成功,否则抛出异常)
30 31 32 33 34 35 36 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 30 def get_android_sign_config(bundle_id:) raise ArgumentError, "bundle_id 不能为空" if bundle_id.blank? cfg = fetch_jks_from_jps(bundle_id: bundle_id) # debug 和 release 使用同一个 JKS { "debug" => cfg, "release" => cfg } end |
.get_keystore_config_from_project(project_path, debug = false, workflow_build_type: nil) ⇒ Hash?
从工程的 build.gradle 中读取已有的 keystore 配置
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 98 def get_keystore_config_from_project(project_path, debug = false, workflow_build_type: nil) main_module = Pindo::AndroidProjectHelper.get_main_module(project_path) return unless main_module gradle_kts_path = File.join(main_module, "build.gradle.kts") gradle_path = File.join(main_module, "build.gradle") if File.exist?(gradle_kts_path) puts "KTS 项目,读取 #{File.basename(gradle_kts_path)} 文件" get_keystore_config_kts(gradle_kts_path, project_path, debug, workflow_build_type: workflow_build_type) elsif File.exist?(gradle_path) puts "Groovy 项目,读取 #{File.basename(gradle_path)} 文件" get_keystore_config_groovy(gradle_path, project_path, debug, workflow_build_type: workflow_build_type) else puts "未找到 build.gradle 或 build.gradle.kts 文件" nil end end |
.resolve_keystore_paths(config) ⇒ Hash
解析 keystore 文件路径
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 68 def resolve_keystore_paths(config) # 使用 PindoConfig 获取配置目录 pindo_config = Pindoconfig.instance pindo_common_config_dir = pindo_config.pindo_common_configdir resolved_config = {} ["debug", "release"].each do |build_type| next if config[build_type].nil? cfg = config[build_type].dup store_file = cfg["storeFile"] # 如果是相对路径,则基于 pindo_common_config 目录解析 cfg["storeFile"] = File.join(pindo_common_config_dir, store_file) unless store_file.start_with?("/") # 验证文件是否存在 Funlog.warning("Keystore 文件不存在: #{cfg["storeFile"]}") unless File.exist?(cfg["storeFile"]) resolved_config[build_type] = cfg end resolved_config end |
.restore_managed_signing_config! ⇒ Object
打包结束后恢复本次被修改的 Gradle 签名配置(仅恢复被本次任务改动过的文件)
126 127 128 129 130 131 132 133 134 135 136 137 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 126 def restore_managed_signing_config! backups = @pindo_managed_gradle_backups || {} backups.each do |path, original_content| next if path.nil? || path.to_s.empty? next unless original_content.is_a?(String) next unless File.exist?(path) File.write(path, original_content) end ensure @pindo_managed_gradle_backups = {} end |
.validate_sign_config(config) ⇒ Boolean
验证签名配置格式
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/pindo/module/android/keystore_helper.rb', line 41 def validate_sign_config(config) return false unless config.is_a?(Hash) # 至少需要有 debug 或 release 配置 return false if config["debug"].nil? && config["release"].nil? # 验证每个配置的必需字段 ["debug", "release"].each do |build_type| next if config[build_type].nil? cfg = config[build_type] required_fields = %w[storeFile storePassword keyAlias keyPassword] required_fields.each do |field| if cfg[field].nil? || cfg[field].to_s.empty? Funlog.error("#{build_type} 配置缺少必需字段: #{field}") return false end end end true end |