Module: RubyNative
- Defined in:
- lib/ruby_native.rb,
lib/ruby_native/cli.rb,
lib/ruby_native/engine.rb,
lib/ruby_native/helper.rb,
lib/ruby_native/version.rb,
lib/ruby_native/cli/login.rb,
lib/ruby_native/iap/event.rb,
lib/ruby_native/cli/deploy.rb,
lib/ruby_native/cli/preview.rb,
lib/ruby_native/iap/decodable.rb,
lib/ruby_native/iap/verifiable.rb,
lib/ruby_native/native_version.rb,
lib/ruby_native/cli/credentials.rb,
lib/ruby_native/inertia_support.rb,
lib/ruby_native/iap/normalizable.rb,
lib/ruby_native/native_detection.rb,
lib/ruby_native/oauth_middleware.rb,
lib/generators/ruby_native/iap_generator.rb,
lib/ruby_native/tunnel_cookie_middleware.rb,
app/models/ruby_native/iap/purchase_intent.rb,
lib/ruby_native/screenshots/sign_in_helper.rb,
app/controllers/ruby_native/aasa_controller.rb,
lib/ruby_native/iap/apple_webhook_processor.rb,
lib/generators/ruby_native/install_generator.rb,
app/controllers/ruby_native/config_controller.rb,
app/controllers/ruby_native/assetlinks_controller.rb,
app/controllers/ruby_native/auth/start_controller.rb,
app/controllers/ruby_native/iap/restores_controller.rb,
app/controllers/ruby_native/push/devices_controller.rb,
app/controllers/ruby_native/auth/sessions_controller.rb,
app/controllers/ruby_native/iap/purchases_controller.rb,
app/controllers/ruby_native/webhooks/apple_controller.rb,
app/controllers/ruby_native/iap/completions_controller.rb,
app/controllers/ruby_native/screenshots/sessions_controller.rb
Defined Under Namespace
Modules: Auth, Generators, Helper, IAP, InertiaSupport, NativeDetection, Push, Screenshots, Webhooks Classes: AasaController, AssetlinksController, CLI, ConfigController, Engine, NativeVersion, OAuthMiddleware, TunnelCookieMiddleware
Constant Summary collapse
- ERROR_SCREEN_STATES =
The native fallback screen has two states:
offline(no connectivity) andgeneric(any other load failure). Each can carry a per-platform icon and localized copy. %i[offline generic].freeze
- ERROR_SCREEN_COPY_KEYS =
%i[title message].freeze
- VERSION =
"0.14.0"
Class Method Summary collapse
-
.backfill_error_icons ⇒ Object
Mirrors
backfill_tab_iconsfor the error screen: fills a state's flaticonfrom its per-platformicons(ios first, then android), so the iOS app, which reads only the flaticon, still renders one. -
.backfill_tab_icons ⇒ Object
Mirrors per-platform
icons:into the legacy flaticon:field so native binaries that only readtab.iconkeep rendering an icon. -
.config_as_json ⇒ Object
The JSON served at GET /native/config.
- .configure {|_self| ... } ⇒ Object
-
.error_screen_config(yaml_errors) ⇒ Object
Merges per-state error-screen icons (from YAML) with localized copy (from I18n) into the shape the native apps decode.
-
.error_screen_translations(subkey) ⇒ Object
Reads
ruby_native.errors.<subkey>for every available locale, keeping only the locales the developer actually translated. - .fire_subscription_callbacks(event) ⇒ Object
- .load_config ⇒ Object
-
.normalize_linked_paths ⇒ Object
Entries are path prefixes: "/pair/" links every URL under it.
-
.normalize_oauth_paths ⇒ Object
auth.oauth_pathsmust list only OAuth authorize paths, never their callbacks. - .on_subscription_change(&block) ⇒ Object
-
.render_config(path) ⇒ Object
config/ruby_native.yml is rendered as ERB before it is parsed, so a developer can interpolate Rails helpers into it.
Class Method Details
.backfill_error_icons ⇒ Object
Mirrors backfill_tab_icons for the error screen: fills a state's flat
icon from its per-platform icons (ios first, then android), so the iOS
app, which reads only the flat icon, still renders one. An explicit
icon: wins.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ruby_native.rb', line 101 def self.backfill_error_icons errors = self.config[:errors] return unless errors.is_a?(Hash) ERROR_SCREEN_STATES.each do |state| state_config = errors[state] next unless state_config.is_a?(Hash) icons = state_config[:icons] next unless icons.is_a?(Hash) state_config[:icon] ||= icons[:ios] || icons[:android] end end |
.backfill_tab_icons ⇒ Object
Mirrors per-platform icons: into the legacy flat icon: field so native
binaries that only read tab.icon keep rendering an icon. Explicit icon:
wins; otherwise falls back to icons.ios, then icons.android.
86 87 88 89 90 91 92 93 94 95 |
# File 'lib/ruby_native.rb', line 86 def self.backfill_tab_icons Array(self.config[:tabs]).each do |tab| next unless tab.is_a?(Hash) icons = tab[:icons] next unless icons.is_a?(Hash) tab[:icon] ||= icons[:ios] || icons[:android] end end |
.config_as_json ⇒ Object
The JSON served at GET /native/config. Identical to config, except the
errors block is enriched: per-state icons from config/ruby_native.yml are
merged with localized title/message pulled from the host app's I18n
(ruby_native.errors.<state>.<key>), one entry per available locale. Only
values the developer actually provided are emitted; the native apps fall
back to bundled English copy for anything missing. Built on a deep copy so
the in-memory config the server reads for view helpers is never mutated.
129 130 131 132 133 134 135 136 137 138 139 140 |
# File 'lib/ruby_native.rb', line 129 def self.config_as_json return config if config.nil? payload = config.deep_dup errors = error_screen_config(payload[:errors]) if errors.empty? payload.delete(:errors) else payload[:errors] = errors end payload end |
.configure {|_self| ... } ⇒ Object
31 32 33 |
# File 'lib/ruby_native.rb', line 31 def self.configure yield self end |
.error_screen_config(yaml_errors) ⇒ Object
Merges per-state error-screen icons (from YAML) with localized copy (from
I18n) into the shape the native apps decode. Omits any state with neither an
icon nor copy, so an untouched app sends no errors block at all.
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/ruby_native.rb', line 145 def self.error_screen_config(yaml_errors) config = ERROR_SCREEN_STATES.each_with_object({}) do |state, result| entry = {} state_config = yaml_errors[state] if yaml_errors.is_a?(Hash) if state_config.is_a?(Hash) entry[:icon] = state_config[:icon] if state_config[:icon] entry[:icons] = state_config[:icons] if state_config[:icons] end ERROR_SCREEN_COPY_KEYS.each do |key| translations = error_screen_translations("#{state}.#{key}") entry[key] = translations unless translations.empty? end result[state] = entry unless entry.empty? end # The Retry button label is shared by both states, so it sits at the top of # the block rather than under a state. retry_label = error_screen_translations("retry") config[:retry] = retry_label unless retry_label.empty? config end |
.error_screen_translations(subkey) ⇒ Object
Reads ruby_native.errors.<subkey> for every available locale, keeping only
the locales the developer actually translated. Copy lives in the host app's
own locale files; the gem ships none.
170 171 172 173 174 175 |
# File 'lib/ruby_native.rb', line 170 def self.error_screen_translations(subkey) I18n.available_locales.each_with_object({}) do |locale, result| value = I18n.t("ruby_native.errors.#{subkey}", locale: locale, default: nil) result[locale] = value unless value.nil? end end |
.fire_subscription_callbacks(event) ⇒ Object
39 40 41 |
# File 'lib/ruby_native.rb', line 39 def self.fire_subscription_callbacks(event) subscription_callbacks.each { |cb| cb.call(event) } end |
.load_config ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/ruby_native.rb', line 43 def self.load_config path = Rails.root.join("config", "ruby_native.yml") return unless path.exist? parsed = YAML.load(render_config(path), filename: path.to_s, aliases: true) # An empty file, comments only, or ERB rendering to nothing parses to nil; # treat it like a missing file instead of crashing Rails boot. unless parsed.is_a?(Hash) Rails.logger.warn("[RubyNative] #{path} is empty or not a YAML mapping; ignoring it.") return end self.config = parsed.deep_symbolize_keys self.config[:app] ||= {} self.config[:app][:entry_path] ||= self.config.dig(:tabs, 0, :path) || "/" self.config[:auth] ||= {} normalize_oauth_paths normalize_linked_paths backfill_tab_icons backfill_error_icons end |
.normalize_linked_paths ⇒ Object
Entries are path prefixes: "/pair/" links every URL under it. A leading slash is added when missing, and a trailing "*" (an easy slip, since the AASA file uses one) is stripped so both platforms receive a plain prefix. Left absent when unconfigured so config.json doesn't grow an empty key.
201 202 203 204 205 206 207 208 |
# File 'lib/ruby_native.rb', line 201 def self.normalize_linked_paths return unless self.config.key?(:linked_paths) self.config[:linked_paths] = Array(self.config[:linked_paths]) .map { |path| path.to_s.strip.sub(/\*+\z/, "") } .reject(&:empty?) .map { |path| path.start_with?("/") ? path : "/#{path}" } end |
.normalize_oauth_paths ⇒ Object
auth.oauth_paths must list only OAuth authorize paths, never their
callbacks. The native app treats every listed path as a sign-in trigger and
derives the provider from the last path segment, so a callback entry like
"/auth/google/callback" would launch a bogus flow for a provider named
"callback" and send sign-in into a loop. The callback round-trip is handled
automatically by OAuthMiddleware's tracking cookie, so it never needs
listing. Drop any entry that is the "/callback" child of another listed
path and warn, so a copied-in callback can't break native sign-in.
185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/ruby_native.rb', line 185 def self.normalize_oauth_paths paths = Array(self.config.dig(:auth, :oauth_paths)) callbacks = paths.select { |path| paths.any? { |start| path == "#{start}/callback" } } return if callbacks.empty? Rails.logger.warn( "[RubyNative] Ignoring OAuth callback path(s) in config/ruby_native.yml " \ "(#{callbacks.join(", ")}). List only the authorize path; callbacks are handled automatically." ) self.config[:auth][:oauth_paths] = paths - callbacks end |
.on_subscription_change(&block) ⇒ Object
35 36 37 |
# File 'lib/ruby_native.rb', line 35 def self.on_subscription_change(&block) subscription_callbacks << block end |
.render_config(path) ⇒ Object
config/ruby_native.yml is rendered as ERB before it is parsed, so a
developer can interpolate Rails helpers into it. The motivating case is the
navbar logo: logo: '<%= image_url("logo.png") %>' resolves to a
fingerprinted asset URL the native app downloads and caches, and because the
digest changes whenever the asset changes, the cache busts itself. A full
URL (a CDN, say) works just as well; the app only ever sees a URL to fetch.
The template renders against the controller helper proxy, so image_url and
friends behave exactly as they do in a view. With no request or asset host
they degrade to a relative path -- asset helpers never raise "missing host"
the way routing helpers do -- and the native app resolves any relative URL
against the base URL it already fetched the config from.
78 79 80 81 |
# File 'lib/ruby_native.rb', line 78 def self.render_config(path) helpers = ActionController::Base.helpers ERB.new(path.read, trim_mode: "-").result(helpers.instance_eval { binding }) end |