Module: Everywhere::Config::App
- Included in:
- Everywhere::Config
- Defined in:
- lib/everywhere/config/app.rb
Constant Summary collapse
- BUNDLE_ID =
A bundle id isn't only an identifier: it's a path segment (Paths.*_work_dir, which the builders rm_rf, and the update-signing key on disk). The derived default is safe by construction; an explicit one is whatever the app repo says, so it's held to reverse-DNS characters and nothing else.
/\A[A-Za-z0-9][A-Za-z0-9.-]*\z/
Instance Method Summary collapse
-
#android_target_sdk ⇒ Object
platforms.android.target_sdk— the escape hatch for shipping ahead of a Google Play deadline that lands before our next release does. -
#android_target_sdk_errors ⇒ Object
Raising it is the supported direction.
- #background_color ⇒ Object
-
#build ⇒ Object
The
build:section — durable build knobs that were onceevery buildflags (ruby, targets, capabilities). -
#build_capabilities ⇒ Object
Desktop OS-integration capabilities the app declares (
build.capabilities), as a plain list. -
#build_ruby ⇒ Object
Ruby version to package.
-
#build_target_specs ⇒ Object
The raw
build.targetsentries, suffixes intact ("ios-arm64:testflight"). -
#bundle_id(target: nil) ⇒ Object
Reverse-DNS identifier: macOS bundle id, and the name of the per-user app-data directory on every platform.
- #entry_path ⇒ Object
-
#icon ⇒ Object
App icon source: a PNG (ideally square, 1024px+).
- #identity_errors ⇒ Object
-
#mode ⇒ Object
"local" — the app is tebako-pressed and runs on-device (default) "remote" — thin shell around an already-deployed app: no press, no sidecar.
- #name(target: nil) ⇒ Object
- #remote? ⇒ Boolean
-
#remote_instances? ⇒ Boolean
Multi-instance apps (
remote.instances: true): the mobile shell boots into remote.url — a hosted instance-picker page — and lets that page re-root the app onto a chosen instance via Everywhere.instance.set, persisted across launches until Everywhere.instance.clear. -
#remote_instances_escape? ⇒ Boolean
Whether the shell offers its built-in escape hatch while re-rooted on an instance: a "back to start" toolbar action on screens where the tab bar (and the injected leave tab it carries) is hidden — every modal-context screen, and an instance serving no tabs at all.
- #remote_url ⇒ Object
-
#splash ⇒ Object
Optional custom splash page (HTML file, path relative to the app root).
-
#targets ⇒ Object
Build targets as BARE os-arch strings — any ":
" suffix is stripped. - #tint_color ⇒ Object
-
#version(target: nil) ⇒ Object
Marketing/display version of the app (CFBundleShortVersionString, and the
versionrecorded in the build receipt).
Instance Method Details
#android_target_sdk ⇒ Object
platforms.android.target_sdk — the escape hatch for shipping ahead of
a Google Play deadline that lands before our next release does. It is
the ONLY SDK level an app may set, and deliberately not a general knob:
targetSdk is a contract with the OS, not an app preference, and every
behaviour change it opts into lands on the Kotlin in the frozen shell,
which is only tested at AndroidSdk::TARGET_SDK. Setting it means "I
accept untested OS behaviour".
compileSdk stays unexposed on purpose: from API 37 on it needs a matching compileSdkMinor and an AGP that knows the level, so moving it is a template change, never a config one.
nil when unset — the builder substitutes AndroidSdk::TARGET_SDK, so the default lives in one place rather than being duplicated here.
52 53 54 55 |
# File 'lib/everywhere/config/app.rb', line 52 def android_target_sdk raw = android_platform["target_sdk"] Integer(raw.to_s, exception: false) unless raw.nil? end |
#android_target_sdk_errors ⇒ Object
Raising it is the supported direction. Lowering is refused: the shipped Kotlin assumes the behaviour of the level it was built for, and a target under Play's floor is rejected at upload — the exact failure AndroidSdk::PLAY_TARGET_SDK_FLOOR exists to catch. Nothing caps the top end, because targeting a level above compileSdk is the whole point (and AGP allows it: the manifest claims the level, the code compiled against ours).
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/everywhere/config/app.rb', line 64 def android_target_sdk_errors raw = android_platform["target_sdk"] return [] if raw.nil? value = android_target_sdk tested = AndroidSdk::TARGET_SDK if value.nil? ["platforms.android.target_sdk #{raw.inspect} is not an API level — " \ "a whole number like #{tested}"] elsif value < tested ["platforms.android.target_sdk #{value} is below the shell's tested level " \ "(#{tested}) — this option only raises it, to ship ahead of a Play deadline"] else [] end end |
#background_color ⇒ Object
177 178 179 |
# File 'lib/everywhere/config/app.rb', line 177 def background_color normalize_color(appearance["background_color"]) end |
#build ⇒ Object
The build: section — durable build knobs that were once every build
flags (ruby, targets, capabilities). CLI flags still override per-run.
See platform/docs/build-engine.md §2.
117 |
# File 'lib/everywhere/config/app.rb', line 117 def build = @data.fetch("build", nil) || {} |
#build_capabilities ⇒ Object
Desktop OS-integration capabilities the app declares (build.capabilities),
as a plain list. Deliberately not called permissions: the top-level
permissions: below is the mobile prompt declaration — a different shape
for a different consumer — and while both were spelled "permissions" this
accessor was silently redefined by that one and could never be read.
127 |
# File 'lib/everywhere/config/app.rb', line 127 def build_capabilities = Array(build["capabilities"]) |
#build_ruby ⇒ Object
Ruby version to package. nil here means "let the CLI decide its default".
120 |
# File 'lib/everywhere/config/app.rb', line 120 def build_ruby = build["ruby"] |
#build_target_specs ⇒ Object
The raw build.targets entries, suffixes intact ("ios-arm64:testflight").
137 |
# File 'lib/everywhere/config/app.rb', line 137 def build_target_specs = Array(build["targets"]) |
#bundle_id(target: nil) ⇒ Object
Reverse-DNS identifier: macOS bundle id, and the name of the per-user
app-data directory on every platform. Set it explicitly and never change
it — renaming moves users' data. A platform may override it (e.g. the App
Store often wants com.example.app.ios).
14 15 16 17 |
# File 'lib/everywhere/config/app.rb', line 14 def bundle_id(target: nil) resolved(target)["bundle_id"] || "com.rubyeverywhere.#{name(target: target).downcase.gsub(/[^a-z0-9]+/, "-").gsub(/\A-|-\z/, "")}" end |
#entry_path ⇒ Object
101 102 103 104 |
# File 'lib/everywhere/config/app.rb', line 101 def entry_path path = app["entry_path"] || "/" path.start_with?("/") ? path : "/#{path}" end |
#icon ⇒ Object
App icon source: a PNG (ideally square, 1024px+). Explicit app.icon
path relative to the app root, or icon.png at the root by convention.
84 85 86 87 88 89 90 91 |
# File 'lib/everywhere/config/app.rb', line 84 def icon if (explicit = app["icon"]) File.(explicit, root) else default = File.join(root, "icon.png") File.exist?(default) ? default : nil end end |
#identity_errors ⇒ Object
25 26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/everywhere/config/app.rb', line 25 def identity_errors sections = [["app", app]] + platforms.map { |os, override| ["platforms.#{os}", override] } sections.filter_map do |at, section| next unless section.is_a?(Hash) value = section["bundle_id"].to_s next if value.empty? || (value.match?(BUNDLE_ID) && !value.include?("..")) "#{at}.bundle_id #{value.inspect} is not a bundle id — reverse-DNS, " \ "letters/digits/./- only (like com.example.app)" end + android_target_sdk_errors end |
#mode ⇒ Object
"local" — the app is tebako-pressed and runs on-device (default) "remote" — thin shell around an already-deployed app: no press, no sidecar
141 142 143 |
# File 'lib/everywhere/config/app.rb', line 141 def mode app["mode"] || (remote_url ? "remote" : "local") end |
#name(target: nil) ⇒ Object
6 7 8 |
# File 'lib/everywhere/config/app.rb', line 6 def name(target: nil) resolved(target)["name"] || File.basename(File.(root)).split(/[-_]/).map(&:capitalize).join(" ") end |
#remote? ⇒ Boolean
145 |
# File 'lib/everywhere/config/app.rb', line 145 def remote? = mode == "remote" |
#remote_instances? ⇒ Boolean
Multi-instance apps (remote.instances: true): the mobile shell boots
into remote.url — a hosted instance-picker page — and lets that page
re-root the app onto a chosen instance via Everywhere.instance.set,
persisted across launches until Everywhere.instance.clear. Opt-in
because it lets page JS repoint the whole app: apps that aren't
multi-instance shouldn't carry that surface.
157 158 159 |
# File 'lib/everywhere/config/app.rb', line 157 def remote_instances? @data.dig("remote", "instances") == true end |
#remote_instances_escape? ⇒ Boolean
Whether the shell offers its built-in escape hatch while re-rooted on
an instance: a "back to start" toolbar action on screens where the tab
bar (and the injected leave tab it carries) is hidden — every
modal-context screen, and an instance serving no tabs at all. On by
default because stranding is inherent to the picker pattern (a
previewed app's whole signed-out surface can be modal); an instance
app that wants no shell chrome opts out with
remote: { instances_escape: false }.
169 170 171 |
# File 'lib/everywhere/config/app.rb', line 169 def remote_instances_escape? remote_instances? && @data.dig("remote", "instances_escape") != false end |
#remote_url ⇒ Object
147 148 149 |
# File 'lib/everywhere/config/app.rb', line 147 def remote_url @data.dig("remote", "url")&.chomp("/") end |
#splash ⇒ Object
Optional custom splash page (HTML file, path relative to the app root). Shown while the packaged server boots; the shell injects window.EVERYWHERE_CONFIG so it can use the app's name and colors.
96 97 98 99 |
# File 'lib/everywhere/config/app.rb', line 96 def splash path = app["splash"] File.(path, root) if path end |
#targets ⇒ Object
Build targets as BARE os-arch strings — any ":every publish derives S3 update-manifest key paths from the first one),
so a suffix leaking through here would poison those paths. Use
#build_target_specs when the channel matters.
134 |
# File 'lib/everywhere/config/app.rb', line 134 def targets = build_target_specs.map { |t| t.to_s.split(":", 2).first } |
#tint_color ⇒ Object
173 174 175 |
# File 'lib/everywhere/config/app.rb', line 173 def tint_color normalize_color(appearance["tint_color"]) end |
#version(target: nil) ⇒ Object
Marketing/display version of the app (CFBundleShortVersionString, and the
version recorded in the build receipt). One shared app.version is the
default for every target; a platform may override it when a store forces a
different number. Defaults conservatively.
110 111 112 |
# File 'lib/everywhere/config/app.rb', line 110 def version(target: nil) resolved(target)["version"] || "0.1.0" end |