Module: AnnFlavorCocoapods::PodfileHelper
- Defined in:
- lib/ann_flavor_cocoapods/podfile_helper.rb
Class Method Summary collapse
-
.bundle_id(flavor_key, project_root: Dir.pwd) ⇒ Object
Returns the bundle ID for a given flavor key, merging defaults.
-
.bundle_id_for_build_type(flavor_key, build_type, project_root: Dir.pwd) ⇒ Object
Returns the bundle ID for a given flavor key and build type (e.g. "debug"), applying build_types.id_suffix from either flavor or default.
-
.configure_firebase(installer, project_root: Dir.pwd) ⇒ Object
Call inside your Podfile's post_install hook to wire per-flavor Firebase GoogleService-Info.plist into the Xcode build.
-
.inject_build_phases(installer, project_root, config_map) ⇒ Object
Injects pre-build and post-build shell script phases into the Runner (or umbrella) target for every native target that matches the project.
-
.warn_if_static_plist(project_root, xcode_config, config_file) ⇒ Object
Warn if a static GoogleService-Info.plist already exists in the project; a higher-priority static file would shadow the one we copy at build time.
Class Method Details
.bundle_id(flavor_key, project_root: Dir.pwd) ⇒ Object
Returns the bundle ID for a given flavor key, merging defaults.
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/ann_flavor_cocoapods/podfile_helper.rb', line 69 def self.bundle_id(flavor_key, project_root: Dir.pwd) spec = SpecLoader.load(project_root) flavors = SpecLoader.ios_flavors(spec) default = SpecLoader.ios_default(spec) flavor_cfg = flavors[flavor_key.to_s] || {} merged = default.merge(flavor_cfg) base = merged['id'] || default['id'] || '' suffix = flavor_cfg['id_suffix'] || '' "#{base}#{suffix}" end |
.bundle_id_for_build_type(flavor_key, build_type, project_root: Dir.pwd) ⇒ Object
Returns the bundle ID for a given flavor key and build type (e.g. "debug"), applying build_types.id_suffix from either flavor or default.
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/ann_flavor_cocoapods/podfile_helper.rb', line 84 def self.bundle_id_for_build_type(flavor_key, build_type, project_root: Dir.pwd) spec = SpecLoader.load(project_root) flavors = SpecLoader.ios_flavors(spec) default = SpecLoader.ios_default(spec) flavor_cfg = flavors[flavor_key.to_s] || {} merged = default.merge(flavor_cfg) # Merge build_types maps: flavor overrides default per key default_build_types = default.dig('build_types') || {} flavor_build_types = flavor_cfg.dig('build_types') || {} build_types = default_build_types.merge(flavor_build_types) base = merged['id'] || default['id'] || '' id_suffix = flavor_cfg['id_suffix'] || '' bt_suffix = build_types.dig(build_type.to_s, 'id_suffix') || '' "#{base}#{id_suffix}#{bt_suffix}" end |
.configure_firebase(installer, project_root: Dir.pwd) ⇒ Object
Call inside your Podfile's post_install hook to wire per-flavor Firebase GoogleService-Info.plist into the Xcode build.
Example Podfile usage:
require 'ann_flavor_cocoapods'
post_install do |installer|
AnnFlavorCocoapods::PodfileHelper.configure_firebase(installer)
end
For each iOS flavor that has config_file set, this injects two build phases into the Runner target (or the matching umbrella target):
- A pre-build shell script that copies the correct plist to
${SRCROOT}/Runner/GoogleService-Info.plist at build time.
- A post-build shell script that removes the copied file so the workspace
stays clean and a mis-matched plist cannot accidentally survive.
Gate: only runs when integrations.firebase is true in annspec.yaml.
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/ann_flavor_cocoapods/podfile_helper.rb', line 23 def self.configure_firebase(installer, project_root: Dir.pwd) spec = SpecLoader.load(project_root) # integrations.firebase must be explicitly enabled (REQ-FIRE-00010). return unless spec.dig('app', 'integrations', 'firebase') == true flavors = SpecLoader.ios_flavors(spec) default = SpecLoader.ios_default(spec) # Build a map: configuration_name → config_file path. # Xcode configuration names are capitalized: Release-<flavor>, Debug-<flavor>. config_map = {} flavors.each do |flavor_key, flavor_cfg| merged = default.merge(flavor_cfg || {}) default_build_types = default.dig('build_types') || {} flavor_build_types = (flavor_cfg || {}).dig('build_types') || {} build_types = default_build_types.merge(flavor_build_types) %w[release debug].each do |bt| bt_fb = build_types.dig(bt, 'firebase') || {} fb_file = bt_fb['config_file'] project_id = bt_fb['project_id'] if fb_file.nil? && project_id # project_id mode — derive plist from stable generated path. fb_file = "lib/generated/firebase/GoogleService-Info-#{flavor_key}-#{bt}.plist" end next unless fb_file # Map Xcode config name (e.g. "Release-ledger_in") → plist path xcode_config = "#{bt.capitalize}-#{flavor_key}" config_map[xcode_config] = fb_file warn_if_static_plist(project_root, xcode_config, fb_file) end end return if config_map.empty? return if installer.nil? inject_build_phases(installer, project_root, config_map) end |
.inject_build_phases(installer, project_root, config_map) ⇒ Object
Injects pre-build and post-build shell script phases into the Runner (or umbrella) target for every native target that matches the project.
119 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 145 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 |
# File 'lib/ann_flavor_cocoapods/podfile_helper.rb', line 119 def self.inject_build_phases(installer, project_root, config_map) # Build the per-config shell that selects the right source file. # Uses a case statement keyed on $CONFIGURATION (Xcode build setting). case_body = config_map.map do |xcode_config, plist_path| " #{xcode_config}) SRC_PLIST=\"${SRCROOT}/../#{plist_path}\" ;;" end.join("\n") pre_build_script = <<~SHELL # Injected by ann-flavor-cocoapods: copy per-flavor GoogleService-Info.plist case "$CONFIGURATION" in #{case_body} *) echo "ann-flavor-cocoapods: no Firebase plist for $CONFIGURATION"; exit 0 ;; esac DEST="${SRCROOT}/Runner/GoogleService-Info.plist" if [ ! -f "$SRC_PLIST" ]; then echo "ann-flavor-cocoapods ERROR: Firebase plist not found: $SRC_PLIST" exit 1 fi cp "$SRC_PLIST" "$DEST" echo "ann-flavor-cocoapods: copied $SRC_PLIST -> $DEST" SHELL post_build_script = <<~SHELL # Injected by ann-flavor-cocoapods: remove copied GoogleService-Info.plist after build DEST="${SRCROOT}/Runner/GoogleService-Info.plist" rm -f "$DEST" echo "ann-flavor-cocoapods: removed $DEST" SHELL installer.pods_project.targets.each do |target| next unless target.name == 'Pods-Runner' # Avoid duplicate injection on repeated pod install runs. next if target.build_phases.any? { |p| p.respond_to?(:shell_script) && p.shell_script.include?('ann-flavor-cocoapods: copy per-flavor') } pre = target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) pre.name = '[ann-flavor] Copy Firebase plist' pre.shell_path = '/bin/sh' pre.shell_script = pre_build_script pre.show_env_vars_in_log = '0' target.build_phases.unshift(pre) post = target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) post.name = '[ann-flavor] Remove Firebase plist' post.shell_path = '/bin/sh' post.shell_script = post_build_script post.show_env_vars_in_log = '0' target.build_phases << post puts "ann-flavor-cocoapods: injected Firebase build phases into #{target.name} " \ "(#{config_map.size} configuration(s))" end end |
.warn_if_static_plist(project_root, xcode_config, config_file) ⇒ Object
Warn if a static GoogleService-Info.plist already exists in the project; a higher-priority static file would shadow the one we copy at build time.
107 108 109 110 111 112 113 114 115 |
# File 'lib/ann_flavor_cocoapods/podfile_helper.rb', line 107 def self.warn_if_static_plist(project_root, xcode_config, config_file) static_path = File.join(project_root, 'ios', 'Runner', 'GoogleService-Info.plist') if File.exist?(static_path) puts "ann-flavor-cocoapods WARNING: A static GoogleService-Info.plist exists at " \ "ios/Runner/GoogleService-Info.plist. It will be overwritten at build time " \ "for configuration '#{xcode_config}' (source: #{config_file}). " \ "Remove the static file to silence this warning." end end |