Module: Everywhere::Config::DeepLinking

Included in:
Everywhere::Config
Defined in:
lib/everywhere/config/deep_linking.rb

Instance Method Summary collapse

Instance Method Details

#apple_app_site_associationObject

The apple-app-site-association document (a Hash), or nil when no Apple app ids are configured. applinks for universal links; webcredentials so associated-domains password autofill / Face ID credentials work too.



74
75
76
77
78
79
80
81
82
# File 'lib/everywhere/config/deep_linking.rb', line 74

def apple_app_site_association
  ids = deep_linking_apple_app_ids
  return nil if ids.empty?

  { "applinks" => {
      "details" => [{ "appIDs" => ids, "components" => deep_linking_paths.map { |p| { "/" => p } } }]
    },
    "webcredentials" => { "apps" => ids } }
end

#apple_app_site_association_jsonObject



84
85
86
87
88
# File 'lib/everywhere/config/deep_linking.rb', line 84

def apple_app_site_association_json
  require "json"
  doc = apple_app_site_association or return nil
  JSON.generate(doc)
end

The Digital Asset Links document (an Array), or nil without an Android app.



91
92
93
94
95
96
97
98
# File 'lib/everywhere/config/deep_linking.rb', line 91

def asset_links
  return nil unless deep_linking_android?

  [{ "relation" => ["delegate_permission/common.handle_all_urls"],
     "target" => { "namespace" => "android_app",
                   "package_name" => deep_linking_android_package,
                   "sha256_cert_fingerprints" => deep_linking_android_fingerprints } }]
end


100
101
102
103
104
# File 'lib/everywhere/config/deep_linking.rb', line 100

def asset_links_json
  require "json"
  doc = asset_links or return nil
  JSON.generate(doc)
end

#deep_linkingObject

Deep linking / universal links. Declares the app's association with its web domains so the OS can hand matching URLs to the app instead of the browser. The gem serves the two well-known association files this needs — /.well-known/apple-app-site-association and /.well-known/assetlinks.json — generated from this config (Everywhere::Engine in Rails; MobileConfigEndpoint for Sinatra/Hanami). The iOS builder stamps the matching Associated Domains entitlement, and the shell routes an incoming link to its path.

deep_linking:
team_id: ABCDE12345          # derives the iOS app id from bundle_id
# or set app ids explicitly:
# apple_app_id: ABCDE12345.com.example.app
# apple_app_ids: ["ABCDE12345.com.example.app"]
paths: ["/*"]                # which paths open the app (default: all)
domains: ["www.example.com"] # extra applinks: domains (remote host is implicit)
android:
  package: com.example.app
  sha256_cert_fingerprints: ["AB:CD:EF:..."]


24
# File 'lib/everywhere/config/deep_linking.rb', line 24

def deep_linking = @data.fetch("deep_linking", nil) || {}

#deep_linking?Boolean

Returns:

  • (Boolean)


54
# File 'lib/everywhere/config/deep_linking.rb', line 54

def deep_linking? = deep_linking_apple? || deep_linking_android?

#deep_linking_androidObject



43
# File 'lib/everywhere/config/deep_linking.rb', line 43

def deep_linking_android = deep_linking["android"].is_a?(Hash) ? deep_linking["android"] : {}

#deep_linking_android?Boolean

Returns:

  • (Boolean)


50
# File 'lib/everywhere/config/deep_linking.rb', line 50

def deep_linking_android? = !deep_linking_android_package.to_s.empty? && !deep_linking_android_fingerprints.empty?

#deep_linking_android_fingerprintsObject



46
47
48
# File 'lib/everywhere/config/deep_linking.rb', line 46

def deep_linking_android_fingerprints
  Array(deep_linking_android["sha256_cert_fingerprints"]).map { |f| f.to_s.strip }.reject(&:empty?)
end

#deep_linking_android_packageObject



44
# File 'lib/everywhere/config/deep_linking.rb', line 44

def deep_linking_android_package = deep_linking_android["package"]&.to_s

#deep_linking_apple?Boolean

Returns:

  • (Boolean)


52
# File 'lib/everywhere/config/deep_linking.rb', line 52

def deep_linking_apple? = !deep_linking_apple_app_ids.empty?

#deep_linking_apple_app_idsObject

The iOS/tvOS/... app identifiers (TeamID.bundleID) the association file advertises. Explicit ids win; otherwise team_id + the app's iOS bundle id.



28
29
30
31
32
33
34
# File 'lib/everywhere/config/deep_linking.rb', line 28

def deep_linking_apple_app_ids
  explicit = Array(deep_linking["apple_app_ids"]) + [deep_linking["apple_app_id"]].compact
  return explicit.map(&:to_s).uniq unless explicit.empty?

  team = deep_linking["team_id"].to_s.strip
  team.empty? ? [] : ["#{team}.#{bundle_id(target: "ios")}"]
end

#deep_linking_domainsObject

Domains for the iOS Associated Domains entitlement (applinks:) and the shell's universal-link host allowlist: the remote host plus any extra domains:. Bare hostnames (no scheme, no path).



59
60
61
62
63
64
65
66
67
68
69
# File 'lib/everywhere/config/deep_linking.rb', line 59

def deep_linking_domains
  hosts = []
  if remote_url
    require "uri"
    hosts << URI(remote_url).host
  end
  hosts += Array(deep_linking["domains"]).map { |d| d.to_s.sub(%r{\Ahttps?://}, "").sub(%r{/.*\z}, "") }
  hosts.compact.reject(&:empty?).uniq
rescue URI::InvalidURIError
  Array(deep_linking["domains"]).map(&:to_s).reject(&:empty?).uniq
end

#deep_linking_pathsObject

URL path patterns that open the app. Modern (iOS 14+) component form; defaults to every path.



38
39
40
41
# File 'lib/everywhere/config/deep_linking.rb', line 38

def deep_linking_paths
  paths = Array(deep_linking["paths"]).map(&:to_s).reject(&:empty?)
  paths.empty? ? ["*"] : paths
end