Class: FastlaneFlutterFlavor::PodspecBridge

Inherits:
Object
  • Object
show all
Defined in:
lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(loader, flavor, project_root, config_name = nil) ⇒ PodspecBridge

Returns a new instance of PodspecBridge.



90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 90

def initialize(loader, flavor, project_root, config_name = nil)
  @loader = loader
  @flavor = flavor
  @project_root = project_root
  @platform = :ios

  # BUILD TYPE DETECTION: Prioritize Flutter CLI mode, fallback to config name regex
  flutter_mode = ENV['FLUTTER_BUILD_MODE']&.downcase
  active_config = config_name || ENV['CONFIGURATION'] || ""

  if flutter_mode && !flutter_mode.empty?
    # Profile mode maps to release for production-like behavior
    @build_type = (flutter_mode == 'profile') ? 'release' : flutter_mode
  elsif active_config.match?(/debug/i)
    @build_type = 'debug'
  else
    @build_type = 'release'
  end
end

Class Method Details

.apply_build_settings(installer) ⇒ Object

Injects YAML values into the Xcode Project Build Settings



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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 39

def self.apply_build_settings(installer)
  project = nil

  installer.aggregate_targets.each do |target|
    target.user_project.targets.each do |user_target|
      # Only apply to the main app target (Runner)
      next unless user_target.name == 'Runner'
      project = target.user_project

      user_target.build_configurations.each do |config|
        # Initialize bridge per configuration iteration
        bridge = self.current_config(config.name)
        s = config.build_settings

        # Injection Mapping: YAML -> Xcode Build Settings (User-Defined)
        s['ASSET_PREFIX']              = bridge.asset_prefix
        s['APP_DISPLAY_NAME']          = bridge.display_name
        s['PRODUCT_BUNDLE_IDENTIFIER'] = bridge.bundle_id
        s['MARKETING_VERSION']         = bridge.version_name
        s['CURRENT_PROJECT_VERSION']   = bridge.version_code
        s['GMS_ADS_ID']                = bridge.gms_ads_id
        s['REVERSED_CLIENT_ID']        = bridge.auth_reversed_client_id
        s['GOOGLE_APP_ID']             = bridge.google_app_id

        # Optional: Auto-set development team from YAML if present
        s['DEVELOPMENT_TEAM']          = bridge.team_id if bridge.team_id
      end
    end
  end

  installer.pods_project.targets.each do |pod_target|
    pod_target.build_configurations.each do |config|
      bridge = self.current_config(config.name)
      s = config.build_settings

      # We push the specific keys needed by the podscripts
      s['GMS_ADS_ID']           = bridge.gms_ads_id
      s['APP_DISPLAY_NAME']     = bridge.display_name
      s['GOOGLE_APP_ID']        = bridge.google_app_id
      s['REVERSED_CLIENT_ID']   = bridge.auth_reversed_client_id

    end
  end

  # Save the project once after all configurations are updated
  project.save if project

  log_flavor = ENV['FLUTTER_APP_FLAVOR'] || "detected"
  puts "[Annai] Successfully injected flavor '#{log_flavor}' settings into Xcode configurations."
end

.current_config(config_name = nil) ⇒ Object

Static entry point to initialize the bridge.

Parameters:

  • config_name (String) (defaults to: nil)

    optional specific Xcode configuration name (e.g., "Debug-ledger_in")



6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 6

def self.current_config(config_name = nil)
  # 1. FLAVOR DETECTION: Prioritize Flutter CLI, fallback to config name parsing
  flavor = ENV['FLUTTER_APP_FLAVOR']
  if flavor.nil? || flavor.empty?
    active_config = config_name || ENV['CONFIGURATION'] || ""
    flavor = active_config.split('-').last
  end

  # 2. SMART ROOT DETECTION
  # Start from the current directory and walk up until we find annspec.yaml
  search_dir = Dir.pwd
  spec_file = 'annspec.yaml'
  root = nil

  # Walk up to 10 levels to find the project root
  10.times do
    if File.exist?(File.join(search_dir, spec_file))
      root = search_dir
      break
    end
    search_dir = File.expand_path('..', search_dir)
  end

  if root.nil?
    raise "Could not find #{spec_file} in #{Dir.pwd} or any parent directories. " +
            "Ensure you are running pod install from your Flutter project's /ios folder."
  end

  loader = YamlSpecLoader.new(root, spec_file)
  self.new(loader, flavor, root, config_name)
end

Instance Method Details

#asset_prefixObject

--- Interface Methods (Proxy to YamlSpecLoader) ---



112
113
114
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 112

def asset_prefix
  @flavor
end

#auth_client_idObject



140
141
142
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 140

def auth_client_id
  @loader.get_auth_client_id(@platform, @flavor, @build_type)
end

#auth_reversed_client_idObject



144
145
146
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 144

def auth_reversed_client_id
  @loader.get_auth_reversed_client_id(@platform, @flavor, @build_type)
end

#bundle_idObject



120
121
122
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 120

def bundle_id
  @loader.get_package_id(@platform, @flavor)
end

#display_nameObject



116
117
118
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 116

def display_name
  @loader.get_display_name(@platform, @flavor)
end

#gms_ads_idObject



132
133
134
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 132

def gms_ads_id
  @loader.get_gms_ads_id(@platform, @flavor)
end

#google_app_idObject



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
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 148

def google_app_id
  # Primary: read appId from the generated firebase_options dart file.
  # File is generated by `dart run ann_flutter_flavor sync` and committed to the repo.
  dart_file = File.join(
    @project_root,
    "lib/generated/firebase/#{@flavor}_#{@build_type}_ios_firebase_options.dart"
  )
  if File.exist?(dart_file)
    content = File.read(dart_file)
    match = content.match(/appId:\s*'([^']+)'/) ||
            content.match(/appId:\s*"([^"]+)"/)
    return match[1] if match
  end

  # Fallback: ANN_GOOGLE_APP_ID env var — use when the dart file is missing
  # (e.g. fresh CI environment before sync has been run).
  env_value = ENV['ANN_GOOGLE_APP_ID']
  if env_value && !env_value.empty?
    Fastlane::UI.important(
      "[Annai] GOOGLE_APP_ID read from ANN_GOOGLE_APP_ID env var for " \
      "#{@flavor}/#{@build_type}. Run 'dart run ann_flutter_flavor sync' " \
      "to generate the source file and remove this dependency."
    )
    return env_value
  end

  ''
end

#team_idObject



136
137
138
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 136

def team_id
  @loader.get_team_id(@platform, @flavor)
end

#version_codeObject



128
129
130
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 128

def version_code
  @loader.get_version_code(@platform, @flavor)
end

#version_nameObject



124
125
126
# File 'lib/fastlane/plugin/ann_flavor_flutter/helper/podspec_bridge.rb', line 124

def version_name
  @loader.get_version_name(@platform, @flavor)
end