ann-flavor-cocoapods 0.2.0 → 0.3.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 68dcf959d5d5f927bc43085645168885f76ac29cff73dc973fa9d0d5a8809beb
4
- data.tar.gz: 9d214c8beb19db807200490e5a66e4bc6b22b20539cc950abbf316bb059f3ca7
3
+ metadata.gz: 203077b214e8b6dcbf87c8792ea6df6055d34b4b6ea36af00c1c28a94207aab9
4
+ data.tar.gz: fcdbfba3ba5e54184fb3d05ace52259c10476947259d550cc4b134009d83e560
5
5
  SHA512:
6
- metadata.gz: dfd4c329b80c085c88607557aaa9027793f7a43c680751019608acdfb16d930a71ed9dc7d464a5ea7e2beb608af88148661ac3324083ea40aa8d370b0787b7dd
7
- data.tar.gz: a0c24e164cc92f315382be34c593a6326151db80e33b69f473b7fbb3a3bb19431b6520e4357b7475ea39c0ec573d1a3b3b40ec6486c73fbf2eb872f967191748
6
+ metadata.gz: 1968396623737c7d68439d68cb2fb4d8b8ac6d1da7bba9c32722bc9a0408e3d73fc2b6a4087fbff63231d0d8bd1403949d62e46bf2382a7d9361bd33a7d9fbd1
7
+ data.tar.gz: 5f6f3d65b87f5f8c41d52f6201c622fb379da14d81cf7d6338edf5a76bde7168213c2722f067495d0e8571f0ce35415f67e37538f47f4b5d266e297887672cee
data/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Added
6
+ - **New `[ann-flavor] Merge Info.plist` build phase composes the final
7
+ Info.plist Xcode builds against at build time**, not sync time: copies
8
+ `ios/Runner/Info.plist` (the generic/base layer, developer-owned, always
9
+ present) to `$(DERIVED_FILE_DIR)/Info-merged.plist`, then merges in every
10
+ key from the current flavor's `ios/ann/Info/Info-<flavor>.plist` delta (see
11
+ `ann_flutter_flavor` 1.2.0 — that file now holds only the flavor's
12
+ `info_plist:` cascade, not a full copy of `Runner/Info.plist`), with the
13
+ flavor's value winning on any key both define. Uses `PlistBuddy`
14
+ (`/usr/libexec/PlistBuddy`), not `python3`/`ruby` — ships as part of Xcode
15
+ itself, so this phase adds no dependency on any scripting runtime beyond
16
+ what Xcode already requires. Every plist value type (string, bool, integer,
17
+ real, array, nested dict — e.g. `SKAdNetworkItems`) round-trips correctly
18
+ through the merge, not just strings. Prints a one-line notice to the Xcode
19
+ build log for any key the flavor delta actually overrides, to make an
20
+ unintentional override easy to spot. Found-and-updated in place on a
21
+ re-run, same UUID-stability guarantee as the Firebase-copy and Print Build
22
+ Info phases.
23
+
24
+ ### Changed
25
+ - **`INFOPLIST_FILE` now points at `$(DERIVED_FILE_DIR)/Info-merged.plist`**
26
+ (the Merge Info.plist phase's output above) instead of directly at
27
+ `ios/ann/Info/Info-<flavor>.plist`. Enables `Runner/Info.plist` to remain a
28
+ live, always-consulted base layer instead of a one-time sync-time template
29
+ — the change this whole release exists to support. See
30
+ [plan 038](../../docs/03-planning/features/038-info-plist-build-time-merge.md)
31
+ and the [`Info.plist`
32
+ keys](../../docs/04-userguide/ios/overview.md#infoplist-keys) section of the
33
+ iOS userguide for the full design and migration notes.
34
+
3
35
  ## 0.2.0
4
36
 
5
37
  ### Added
@@ -174,7 +174,6 @@ module AnnFlavorCocoapods
174
174
  # until checked against what the xcconfig #include actually
175
175
  # applied).
176
176
  xcconfig_path = "ann/xcconfig/#{flavor_key}#{bt.capitalize}.xcconfig"
177
- info_plist_path = "ann/Info/Info-#{flavor_key}.plist"
178
177
  icon_name = "#{flavor_key.capitalize}AppIcon"
179
178
 
180
179
  assert_icon_generated!(user_project, flavor_key, icon_name)
@@ -191,7 +190,7 @@ module AnnFlavorCocoapods
191
190
  entitlements_path = nil unless File.exist?(entitlements_file)
192
191
 
193
192
  configure_build_configuration(
194
- target, user_project, xcode_config, xcconfig_path, info_plist_path,
193
+ target, user_project, xcode_config, xcconfig_path,
195
194
  icon_name, entitlements_path
196
195
  )
197
196
  end
@@ -202,6 +201,8 @@ module AnnFlavorCocoapods
202
201
  if print_build_info
203
202
  inject_build_info_phase(target)
204
203
  end
204
+
205
+ inject_merge_info_plist_phase(target)
205
206
  end
206
207
 
207
208
  # Fixes a real pod-install failure: PBXNativeTarget#resolved_build_setting
@@ -598,7 +599,7 @@ module AnnFlavorCocoapods
598
599
  CODE_SIGN_ENTITLEMENTS
599
600
  ].freeze
600
601
 
601
- def self.configure_build_configuration(target, user_project, xcode_config, xcconfig_path, info_plist_path, icon_name, entitlements_path = nil)
602
+ def self.configure_build_configuration(target, user_project, xcode_config, xcconfig_path, icon_name, entitlements_path = nil)
602
603
  config_list = target.build_configuration_list
603
604
  config = config_list[xcode_config]
604
605
 
@@ -624,7 +625,12 @@ module AnnFlavorCocoapods
624
625
  user_project.main_group.new_reference(xcconfig_path)
625
626
  config.base_configuration_reference = xcconfig_ref
626
627
 
627
- config.build_settings['INFOPLIST_FILE'] = info_plist_path
628
+ # Points at the [ann-flavor] Merge Info.plist run-script phase's output
629
+ # (plan 038), not directly at ann/Info/Info-<flavor>.plist -- that file
630
+ # now holds only the flavor's info_plist: cascade delta, not a complete
631
+ # plist; the merge phase composes it with Runner/Info.plist (base) at
632
+ # build time and writes the result here.
633
+ config.build_settings['INFOPLIST_FILE'] = '$(DERIVED_FILE_DIR)/Info-merged.plist'
628
634
  config.build_settings['ASSETCATALOG_COMPILER_APPICON_NAME'] = icon_name
629
635
  # entitlements: is opt-in (unlike INFOPLIST_FILE/the icon catalog, which
630
636
  # every flavor always has) -- only set CODE_SIGN_ENTITLEMENTS when the
@@ -769,5 +775,124 @@ module AnnFlavorCocoapods
769
775
  target.build_phases.unshift(phase)
770
776
  end
771
777
  end
778
+
779
+ # Composes the final Info.plist Xcode actually builds against, from two
780
+ # layers -- Runner/Info.plist (generic/base, developer-owned) and the
781
+ # flavor-specific ann/Info/Info-<flavor>.plist (annspec.yaml's info_plist:
782
+ # cascade, opt-in -- may not exist for a flavor with no cascade) -- with
783
+ # the flavor layer winning on any key collision. Plan 038: since plan 035,
784
+ # ios_generator.dart's _generateInfoPlists used to bake a full copy of
785
+ # Runner/Info.plist into every flavor's generated plist at sync time; that
786
+ # made the generated file impossible to read as "what's actually
787
+ # flavor-specific" and gave nothing else (e.g. a CocoaPods plugin like
788
+ # ann_ads) any way to contribute Info.plist keys, since INFOPLIST_FILE
789
+ # pointed at the fully-resolved flavor file and Runner/Info.plist was
790
+ # never read again. This phase moves that composition to build time
791
+ # instead, so Runner/Info.plist stays a live, always-consulted base layer.
792
+ #
793
+ # Uses PlistBuddy (/usr/libexec/PlistBuddy), not python3/ruby -- PlistBuddy
794
+ # ships as part of Xcode itself, so this phase has no dependency on any
795
+ # scripting runtime beyond what Xcode already requires (OQ-1,
796
+ # docs/03-planning/features/038-info-plist-build-time-merge.md).
797
+ #
798
+ # Runs before_compile, ahead of Xcode's own Info.plist processing --
799
+ # INFOPLIST_FILE (set in configure_build_configuration) points at this
800
+ # phase's output, not at either source file directly.
801
+ def self.inject_merge_info_plist_phase(target)
802
+ script = <<~SHELL
803
+ # Injected by ann-flavor-cocoapods: compose the final Info.plist from
804
+ # two layers -- Runner/Info.plist (generic/base) and the flavor-
805
+ # specific ann/Info/Info-<flavor>.plist (annspec.yaml's info_plist:
806
+ # cascade) -- with the flavor layer winning on any key collision.
807
+ # See docs/03-planning/features/038-info-plist-build-time-merge.md.
808
+ PLISTBUDDY=/usr/libexec/PlistBuddy
809
+ BASE="${SRCROOT}/Runner/Info.plist"
810
+ FLAVOR_NAME="${CONFIGURATION#*-}"
811
+ FLAVOR_PLIST="${SRCROOT}/ann/Info/Info-${FLAVOR_NAME}.plist"
812
+ OUT="${DERIVED_FILE_DIR}/Info-merged.plist"
813
+
814
+ if [ ! -f "$BASE" ]; then
815
+ echo "error: [ann-flavor] Runner/Info.plist not found at $BASE"
816
+ exit 1
817
+ fi
818
+
819
+ # Start from a full copy of the base layer -- every key
820
+ # Runner/Info.plist already has is correct by default; only the
821
+ # flavor delta's keys need explicit merging in below.
822
+ cp "$BASE" "$OUT"
823
+
824
+ if [ ! -f "$FLAVOR_PLIST" ]; then
825
+ echo "warning: [ann-flavor] no flavor Info.plist found for '$FLAVOR_NAME' at $FLAVOR_PLIST -- using Runner/Info.plist unmerged."
826
+ exit 0
827
+ fi
828
+
829
+ # Enumerate the flavor delta's top-level keys. PlistBuddy "Print" with
830
+ # no key path dumps the whole dict; grep the top-level "Key = " lines
831
+ # (four leading spaces = depth 1 in PlistBuddy's indented dump format).
832
+ FLAVOR_KEYS=$("$PLISTBUDDY" -c "Print" "$FLAVOR_PLIST" | grep -E '^ [A-Za-z]' | sed 's/ =.*//' | sed 's/^ *//')
833
+
834
+ for KEY in $FLAVOR_KEYS; do
835
+ # OQ-2: warn (non-fatal) only on a genuine collision -- Runner/Info.plist
836
+ # already had this key, with a different value, before the flavor delta
837
+ # is applied. A net-new key (not previously in Runner/Info.plist) is not
838
+ # a collision and stays silent -- that's the expected, common case.
839
+ # Compared via PlistBuddy's human-readable Print output, which is
840
+ # good enough for equality-detection purposes even though it can't
841
+ # reliably tell types apart (see the VALUE_XML extraction below,
842
+ # which is what actually determines the merged value/type).
843
+ BASE_VALUE=$("$PLISTBUDDY" -c "Print :$KEY" "$OUT" 2>/dev/null)
844
+ BASE_HAD_KEY=$?
845
+ FLAVOR_VALUE=$("$PLISTBUDDY" -c "Print :$KEY" "$FLAVOR_PLIST")
846
+
847
+ if [ "$BASE_HAD_KEY" -eq 0 ] && [ "$BASE_VALUE" != "$FLAVOR_VALUE" ]; then
848
+ echo "[ann-flavor] Info.plist: '$KEY' overridden by flavor value ($FLAVOR_NAME) -- Runner/Info.plist's value ignored for this build."
849
+ fi
850
+
851
+ # Extract the flavor value's own XML fragment (e.g. <string>x</string>,
852
+ # <true/>, <integer>42</integer>, <array>...</array>) via PlistBuddy's
853
+ # -x (XML) output, scoped to just this key, stripping the <plist
854
+ # version="1.0">...</plist> wrapper that -x always adds. This
855
+ # preserves the flavor delta's real plist type -- Print's
856
+ # human-readable output alone can't distinguish an integer 42 from
857
+ # the string "42", or a bool true from the string "true", so a
858
+ # scalar-vs-composite TYPE guess from Print was unreliable and has
859
+ # been replaced with this approach (verified against a real
860
+ # PlistBuddy: bool/int/real/string/array/dict all round-trip
861
+ # correctly this way, plan 038 STEP-02).
862
+ VALUE_XML=$("$PLISTBUDDY" -x -c "Print :$KEY" "$FLAVOR_PLIST" | sed -n '/<plist version/,/<\\/plist>/p' | sed '1d;$d')
863
+
864
+ "$PLISTBUDDY" -c "Delete :$KEY" "$OUT" >/dev/null 2>&1
865
+ FRAGMENT=$(mktemp /tmp/ann-flavor-plist-fragment.XXXXXX)
866
+ cat > "$FRAGMENT" <<XMLEOF
867
+ <?xml version="1.0" encoding="UTF-8"?>
868
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
869
+ <plist version="1.0">
870
+ <dict>
871
+ <key>$KEY</key>
872
+ $VALUE_XML
873
+ </dict>
874
+ </plist>
875
+ XMLEOF
876
+ "$PLISTBUDDY" -c "Merge \\"$FRAGMENT\\"" "$OUT"
877
+ rm -f "$FRAGMENT"
878
+ done
879
+ SHELL
880
+
881
+ # Find-or-update in place, rather than delete+recreate -- same
882
+ # idempotency rationale as inject_build_info_phase above.
883
+ existing = target.build_phases.find { |p| p.respond_to?(:name) && p.name == '[ann-flavor] Merge Info.plist' }
884
+ phase = existing || target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
885
+ phase.name = '[ann-flavor] Merge Info.plist'
886
+ phase.shell_path = '/bin/sh'
887
+ phase.shell_script = script
888
+ phase.show_env_vars_in_log = '0'
889
+ # Declares this phase's output so Xcode's build system understands the
890
+ # dependency (same technique already used for the Firebase-copy phase's
891
+ # output_paths) -- suppresses "input file not found" for INFOPLIST_FILE
892
+ # referencing a path nothing else produces until this phase runs.
893
+ phase.output_paths = ['$(DERIVED_FILE_DIR)/Info-merged.plist']
894
+
895
+ target.build_phases.unshift(phase) unless existing
896
+ end
772
897
  end
773
898
  end
@@ -1,3 +1,3 @@
1
1
  module AnnFlavorCocoapods
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ann-flavor-cocoapods
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ANN Solutions