Repository navigation
feat(ios): make CoreSVG decoder opt-in - #606
oleksandrzavarzin-callstack wants to merge 11 commits into
Conversation
|
Hey @oleksandrzavarzin-callstack, thanks for picking this up from #566. The codegen, modulemap and SPM work is solid. I'm asking for a change of direction on two points, plus a few smaller findings. 1. Let's not ship a breaking change nowKeep SVG enabled by default in this release, and make disabling it the opt-in. Flipping the default should wait for the next major. Suggested shape: a single tri-state flag, so the next major doesn't need a new one:
Please flag the upcoming change in these places:
2.
|
|
Thanks @thiagobrez! I've done:
|
|
@apex-sentinel-staging review |
|
/review |
Apex SentinelVerdict: 11 finding(s): 6 minor, 5 nit. Verdict: approve. reached max rounds (1). 🟡 Minor (6)
🔵 Nit (5)
Reply under an inline comment with |
There was a problem hiding this comment.
Apex Sentinel: 11 new findings on da9795f. The verdict and the full list are in the summary comment.
| // unset -> enabled, with a deprecation notice in dev builds | ||
| // 1 / true -> enabled | ||
| // 0 / false -> disabled, no private CoreSVG code is compiled | ||
| let svgSetting = Context.environment["RN_BOTTOM_TABS_ENABLE_SVG"]? |
There was a problem hiding this comment.
🟡 Minor · SwiftPM accepts only 0/false/no and silently enables on anything else, unlike the Ruby path which raises
enableSVG = !["0", "false", "no"].contains(svgSetting ?? "") (Package.swift:15) treats every other non-empty value as "enabled", and because svgSettingIsUnset is false in that case RN_BOTTOM_TABS_SVG_DEFAULTED is not defined either — so there is no deprecation notice and no error. RN_BOTTOM_TABS_ENABLE_SVG=off (or a typo such as flase, or yes) therefore leaves the private CoreSVG dlsym calls and base64 literals in the binary with no signal at all, while the identical value under CocoaPods hard-fails pod install with ArgumentError (svg_configuration.rb:28-33). The two readers of the same variable also disagree on the accepted vocabulary: the Ruby side accepts yes as true, the SwiftPM side does not.
Suggested change
Use one accepted-value set in both readers (true/1/yes, false/0/no, anything else is an error) and make Package.swift fail the resolution with a clear message — e.g. preprocessWarning/a forced fatalError-style diagnostics — instead of defaulting to enabled for a value the Podfile path rejects.
Details
Also raised here
Also raised at this location by javascript: SwiftPM accepts flag values that the Podfile path rejects as an error — Package.swift enables SVG for anything that is not exactly 0/false/no after lowercasing and whitespace removal, so a typo or an unexpected value (RN_BOTTOM_TABS_ENABLE_SVG=flase, off, no , 2) silently produces an SVG-enabled build — i.e. the private CoreSVG code the author asked to remove stays linked, with no diagnostic. The CocoaPods path in ios/svg_configuration.rb treats exactly the same input as a hard error (raise ArgumentError), so the two flag readers disagree: the same environment value either aborts pod install or silently changes the binary depending on which build system the app uses. Note svgSettingIsUnset also only checks isEmpty, so a whitespace-only value (' ') is treated as unset in the Ruby path (strip → nil → DEFAULTED warning) and coincidentally matches here, but any other non-empty unknown value falls through to "enabled".
Also raised at this location by senior-developer: SwiftPM and CocoaPods disagree on an unsupported flag value: env var silently enables SVG, Podfile hard-fails pod install — Package.swift:15 decides with !=["0", "false", "no"].contains(svgSetting ?? ""), i.e. anything that is not exactly one of those three strings enables the decoder, while svg_configuration.rb:22-34 raises ArgumentError for anything that is not in TRUE_VALUES/FALSE_VALUES/empty. Setting RN_BOTTOM_TABS_ENABLE_SVG=true gives the same result in both paths, but a typo such as RN_BOTTOM_TABS_ENABLE_SVG=ture (or enabled, OFF) silently enables the private CoreSVG code for an app that intended to remove it — exactly the outcome the flag exists to guarantee, and the CI assertion Check that no private CoreSVG code is linked would only catch it in the job that sets the value itself. The same typo in $RNBottomTabsEnableSVG aborts pod install with a clear ArgumentError. …
Also raised at this location by maintainability: SwiftPM silently enables SVG for an unrecognized flag value where the podspec raises — enableSVG = !["0", "false", "no"].contains(svgSetting ?? "") only matches the negative list, so a typo such as RN_BOTTOM_TABS_ENABLE_SVG=flase resolves to enabled and compiles the private CoreSVG code into the app, the opposite of what the author asked for. Worse, .filter { !$0.isWhitespace } strips whitespace from anywhere in the value instead of trimming it, so "0 1" becomes "01" and is enabled too. svg_configuration.rb#setting raises ArgumentError for exactly this input (locked in by test_unsupported_value_raises), so the two configuration paths disagree on the same bad value. Validate against explicit true/false lists and preconditionFailure on anything else.
persona: swift-ios, javascript, senior-developer, maintainability
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging like
There was a problem hiding this comment.
Fixed
| ], | ||
| "scripts": { | ||
| "test": "jest", | ||
| "test": "ruby ios/__tests__/svg_configuration_test.rb && jest", |
There was a problem hiding this comment.
🟡 Minor · test script now hard-depends on ruby, breaking yarn test where Ruby is absent
packages/react-native-bottom-tabs/package.json:41 changes "test": "jest" to "test": "ruby ios/__tests__/svg_configuration_test.rb && jest". Ruby is not a devDependency of this repo, it is not declared in any engines/CI requirement for the jobs that run the tests, and it is not present in every environment the package is tested in (in this very review sandbox ruby is not on PATH: bash: line 1: ruby: command not found). Because of &&, a missing ruby binary aborts the whole script before jest runs, so all JS tests silently stop running: the failure mode is the most alarming one (the JS suite never executes) and a contributor or CI runner on a Ruby-less image (a plain Node container, Windows without RubyInstaller, a sandboxed CI image) will get "ruby: command not found" and no JS coverage at all. There is also no Gemfile/gemspec declaring the minitest dependency the new test requires. Suggested fix: run the Ruby suite from a dedicated job/step guarded by a Ruby setup action (or a test:ruby script the CI matrix invokes) so yarn test stays runnable with only Node, and add the Ruby/minitest provisioning to CI explicitly.
| "test": "ruby ios/__tests__/svg_configuration_test.rb && jest", | |
| "test": "jest", | |
| "test:ruby": "ruby ios/__tests__/svg_configuration_test.rb", |
Suggested change
Move the Ruby suite out of the test script (e.g. a separate test:ruby script invoked by a CI job that installs Ruby), so yarn test keeps working where Ruby is not installed, and declare the Ruby/minitest requirement for CI.
Details
Also raised here
Also raised at this location by javascript: New Ruby flag tests are never run on CI (no job invokes yarn test) — The package's test script becomes ruby ios/__tests__/svg_configuration_test.rb && jest, so the new flag logic is covered only by that script — but no job in .github/workflows/ci.yml invokes yarn test (the jobs are lint (which runs yarn lint/yarn typecheck), swift-lint, build-library, build-android, build-ios, and the two jobs added here). The 6 new Ruby tests for svg_configuration.rb — the code that decides whether the private CoreSVG code is compiled — therefore never run on CI, and the PR description's "yarn test: passes, with 6 Ruby tests" reflects a local run only. Two consequences: (a) a regression in setting/xcconfig/warn_if_unset (e.g. the Podfile-wins-over-env rule or the GCC_PREPROCESSOR_DEFINITIONS string) merges silently, and (b) on any contributor machine or runner image without a ruby binary the whole test script now fails, not just the Ruby part, because && short-circuits before jest.
Also raised at this location by swift-ios: package.json test script depends on a bare ruby binary, with no CI job that runs it — "test": "ruby ios/__tests__/svg_configuration_test.rb && jest" (package.json:41) makes the whole package's test suite fail outright wherever ruby is not on PATH (sh: ruby: command not found → exit 127, and jest never runs). No workflow in .github/workflows invokes yarn test/yarn jest/turbo run test (only build/typecheck/lint do), so the six new Ruby tests the PR description counts on never run in CI either, while a contributor on Windows without Ruby gets a red yarn test for an unrelated change.
persona: javascript, swift-ios, senior-developer
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging like
There was a problem hiding this comment.
Fixed
| contents: string, | ||
| enableSVG: boolean | undefined | ||
| ): string { | ||
| const lines = contents.split('\n'); |
There was a problem hiding this comment.
🟡 Minor · setPodfileSVGFlag leaves a duplicated flag when the generated block's end marker is missing
packages/react-native-bottom-tabs/src/expoPodfile.ts:15-22 removes the generated block only when both markers are found (if (start !== -1 && end !== -1)). If the Podfile's generated block end line is deleted or altered (a user tidying the file, a merge conflict resolved badly, or a previous prebuild whose end-marker line got a trailing suffix), start is found and end is -1, nothing is spliced out, and lines 27-33 then insert a second # @generated begin ... / $RNBottomTabsEnableSVG = <value> / end block. Result: the Podfile ends up with two $RNBottomTabsEnableSVG assignments, and — because the insertion point is platformLine + 1 while the orphan block sits elsewhere — the one that actually wins is whichever appears last in the file, not the one the plugin just wrote. enableSVG: true in app.json can therefore be silently overridden by a stale false (or vice versa) with no error. Nothing in src/__tests__/expoPodfile.test.ts covers the start-without-end case. Handling the orphan (drop everything from start to the next marker or to end-of-block, or remove any stray $RNBottomTabsEnableSVG line before inserting) makes the write idempotent regardless of file state.
| const lines = contents.split('\n'); | |
| const lines = contents.split('\n'); | |
| const start = lines.findIndex((line) => line.startsWith(BLOCK_START)); | |
| const end = lines.findIndex( | |
| (line, index) => index > start && line.startsWith(BLOCK_END) | |
| ); | |
| if (start !== -1) { | |
| lines.splice(start, (end === -1 ? lines.length : end + 1) - start); | |
| } |
Suggested change
Make the removal branch handle a start marker without an end marker (and add a test for it), so a hand-edited Podfile cannot end up with two conflicting $RNBottomTabsEnableSVG assignments whose winner depends on line order.
Details
persona: senior-developer, javascript
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging like
There was a problem hiding this comment.
Fixed
|
|
||
| @synthesize callableJSModules = _callableJSModules; | ||
|
|
||
| #if RCT_DEV |
There was a problem hiding this comment.
🟡 Minor · The dev warning is sent by invoking the JS module named "RCTLog" with method "logToConsole", but RCTLog is not a call…
The dev warning is sent by invoking the JS module named "RCTLog" with method "logToConsole", but RCTLog is not a callable JS module in React Native, so RCTCallableJSModules.invokeModule would drop the call and neither the DevTools warning nor the LogBox entry the PR description reports would appear; only NSLog would.
Details
Noted in the reviewer's candidate ledger and not refuted before the budget ran out.
persona: maintainability
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging pivot RCTLog is a callable JS module. Libraries/Core/setUpBatchedBridge.js registers it with registerModule('RCTLog', ...). I tested this with Metro: the warning shows in the React Native DevTools console.
| withMaterial3Theme, | ||
| 'react-native-bottom-tabs' | ||
| ); | ||
| const withSVGSupport: ConfigPlugin<ConfigProps> = (config, options) => { |
There was a problem hiding this comment.
🟡 Minor · Prebuild deletes a hand-set $RNBottomTabsEnableSVG block for consumers who leave enableSVG unset
withSVGSupport unconditionally rewrites the app's Podfile on every expo prebuild, even when the consumer never opted in: withBottomTabs always calls withSVGSupport, and when options?.enableSVG is undefined the withPodfile mod still runs setPodfileSVGFlag(contents, undefined), which removes any existing # @generated begin react-native-bottom-tabs-svg … # @generated end block. So a user who hand-wrote the generated block (or who keeps $RNBottomTabsEnableSVG only in the Podfile and leaves the plugin option out) loses it on the next prebuild, and the build silently reverts to "flag unset" — SVG enabled plus the deprecation warning — instead of the choice they encoded. Note also that the module-level default is what makes this happen: the mod is registered unconditionally rather than only when enableSVG !== undefined, so the plugin now dirties a file it was previously never given write access to for every existing consumer.
| const withSVGSupport: ConfigPlugin<ConfigProps> = (config, options) => { | |
| const withSVGSupport: ConfigPlugin<ConfigProps> = (config, options) => { | |
| if (options?.enableSVG === undefined) { | |
| return config; | |
| } | |
| return withPodfile(config, (podfileConfig) => { |
Suggested change
Skip the withPodfile mod entirely when options?.enableSVG === undefined (return config unchanged) so the plugin neither registers a Podfile writer nor deletes a flag block the user added by hand; document that the removal path is enableSVG: true/false only.
Details
persona: javascript
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging note This is on purpose. The plugin generates this block and marks it "DO NOT MODIFY". If the user removes enableSVG from app.json, the plugin must remove the block, or a stale value stays. To set the flag by hand, you add $RNBottomTabsEnableSVG outside the generated block, and the plugin does not touch that line.
| ], | ||
| publicHeadersPath: "ios/include", | ||
| cxxSettings: [ | ||
| cSettings: svgDefines.filter(\.enabled).map { .define($0.name, to: "1") }, |
There was a problem hiding this comment.
🔵 Nit · Duplicated filter(\.enabled).map define expression and diverging whitespace handling between Package.swift and svg_configuration.rb
svgDefines.filter(\.enabled).map { .define($0.name, to: "1") } is written out twice (lines 83 and 84) for cSettings and cxxSettings; a single let svgSettings = svgDefines.filter(\.enabled).map { .define($0.name, to: "1") } bound above let package removes the duplication and the risk of the two lists diverging. Related: the Ruby reader normalizes with value.to_s.strip.downcase while the Swift one uses .filter { !$0.isWhitespace }.lowercased(), which also deletes inner whitespace — the two readers keep drifting apart because neither derives from the other.
| cSettings: svgDefines.filter(\.enabled).map { .define($0.name, to: "1") }, | |
| cSettings: svgSettings, | |
| cxxSettings: svgSettings + [ |
Details
Also raised here
Also raised at this location by maintainability: The svgDefines -> defines mapping is duplicated across cSettings and cxxSettings — Compute it once into a let above let package and reuse it, so the two lists cannot drift when a third define is added.
persona: javascript, maintainability
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging like
There was a problem hiding this comment.
Fixed
|
|
||
| import PackageDescription | ||
|
|
||
| // The SVG image decoder uses private CoreSVG APIs. RN_BOTTOM_TABS_ENABLE_SVG controls it |
There was a problem hiding this comment.
🔵 Nit · Package.swift comment documents a different set of accepted values than the code it sits above
The new comment lists unset / 1 / true / 0 / false, but enableSVG also treats "no" as disabled, matching FALSE_VALUES in svg_configuration.rb whose own comment table lists its values. This is a third hand-copied list of accepted values that already disagrees with the code, and the next value added to TRUE_VALUES/FALSE_VALUES has to be remembered in all three places. Document "no" (and "yes" on the true side) or drop it, so the SwiftPM table matches the Ruby one.
| // The SVG image decoder uses private CoreSVG APIs. RN_BOTTOM_TABS_ENABLE_SVG controls it | |
| // The SVG image decoder uses private CoreSVG APIs. RN_BOTTOM_TABS_ENABLE_SVG controls it | |
| // when SwiftPM resolves the package: | |
| // unset -> enabled, with a deprecation notice in dev builds | |
| // 1 / true / yes -> enabled | |
| // 0 / false / no -> disabled, no private CoreSVG code is compiled | |
Details
persona: maintainability
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging like
There was a problem hiding this comment.
Fixed
|
|
||
| @implementation SvgDecoder | ||
|
|
||
| RCT_EXPORT_MODULE() |
There was a problem hiding this comment.
🔵 Nit · @synthesize callableJSModules and RCTCallableJSModules rely on headers SvgDecoder.mm never imports
SvgDecoder.mm adds @synthesize callableJSModules = _callableJSModules; (line 24, compiled unconditionally, not inside #if RCT_DEV) and names the RCTCallableJSModules type (line 31), but the file imports only SvgDecoder.h and <React/RCTLog.h>, and neither of the two protocols SvgDecoder declares (SvgDecoder.h:6, RCTImageDataDecoder, NativeSVGDecoderSpec) is the place that property is declared in React Native — it comes from the image-loader side. So the declaration of both the property and the class must arrive transitively through whatever RCTLog.h/RCTImageDataDecoder.h happen to pull in today; @synthesize for a property that is not declared is a hard compile error, and an RN header reshuffle (RN has moved RCTCallableJSModules and the image-loader protocols more than once) breaks both Debug and Release builds of every consumer. I could not check the RN headers in this offline checkout, hence the lowered confidence; the same applies to RCT_DEV, which is only correct if RCTDefines.h really is imported by RCTLog.h on the supported RN versions. The disabled/RCT_DEV code paths are also the ones no CI job compiles as Release-with-dev-warnings, so a regression here surfaces only for a subset of consumers.
| RCT_EXPORT_MODULE() | |
| #import "SvgDecoder.h" | |
| #import <React/RCTLog.h> | |
| #import <React/RCTCallableJSModules.h> | |
| #import <React/RCTImageLoaderProtocol.h> |
Suggested change
Import the headers you use directly (#import <React/RCTCallableJSModules.h>, and the image-loader header that declares the callableJSModules property) rather than relying on transitive imports, and move @synthesize inside the same #if RCT_DEV guard as its only use so a release build does not depend on the property existing.
Details
persona: swift-ios
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging pivot RCTImageDataDecoder.h imports RCTBridge.h, and the protocol is declared as RCTImageDataDecoder . RCTBridgeModule.h declares the callableJSModules property in all builds and tells modules to add @synthesize callableJSModules. SvgDecoder.h imports RCTImageDataDecoder.h, so the declaration is a direct part of the protocol that SvgDecoder adopts
|
|
||
| @implementation SvgDecoder | ||
|
|
||
| RCT_EXPORT_MODULE() |
There was a problem hiding this comment.
🔵 Nit · @synthesize callableJSModules sits outside the #if RCT_DEV guard that covers its only reader
@synthesize callableJSModules = _callableJSModules; at SvgDecoder.mm:24 is emitted unconditionally, while the whole RCTImageDataDecoder protocol it satisfies and the logDevWarning: reader at line 31 are gated behind #if RCT_DEV (the RCTImageDataDecoder protocol declares @property (nonatomic, weak) RCTCallableJSModules *callableJSModules;). If that declaration turns out to be dev-only in a given React version (as the surrounding #if RCT_DEV blocks around the call sites assume), the synthesized accessor for an undeclared property is a hard error in the SVG-disabled Release build — exactly the configuration this PR adds a CI job for, and the reason @synthesize normally sits inside the same #if RCT_DEV guard as its only user. Either way it is inconsistent: the only consumer is dev-only, so the ivar/accessor are dead weight (and an unused-ivar/property warning surface) in every non-dev build.
| RCT_EXPORT_MODULE() | |
| #if RCT_DEV | |
| @synthesize callableJSModules = _callableJSModules; | |
| // RCTLogWarn alone does not show the message in React Native DevTools, so the |
Suggested change
Move @synthesize callableJSModules = _callableJSModules; inside the existing #if RCT_DEV block that contains logDevWarning: (verifying whether RCTImageDataDecoder declares the property unconditionally), so the synthesized accessor is compiled exactly when something reads it.
Details
persona: javascript
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging pivot The property comes from RCTBridgeModule and is declared in all builds, not only in dev builds. Because SvgDecoder adopts the protocol, it must synthesize the property in Release too. If it does not, the compiler warns about a missing property implementation.
|
|
||
| @synthesize callableJSModules = _callableJSModules; | ||
|
|
||
| #if RCT_DEV |
There was a problem hiding this comment.
🔵 Nit · logDevWarning silently drops the deprecation warning when callableJSModules is nil in a Release build
logDevWarning: is compiled only under #if RCT_DEV (line 26), but it reads self.callableJSModules, which RCTImageLoader only injects during its own (dev-only) initialization. In the CI job added by this PR the SwiftPM example is built with -configuration Release, where RCTImageLoader's #if RCT_DEV setup does not run, so callableJSModules stays nil and the else branch emits a plain RCTLogWarn — which is itself compiled out when RCT_DEV is 0. The result: the deprecation/disabled warning the PR describes as "logged to the JavaScript console" never reaches any consumer of a Release-with-dev-logging build; the same asymmetry applies to any app whose image decoding happens before the loader wires the decoder. At minimum the fallback path is dead code under the very configuration it is written for.
Details
persona: javascript
Reply @apex-sentinel-staging note ... to add context, or @apex-sentinel-staging pivot ... if this is wrong — I will re-check the cited code.
Useful? Reply @apex-sentinel-staging like, or @apex-sentinel-staging dislike <why> if it is not.
There was a problem hiding this comment.
@apex-sentinel-staging pivot logDevWarning: and all of its callers are compiled only when RCT_DEV is set. In a Release build there is no dev warning to lose, and the pod install warning covers that case. In dev builds, React Native sets callableJSModules on the module, and the DevTools test showed the warning.
Closes #565. It is a continuation of @thiagobrez's work from #566.
Summary
The private CoreSVG code on Apple platforms can now be removed from the build. SVG decoding stays enabled by default in this release. The next major version disables it by default.
$RNBottomTabsEnableSVG/ ExpoenableSVG/ SwiftPMRN_BOTTOM_TABS_ENABLE_SVGfalse/false/0true/true/1Changes on top of #566:
Package.swift.SvgDecoder.his removed fromios/include/module.modulemap.artifacts/issue-565/) are removed from the repository.TabViewProvider.swiftis split for SwiftLint. The SVG helpers moved toios/SVGIconLoader.swift.Results
Tested with Xcode 27.0 on an iPhone simulator with iOS 26.5.
0CoreSVGWrapperand base64 literals in the binary<Image>with an SVG sourceonLoadonErrorpod installwarningyarn test: passes, with 6 Ruby tests for the flag and 5 tests for the Expo Podfile helper.yarn lintandyarn typecheck: pass.Before Merging
Blast Radius: none by default
Apps that do not set the flag keep the current behavior and get a deprecation warning. Only apps that set the flag to
falselose SVG images, on purpose. Android is not changed.