Skip to content

feat(ios): make CoreSVG decoder opt-in - #566

Draft
thiagobrez wants to merge 1 commit into
mainfrom
codex/issue-565-svg-opt-in
Draft

feat(ios): make CoreSVG decoder opt-in#566
thiagobrez wants to merge 1 commit into
mainfrom
codex/issue-565-svg-opt-in

Conversation

@thiagobrez

@thiagobrez thiagobrez commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Closes #565.

Summary

Apple-platform SVG tab icons are now disabled by default. The podspec excludes ios/SVG/**/*, and the SVG decoder is no longer registered app-wide as an RCTImageDataDecoder or generated as a TurboModule. Apps that only use SF Symbols, PNGs, JPEGs, or other ordinary image icons therefore do not compile or link the private-CoreSVG implementation.

Apps that need SVG tab icons can explicitly opt in before React Native configures pods:

$RNBottomTabsEnableSVG = true

Expo prebuild apps can use:

[
  "react-native-bottom-tabs",
  { "enableSVG": true }
]

The opt-in decoder is scoped to bottom-tab icons. Local, remote, and extensionless SVG sources are supported without registering the decoder with React Native's global image pipeline. Android SVG support remains enabled and unchanged.

Design

A Podfile flag is used instead of a subspec because React Native autolinking does not select an optional subspec, CocoaPods includes subspecs by default unless a different default is declared, and—most importantly—a subspec cannot conditionally alter the static package.json codegen registration. Removing that registration and invoking the optional decoder only inside TabViewProvider gives both configurations a coherent result:

  • default: no SVG sources, compile condition, decoder class registration, private symbol strings, or CoreSVG implementation in the built product;
  • opt-in: four SVG source files and the RN_BOTTOM_TABS_ENABLE_SVG Objective-C++/Swift conditions, with local and remote SVG tab icons working;
  • both: an empty generated imageDataDecoderClassNames array, so the decoder never becomes app-wide.

This is a breaking default for existing Apple SVG users, so the PR includes a major changeset. Existing users can preserve behavior by adding the Podfile flag (or Expo plugin option), running pod install, and rebuilding. Documentation and the package README call this out explicitly.

Compatibility and package inspection

  • Full default and opt-in pod installs and Debug simulator builds: React Native 0.81.4, new architecture, CocoaPods 1.17.0, Xcode 27.0.
  • Podspec/helper evaluation in both modes: React Native 0.71.19, 0.76.9, 0.79.7, 0.81.6, 0.84.1, and 0.87.1. Every default evaluation resolved zero SVG sources; every opt-in evaluation resolved exactly CoreSVG.{h,mm} and SvgDecoder.{h,mm}. All podspec lints had zero errors (older helpers retain one unrelated existing -Wno warning).
  • npm pack --dry-run confirms the configuration helper and optional SVG implementation are present in the published package, while NativeSVGDecoder is absent.
  • Default binary scan: RCTTabViewComponentView present as a positive control; CoreSVGWrapper, SvgDecoder, CGSVGDocument, _imageWithCGSVGDocument, and all CoreSVG base64 symbol literals absent from the app, app dylib, and pod static library.
  • Opt-in binary scan: RNBottomTabsDecodeSVGData, CoreSVGWrapper, CGSVGDocument, and the encoded CoreSVG symbol strings present as expected.
  • Fresh React Native codegen: empty imageDataDecoderClassNames; no SvgDecoder or CoreSVGWrapper references.

Validation

  • ruby packages/react-native-bottom-tabs/ios/__tests__/svg_configuration_test.rb — 3 tests, 7 assertions
  • yarn lint — passes with three pre-existing warnings
  • yarn typecheck
  • yarn build
  • yarn build:ios
  • yarn build:android — complete Android native bundle build
  • default and opt-in pod install
  • default and opt-in xcodebuild simulator builds
  • package dry-run, pod source inspection, generated-code inspection, and linked/static binary symbol scans
  • Expo plugin enable/disable generation check: adds and cleanly removes the generated Podfile flag block

yarn test still stops in the unchanged @bottom-tabs/react-navigation workspace because it has a jest script but no tests; this is also true on main. The new focused Ruby tests pass independently.

Device verification

Verified with agent-device 0.20.10 on an iPhone 17 Pro simulator running iOS 26.5, following open → snapshot → interaction → explicit accessibility-state verification → close.

Default configuration:

Opt-in configuration:

The complete evidence notes are in artifacts/issue-565/README.md.

CI

All Draft PR checks pass: lint/typecheck, SwiftLint, package build, Android build, iOS build, CodeQL, and GitHub code scanning for Actions, C/C++, and JavaScript/TypeScript.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

iOS: allow opting out of the private-CoreSVG SVG decoder (exclude_files by default, or an opt-in flag)

1 participant