Module: Everywhere::AndroidResources
- Defined in:
- lib/everywhere/android_resources.rb
Overview
Compiles an app's native/android/assets/ tree into Android drawable resources so native code can reach them by name — R.drawable.logo in Kotlin, @drawable/logo in a layout.
Deliberately the same filename API as the iOS side (see AssetCatalog), so one
assets/ tree can be authored once and dropped into both native/ios/ and
native/android/:
logo.png → res/drawable/logo.png (density-independent baseline)
logo@2x.png → res/drawable-xhdpi/logo.png (2x = 320dpi)
logo@3x.png → res/drawable-xxhdpi/logo.png (3x = 480dpi)
logo~dark.png → res/drawable-night/logo.png
logo@2x~dark.png→ res/drawable-night-xhdpi/logo.png
Sub-directories organise the source tree but do NOT namespace the result — res/ is flat, and asset names are global on iOS too, so assets/branding/ logo.png is R.drawable.logo either way.
Constant Summary collapse
- RASTER =
Raster formats aapt2 accepts as-is. WebP is included (and PDF/SVG are not) because that is the split Android itself draws — the reverse of iOS.
%w[.png .jpg .jpeg .webp].freeze
- VECTOR =
A drawable written as XML: vectors, shapes, layer lists, selectors. Scale -free, so the density qualifiers above don't apply to them.
%w[.xml].freeze
- EXTENSIONS =
(RASTER + VECTOR).freeze
- DENSITIES =
iOS's @2x/@3x in Android's density buckets. 1x is plain
drawable, notdrawable-mdpi: both mean 160dpi, but the unqualified directory is also the fallback every density falls back TO, which is what a single-file asset needs to be. { nil => nil, "2x" => "xhdpi", "3x" => "xxhdpi" }.freeze
- RESERVED =
Written by the Android builder itself (adaptive launcher icon layers) or shipped in the frozen template's own res/. Both would collide in the merged resource table, so they're refused by name here — a merge conflict from aapt2 arrives minutes into a Gradle run and names no fix.
%w[ ic_launcher ic_launcher_round ic_launcher_foreground ic_launcher_background ic_tab_placeholder ].freeze
- VALID_NAME =
An Android resource entry is a field on the generated R class, so the name has to be a Java identifier — and aapt2 additionally rejects uppercase in a res/ filename. Hyphens and dots are legal on iOS and never here.
/\A[a-z][a-z0-9_]*\z/- JAVA_KEYWORDS =
Reserved words can't name a field on R.
val/funare fine (Kotlin reads R from Java), so this is the Java list, not the Kotlin one. %w[ abstract assert boolean break byte case catch char class const continue default do double else enum extends final finally float for goto if implements import instanceof int interface long native new package private protected public return short static strictfp super switch synchronized this throw throws transient try void volatile while ].freeze
Class Method Summary collapse
-
.write!(source, res) ⇒ Object
Copy every image under
sourceintoresas a drawable resource.
Class Method Details
.write!(source, res) ⇒ Object
Copy every image under source into res as a drawable resource.
Returns [names, errors]; nothing is written when errors is non-empty, so
a broken assets/ tree can't half-stamp the resource dirs.
68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/everywhere/android_resources.rb', line 68 def write!(source, res) variants, errors = plan(source) return [[], errors] unless errors.empty? variants.each do |variant| dir = File.join(res, variant[:dir]) FileUtils.mkdir_p(dir) FileUtils.cp(variant[:path], File.join(dir, "#{variant[:name]}#{variant[:extension]}")) end [variants.map { |variant| variant[:name] }.uniq.sort, []] end |