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/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, 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.10.14"
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_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.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/ruby_native.rb', line 91 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.
76 77 78 79 80 81 82 83 84 85 |
# File 'lib/ruby_native.rb', line 76 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.
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/ruby_native.rb', line 119 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.
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/ruby_native.rb', line 135 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.
160 161 162 163 164 165 |
# File 'lib/ruby_native.rb', line 160 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 |
# File 'lib/ruby_native.rb', line 43 def self.load_config path = Rails.root.join("config", "ruby_native.yml") return unless path.exist? self.config = YAML.load(render_config(path)).deep_symbolize_keys self.config[:app] ||= {} self.config[:app][:entry_path] ||= self.config.dig(:tabs, 0, :path) || "/" self.config[:auth] ||= {} normalize_oauth_paths backfill_tab_icons backfill_error_icons 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.
175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/ruby_native.rb', line 175 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.
68 69 70 71 |
# File 'lib/ruby_native.rb', line 68 def self.render_config(path) helpers = ActionController::Base.helpers ERB.new(path.read, trim_mode: "-").result(helpers.instance_eval { binding }) end |