Skip to content

1.4.0

Latest

Choose a tag to compare

@mbarta mbarta released this 03 Nov 16:23
1ec18fd

What's Changed

  • Add a configurable origin trust policy by @mbarta in #215
  • Don't leak the previous Activity and its WebViews when it is destroyed by @jonashan in #221
  • Recover when the WebView render process is gone by @jonashan in #222
  • Scope WebView cookies to the request host by @mbarta in #211
  • Stop the redirect check before the cross-origin destination by @jeremy in #213
  • Add web authentication (passkey) support by @leonvogt in #218
  • Hide native title when HTML <title> is not present or blank by @leonvogt in #204

New Features

Origin verification

Hotwire Native now checks the origin of every page before it lets the page navigate in-app or reach native code. Only origins your app trusts can:

  • open in the app instead of a browser tab
  • receive the library's JavaScript and send Turbo and bridge component messages
  • open the file chooser
  • get geolocation, camera and microphone permissions

The default DefaultOriginTrustPolicy trusts the origins of your NavigatorHost start locations. If your app loads a single origin, you don't need to change anything.

To trust more origins, set your own policy. You can build on the default:

private val accounts = Origin.parse("https://accounts.example.com")

Hotwire.config.originTrustPolicy = object : OriginTrustPolicy() {
    override fun isTrustedForNavigation(origin: Origin) =
        origin == accounts || DefaultOriginTrustPolicy.isTrustedForNavigation(origin)

    override fun isTrustedForNativeAccess(origin: Origin) =
        origin == accounts || DefaultOriginTrustPolicy.isTrustedForNativeAccess(origin)
}

An origin is the full scheme, host and port, so http://example.com and https://example.com:8443 are different origins from https://example.com. See #215.

Passkeys

Set Hotwire.config.webAuthenticationEnabled = true in Application.onCreate() to allow WebAuthn (passkey) requests from your WebViews. Your app needs Digital Asset Links set up with your site, and your server has to accept the app's android:apk-key-hash origin. Only turn this on if your WebViews load nothing but your own sites. See #218.

Fixes

  • When the WebView render process is gone, every NavigatorHost now replaces its session and reloads its current page instead of staying blank. See #222.
  • Apps with registered bridge components no longer keep every destroyed Activity and its WebViews in memory after a recreation (dark mode, locale changes) or after signing out. See #221.
  • The library's own HTTP requests now send each host only its own WebView cookies, including on redirects. See #211.
  • When a visit fails on a cross-origin redirect, the library now follows same-origin redirects first, so a chain like /account → /login → your identity provider opens the identity provider. See #213.
  • Pages without a <title> now show an empty title instead of the page URL, matching iOS. See #204.
  • data-native-prevent-pull-to-refresh and scrollable elements now block pull-to-refresh. See #222.

Breaking Changes ⚠️

  • If your app doesn't use NavigatorHost, the default policy trusts nothing, and every page fails to load with LoadError.UntrustedOrigin. Set Hotwire.config.originTrustPolicy. See #215.
  • If your app loads more than one origin in-app, links to the other origins now open in a browser tab, and pages from them fail to load with LoadError.UntrustedOrigin. Set a policy that trusts them. See #215.
  • LoadError has 2 new cases, UntrustedOrigin and WebViewNotSupported. Add branches for them to any exhaustive when over LoadError. See #215.
  • VisitError.description() is now a description property. Switch to the property, or Kotlin callers can import the deprecated dev.hotwire.core.turbo.errors.description extension. See #215.

New Contributors

Full Changelog: 1.3.2...1.4.0