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) and `generic` (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.11"
Class Method Summary collapse
-
.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.
-
.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.
-
.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_paths` must 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.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/ruby_native.rb', line 85 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`.
70 71 72 73 74 75 76 77 78 79 |
# File 'lib/ruby_native.rb', line 70 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.
113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/ruby_native.rb', line 113 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
25 26 27 |
# File 'lib/ruby_native.rb', line 25 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.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/ruby_native.rb', line 129 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.
154 155 156 157 158 159 |
# File 'lib/ruby_native.rb', line 154 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
33 34 35 |
# File 'lib/ruby_native.rb', line 33 def self.fire_subscription_callbacks(event) subscription_callbacks.each { |cb| cb.call(event) } end |
.load_config ⇒ Object
37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/ruby_native.rb', line 37 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.
169 170 171 172 173 174 175 176 177 178 179 |
# File 'lib/ruby_native.rb', line 169 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
29 30 31 |
# File 'lib/ruby_native.rb', line 29 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.
62 63 64 65 |
# File 'lib/ruby_native.rb', line 62 def self.render_config(path) helpers = ActionController::Base.helpers ERB.new(path.read, trim_mode: "-").result(helpers.instance_eval { binding }) end |