xref: /aosp_15_r20/external/accompanist/web/src/main/java/com/google/accompanist/web/WebView.kt (revision fa44fe6ae8e729aa3cfe5c03eedbbf98fb44e2c6)
1  /*
<lambda>null2   * Copyright 2021 The Android Open Source Project
3   *
4   * Licensed under the Apache License, Version 2.0 (the "License");
5   * you may not use this file except in compliance with the License.
6   * You may obtain a copy of the License at
7   *
8   *      https://www.apache.org/licenses/LICENSE-2.0
9   *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  @file:Suppress("DEPRECATION")
18  
19  package com.google.accompanist.web
20  
21  import android.content.Context
22  import android.graphics.Bitmap
23  import android.os.Bundle
24  import android.view.ViewGroup.LayoutParams
25  import android.webkit.WebChromeClient
26  import android.webkit.WebResourceError
27  import android.webkit.WebResourceRequest
28  import android.webkit.WebView
29  import android.webkit.WebViewClient
30  import android.widget.FrameLayout
31  import androidx.activity.compose.BackHandler
32  import androidx.compose.foundation.layout.BoxWithConstraints
33  import androidx.compose.runtime.Composable
34  import androidx.compose.runtime.Immutable
35  import androidx.compose.runtime.LaunchedEffect
36  import androidx.compose.runtime.Stable
37  import androidx.compose.runtime.getValue
38  import androidx.compose.runtime.mutableStateListOf
39  import androidx.compose.runtime.mutableStateOf
40  import androidx.compose.runtime.remember
41  import androidx.compose.runtime.rememberCoroutineScope
42  import androidx.compose.runtime.saveable.Saver
43  import androidx.compose.runtime.saveable.mapSaver
44  import androidx.compose.runtime.saveable.rememberSaveable
45  import androidx.compose.runtime.setValue
46  import androidx.compose.runtime.snapshotFlow
47  import androidx.compose.runtime.snapshots.SnapshotStateList
48  import androidx.compose.ui.Modifier
49  import androidx.compose.ui.viewinterop.AndroidView
50  import com.google.accompanist.web.LoadingState.Finished
51  import com.google.accompanist.web.LoadingState.Loading
52  import kotlinx.coroutines.CoroutineScope
53  import kotlinx.coroutines.Dispatchers
54  import kotlinx.coroutines.flow.MutableSharedFlow
55  import kotlinx.coroutines.launch
56  import kotlinx.coroutines.withContext
57  
58  /**
59   * A wrapper around the Android View WebView to provide a basic WebView composable.
60   *
61   * If you require more customisation you are most likely better rolling your own and using this
62   * wrapper as an example.
63   *
64   * The WebView attempts to set the layoutParams based on the Compose modifier passed in. If it
65   * is incorrectly sizing, use the layoutParams composable function instead.
66   *
67   * @param state The webview state holder where the Uri to load is defined.
68   * @param modifier A compose modifier
69   * @param captureBackPresses Set to true to have this Composable capture back presses and navigate
70   * the WebView back.
71   * @param navigator An optional navigator object that can be used to control the WebView's
72   * navigation from outside the composable.
73   * @param onCreated Called when the WebView is first created, this can be used to set additional
74   * settings on the WebView. WebChromeClient and WebViewClient should not be set here as they will be
75   * subsequently overwritten after this lambda is called.
76   * @param onDispose Called when the WebView is destroyed. Provides a bundle which can be saved
77   * if you need to save and restore state in this WebView.
78   * @param client Provides access to WebViewClient via subclassing
79   * @param chromeClient Provides access to WebChromeClient via subclassing
80   * @param factory An optional WebView factory for using a custom subclass of WebView
81   * @sample com.google.accompanist.sample.webview.BasicWebViewSample
82   */
83  @Deprecated(
84      """
85  accompanist/web is deprecated and the API is no longer maintained.
86  We recommend forking the implementation and customising it to your needs.
87  For more information please visit https://google.github.io/accompanist/web
88  """
89  )
90  @Composable
91  public fun WebView(
92      state: WebViewState,
93      modifier: Modifier = Modifier,
94      captureBackPresses: Boolean = true,
95      navigator: WebViewNavigator = rememberWebViewNavigator(),
96      onCreated: (WebView) -> Unit = {},
<lambda>null97      onDispose: (WebView) -> Unit = {},
<lambda>null98      client: AccompanistWebViewClient = remember { AccompanistWebViewClient() },
<lambda>null99      chromeClient: AccompanistWebChromeClient = remember { AccompanistWebChromeClient() },
100      factory: ((Context) -> WebView)? = null,
101  ) {
<lambda>null102      BoxWithConstraints(modifier) {
103          // WebView changes it's layout strategy based on
104          // it's layoutParams. We convert from Compose Modifier to
105          // layout params here.
106          val width =
107              if (constraints.hasFixedWidth)
108                  LayoutParams.MATCH_PARENT
109              else
110                  LayoutParams.WRAP_CONTENT
111          val height =
112              if (constraints.hasFixedHeight)
113                  LayoutParams.MATCH_PARENT
114              else
115                  LayoutParams.WRAP_CONTENT
116  
117          val layoutParams = FrameLayout.LayoutParams(
118              width,
119              height
120          )
121  
122          WebView(
123              state,
124              layoutParams,
125              Modifier,
126              captureBackPresses,
127              navigator,
128              onCreated,
129              onDispose,
130              client,
131              chromeClient,
132              factory
133          )
134      }
135  }
136  
137  /**
138   * A wrapper around the Android View WebView to provide a basic WebView composable.
139   *
140   * If you require more customisation you are most likely better rolling your own and using this
141   * wrapper as an example.
142   *
143   * The WebView attempts to set the layoutParams based on the Compose modifier passed in. If it
144   * is incorrectly sizing, use the layoutParams composable function instead.
145   *
146   * @param state The webview state holder where the Uri to load is defined.
147   * @param layoutParams A FrameLayout.LayoutParams object to custom size the underlying WebView.
148   * @param modifier A compose modifier
149   * @param captureBackPresses Set to true to have this Composable capture back presses and navigate
150   * the WebView back.
151   * @param navigator An optional navigator object that can be used to control the WebView's
152   * navigation from outside the composable.
153   * @param onCreated Called when the WebView is first created, this can be used to set additional
154   * settings on the WebView. WebChromeClient and WebViewClient should not be set here as they will be
155   * subsequently overwritten after this lambda is called.
156   * @param onDispose Called when the WebView is destroyed. Provides a bundle which can be saved
157   * if you need to save and restore state in this WebView.
158   * @param client Provides access to WebViewClient via subclassing
159   * @param chromeClient Provides access to WebChromeClient via subclassing
160   * @param factory An optional WebView factory for using a custom subclass of WebView
161   */
162  @Deprecated(
163      """
164  accompanist/web is deprecated and the API is no longer maintained.
165  We recommend forking the implementation and customising it to your needs.
166  For more information please visit https://google.github.io/accompanist/web
167  """
168  )
169  @Composable
WebViewnull170  public fun WebView(
171      state: WebViewState,
172      layoutParams: FrameLayout.LayoutParams,
173      modifier: Modifier = Modifier,
174      captureBackPresses: Boolean = true,
175      navigator: WebViewNavigator = rememberWebViewNavigator(),
176      onCreated: (WebView) -> Unit = {},
<lambda>null177      onDispose: (WebView) -> Unit = {},
<lambda>null178      client: AccompanistWebViewClient = remember { AccompanistWebViewClient() },
<lambda>null179      chromeClient: AccompanistWebChromeClient = remember { AccompanistWebChromeClient() },
180      factory: ((Context) -> WebView)? = null,
181  ) {
182      val webView = state.webView
183  
<lambda>null184      BackHandler(captureBackPresses && navigator.canGoBack) {
185          webView?.goBack()
186      }
187  
wvnull188      webView?.let { wv ->
189          LaunchedEffect(wv, navigator) {
190              with(navigator) {
191                  wv.handleNavigationEvents()
192              }
193          }
194  
195          LaunchedEffect(wv, state) {
196              snapshotFlow { state.content }.collect { content ->
197                  when (content) {
198                      is WebContent.Url -> {
199                          wv.loadUrl(content.url, content.additionalHttpHeaders)
200                      }
201  
202                      is WebContent.Data -> {
203                          wv.loadDataWithBaseURL(
204                              content.baseUrl,
205                              content.data,
206                              content.mimeType,
207                              content.encoding,
208                              content.historyUrl
209                          )
210                      }
211  
212                      is WebContent.Post -> {
213                          wv.postUrl(
214                              content.url,
215                              content.postData
216                          )
217                      }
218  
219                      is WebContent.NavigatorOnly -> {
220                          // NO-OP
221                      }
222                  }
223              }
224          }
225      }
226  
227      // Set the state of the client and chrome client
228      // This is done internally to ensure they always are the same instance as the
229      // parent Web composable
230      client.state = state
231      client.navigator = navigator
232      chromeClient.state = state
233  
234      AndroidView(
contextnull235          factory = { context ->
236              (factory?.invoke(context) ?: WebView(context)).apply {
237                  onCreated(this)
238  
239                  this.layoutParams = layoutParams
240  
241                  state.viewState?.let {
242                      this.restoreState(it)
243                  }
244  
245                  webChromeClient = chromeClient
246                  webViewClient = client
247              }.also { state.webView = it }
248          },
249          modifier = modifier,
<lambda>null250          onRelease = {
251              onDispose(it)
252          }
253      )
254  }
255  
256  /**
257   * AccompanistWebViewClient
258   *
259   * A parent class implementation of WebViewClient that can be subclassed to add custom behaviour.
260   *
261   * As Accompanist Web needs to set its own web client to function, it provides this intermediary
262   * class that can be overriden if further custom behaviour is required.
263   */
264  @Deprecated(
265      """
266  accompanist/web is deprecated and the API is no longer maintained.
267  We recommend forking the implementation and customising it to your needs.
268  For more information please visit https://google.github.io/accompanist/web
269  """
270  )
271  public open class AccompanistWebViewClient : WebViewClient() {
272      public open lateinit var state: WebViewState
273          internal set
274      public open lateinit var navigator: WebViewNavigator
275          internal set
276  
onPageStartednull277      override fun onPageStarted(view: WebView, url: String?, favicon: Bitmap?) {
278          super.onPageStarted(view, url, favicon)
279          state.loadingState = Loading(0.0f)
280          state.errorsForCurrentRequest.clear()
281          state.pageTitle = null
282          state.pageIcon = null
283  
284          state.lastLoadedUrl = url
285      }
286  
onPageFinishednull287      override fun onPageFinished(view: WebView, url: String?) {
288          super.onPageFinished(view, url)
289          state.loadingState = Finished
290      }
291  
doUpdateVisitedHistorynull292      override fun doUpdateVisitedHistory(view: WebView, url: String?, isReload: Boolean) {
293          super.doUpdateVisitedHistory(view, url, isReload)
294  
295          navigator.canGoBack = view.canGoBack()
296          navigator.canGoForward = view.canGoForward()
297      }
298  
onReceivedErrornull299      override fun onReceivedError(
300          view: WebView,
301          request: WebResourceRequest?,
302          error: WebResourceError?
303      ) {
304          super.onReceivedError(view, request, error)
305  
306          if (error != null) {
307              state.errorsForCurrentRequest.add(WebViewError(request, error))
308          }
309      }
310  }
311  
312  /**
313   * AccompanistWebChromeClient
314   *
315   * A parent class implementation of WebChromeClient that can be subclassed to add custom behaviour.
316   *
317   * As Accompanist Web needs to set its own web client to function, it provides this intermediary
318   * class that can be overriden if further custom behaviour is required.
319   */
320  @Deprecated(
321      """
322  accompanist/web is deprecated and the API is no longer maintained.
323  We recommend forking the implementation and customising it to your needs.
324  For more information please visit https://google.github.io/accompanist/web
325  """
326  )
327  public open class AccompanistWebChromeClient : WebChromeClient() {
328      public open lateinit var state: WebViewState
329          internal set
330  
onReceivedTitlenull331      override fun onReceivedTitle(view: WebView, title: String?) {
332          super.onReceivedTitle(view, title)
333          state.pageTitle = title
334      }
335  
onReceivedIconnull336      override fun onReceivedIcon(view: WebView, icon: Bitmap?) {
337          super.onReceivedIcon(view, icon)
338          state.pageIcon = icon
339      }
340  
onProgressChangednull341      override fun onProgressChanged(view: WebView, newProgress: Int) {
342          super.onProgressChanged(view, newProgress)
343          if (state.loadingState is Finished) return
344          state.loadingState = Loading(newProgress / 100.0f)
345      }
346  }
347  
348  @Deprecated(
349      """
350  accompanist/web is deprecated and the API is no longer maintained.
351  We recommend forking the implementation and customising it to your needs.
352  For more information please visit https://google.github.io/accompanist/web
353  """
354  )
355  public sealed class WebContent {
356      public data class Url(
357          val url: String,
358          val additionalHttpHeaders: Map<String, String> = emptyMap(),
359      ) : WebContent()
360  
361      public data class Data(
362          val data: String,
363          val baseUrl: String? = null,
364          val encoding: String = "utf-8",
365          val mimeType: String? = null,
366          val historyUrl: String? = null
367      ) : WebContent()
368  
369      public data class Post(
370          val url: String,
371          val postData: ByteArray
372      ) : WebContent() {
equalsnull373          override fun equals(other: Any?): Boolean {
374              if (this === other) return true
375              if (javaClass != other?.javaClass) return false
376  
377              other as Post
378  
379              if (url != other.url) return false
380              if (!postData.contentEquals(other.postData)) return false
381  
382              return true
383          }
384  
hashCodenull385          override fun hashCode(): Int {
386              var result = url.hashCode()
387              result = 31 * result + postData.contentHashCode()
388              return result
389          }
390      }
391  
392      @Deprecated("Use state.lastLoadedUrl instead")
getCurrentUrlnull393      public fun getCurrentUrl(): String? {
394          return when (this) {
395              is Url -> url
396              is Data -> baseUrl
397              is Post -> url
398              is NavigatorOnly -> throw IllegalStateException("Unsupported")
399          }
400      }
401  
402      public object NavigatorOnly : WebContent()
403  }
404  
withUrlnull405  internal fun WebContent.withUrl(url: String) = when (this) {
406      is WebContent.Url -> copy(url = url)
407      else -> WebContent.Url(url)
408  }
409  
410  /**
411   * Sealed class for constraining possible loading states.
412   * See [Loading] and [Finished].
413   */
414  @Deprecated(
415      """
416  accompanist/web is deprecated and the API is no longer maintained.
417  We recommend forking the implementation and customising it to your needs.
418  For more information please visit https://google.github.io/accompanist/web
419  """
420  )
421  public sealed class LoadingState {
422      /**
423       * Describes a WebView that has not yet loaded for the first time.
424       */
425      public object Initializing : LoadingState()
426  
427      /**
428       * Describes a webview between `onPageStarted` and `onPageFinished` events, contains a
429       * [progress] property which is updated by the webview.
430       */
431      public data class Loading(val progress: Float) : LoadingState()
432  
433      /**
434       * Describes a webview that has finished loading content.
435       */
436      public object Finished : LoadingState()
437  }
438  
439  /**
440   * A state holder to hold the state for the WebView. In most cases this will be remembered
441   * using the rememberWebViewState(uri) function.
442   */
443  @Deprecated(
444      """
445  accompanist/web is deprecated and the API is no longer maintained.
446  We recommend forking the implementation and customising it to your needs.
447  For more information please visit https://google.github.io/accompanist/web
448  """
449  )
450  @Stable
451  public class WebViewState(webContent: WebContent) {
452      public var lastLoadedUrl: String? by mutableStateOf(null)
453          internal set
454  
455      /**
456       *  The content being loaded by the WebView
457       */
458      public var content: WebContent by mutableStateOf(webContent)
459  
460      /**
461       * Whether the WebView is currently [LoadingState.Loading] data in its main frame (along with
462       * progress) or the data loading has [LoadingState.Finished]. See [LoadingState]
463       */
464      public var loadingState: LoadingState by mutableStateOf(LoadingState.Initializing)
465          internal set
466  
467      /**
468       * Whether the webview is currently loading data in its main frame
469       */
470      public val isLoading: Boolean
471          get() = loadingState !is Finished
472  
473      /**
474       * The title received from the loaded content of the current page
475       */
476      public var pageTitle: String? by mutableStateOf(null)
477          internal set
478  
479      /**
480       * the favicon received from the loaded content of the current page
481       */
482      public var pageIcon: Bitmap? by mutableStateOf(null)
483          internal set
484  
485      /**
486       * A list for errors captured in the last load. Reset when a new page is loaded.
487       * Errors could be from any resource (iframe, image, etc.), not just for the main page.
488       * For more fine grained control use the OnError callback of the WebView.
489       */
490      public val errorsForCurrentRequest: SnapshotStateList<WebViewError> = mutableStateListOf()
491  
492      /**
493       * The saved view state from when the view was destroyed last. To restore state,
494       * use the navigator and only call loadUrl if the bundle is null.
495       * See WebViewSaveStateSample.
496       */
497      public var viewState: Bundle? = null
498          internal set
499  
500      // We need access to this in the state saver. An internal DisposableEffect or AndroidView
501      // onDestroy is called after the state saver and so can't be used.
502      internal var webView by mutableStateOf<WebView?>(null)
503  }
504  
505  /**
506   * Allows control over the navigation of a WebView from outside the composable. E.g. for performing
507   * a back navigation in response to the user clicking the "up" button in a TopAppBar.
508   *
509   * @see [rememberWebViewNavigator]
510   */
511  @Stable
512  @Deprecated(
513      """
514  accompanist/web is deprecated and the API is no longer maintained.
515  We recommend forking the implementation and customising it to your needs.
516  For more information please visit https://google.github.io/accompanist/web
517  """
518  )
519  public class WebViewNavigator(private val coroutineScope: CoroutineScope) {
520      private sealed interface NavigationEvent {
521          object Back : NavigationEvent
522          object Forward : NavigationEvent
523          object Reload : NavigationEvent
524          object StopLoading : NavigationEvent
525  
526          data class LoadUrl(
527              val url: String,
528              val additionalHttpHeaders: Map<String, String> = emptyMap()
529          ) : NavigationEvent
530  
531          data class LoadHtml(
532              val html: String,
533              val baseUrl: String? = null,
534              val mimeType: String? = null,
535              val encoding: String? = "utf-8",
536              val historyUrl: String? = null
537          ) : NavigationEvent
538  
539          data class PostUrl(
540              val url: String,
541              val postData: ByteArray
542          ) : NavigationEvent {
equalsnull543              override fun equals(other: Any?): Boolean {
544                  if (this === other) return true
545                  if (javaClass != other?.javaClass) return false
546  
547                  other as PostUrl
548  
549                  if (url != other.url) return false
550                  if (!postData.contentEquals(other.postData)) return false
551  
552                  return true
553              }
554  
hashCodenull555              override fun hashCode(): Int {
556                  var result = url.hashCode()
557                  result = 31 * result + postData.contentHashCode()
558                  return result
559              }
560          }
561      }
562  
563      private val navigationEvents: MutableSharedFlow<NavigationEvent> = MutableSharedFlow(replay = 1)
564  
565      // Use Dispatchers.Main to ensure that the webview methods are called on UI thread
handleNavigationEventsnull566      internal suspend fun WebView.handleNavigationEvents(): Nothing = withContext(Dispatchers.Main) {
567          navigationEvents.collect { event ->
568              when (event) {
569                  is NavigationEvent.Back -> goBack()
570                  is NavigationEvent.Forward -> goForward()
571                  is NavigationEvent.Reload -> reload()
572                  is NavigationEvent.StopLoading -> stopLoading()
573                  is NavigationEvent.LoadHtml -> loadDataWithBaseURL(
574                      event.baseUrl,
575                      event.html,
576                      event.mimeType,
577                      event.encoding,
578                      event.historyUrl
579                  )
580  
581                  is NavigationEvent.LoadUrl -> {
582                      loadUrl(event.url, event.additionalHttpHeaders)
583                  }
584  
585                  is NavigationEvent.PostUrl -> {
586                      postUrl(event.url, event.postData)
587                  }
588              }
589          }
590      }
591  
592      /**
593       * True when the web view is able to navigate backwards, false otherwise.
594       */
595      public var canGoBack: Boolean by mutableStateOf(false)
596          internal set
597  
598      /**
599       * True when the web view is able to navigate forwards, false otherwise.
600       */
601      public var canGoForward: Boolean by mutableStateOf(false)
602          internal set
603  
loadUrlnull604      public fun loadUrl(url: String, additionalHttpHeaders: Map<String, String> = emptyMap()) {
605          coroutineScope.launch {
606              navigationEvents.emit(
607                  NavigationEvent.LoadUrl(
608                      url,
609                      additionalHttpHeaders
610                  )
611              )
612          }
613      }
614  
loadHtmlnull615      public fun loadHtml(
616          html: String,
617          baseUrl: String? = null,
618          mimeType: String? = null,
619          encoding: String? = "utf-8",
620          historyUrl: String? = null
621      ) {
622          coroutineScope.launch {
623              navigationEvents.emit(
624                  NavigationEvent.LoadHtml(
625                      html,
626                      baseUrl,
627                      mimeType,
628                      encoding,
629                      historyUrl
630                  )
631              )
632          }
633      }
634  
postUrlnull635      public fun postUrl(
636          url: String,
637          postData: ByteArray
638      ) {
639          coroutineScope.launch {
640              navigationEvents.emit(
641                  NavigationEvent.PostUrl(
642                      url,
643                      postData
644                  )
645              )
646          }
647      }
648  
649      /**
650       * Navigates the webview back to the previous page.
651       */
navigateBacknull652      public fun navigateBack() {
653          coroutineScope.launch { navigationEvents.emit(NavigationEvent.Back) }
654      }
655  
656      /**
657       * Navigates the webview forward after going back from a page.
658       */
navigateForwardnull659      public fun navigateForward() {
660          coroutineScope.launch { navigationEvents.emit(NavigationEvent.Forward) }
661      }
662  
663      /**
664       * Reloads the current page in the webview.
665       */
reloadnull666      public fun reload() {
667          coroutineScope.launch { navigationEvents.emit(NavigationEvent.Reload) }
668      }
669  
670      /**
671       * Stops the current page load (if one is loading).
672       */
stopLoadingnull673      public fun stopLoading() {
674          coroutineScope.launch { navigationEvents.emit(NavigationEvent.StopLoading) }
675      }
676  }
677  
678  /**
679   * Creates and remembers a [WebViewNavigator] using the default [CoroutineScope] or a provided
680   * override.
681   */
682  @Composable
683  @Deprecated(
684      """
685  accompanist/web is deprecated and the API is no longer maintained.
686  We recommend forking the implementation and customising it to your needs.
687  For more information please visit https://google.github.io/accompanist/web
688  """
689  )
rememberWebViewNavigatornull690  public fun rememberWebViewNavigator(
691      coroutineScope: CoroutineScope = rememberCoroutineScope()
692  ): WebViewNavigator = remember(coroutineScope) { WebViewNavigator(coroutineScope) }
693  
694  /**
695   * A wrapper class to hold errors from the WebView.
696   */
697  @Immutable
698  @Deprecated(
699      """
700  accompanist/web is deprecated and the API is no longer maintained.
701  We recommend forking the implementation and customising it to your needs.
702  For more information please visit https://google.github.io/accompanist/web
703  """
704  )
705  public data class WebViewError(
706      /**
707       * The request the error came from.
708       */
709      val request: WebResourceRequest?,
710      /**
711       * The error that was reported.
712       */
713      val error: WebResourceError
714  )
715  
716  /**
717   * Creates a WebView state that is remembered across Compositions.
718   *
719   * @param url The url to load in the WebView
720   * @param additionalHttpHeaders Optional, additional HTTP headers that are passed to [WebView.loadUrl].
721   *                              Note that these headers are used for all subsequent requests of the WebView.
722   */
723  @Composable
724  @Deprecated(
725      """
726  accompanist/web is deprecated and the API is no longer maintained.
727  We recommend forking the implementation and customising it to your needs.
728  For more information please visit https://google.github.io/accompanist/web
729  """
730  )
rememberWebViewStatenull731  public fun rememberWebViewState(
732      url: String,
733      additionalHttpHeaders: Map<String, String> = emptyMap()
734  ): WebViewState =
735  // Rather than using .apply {} here we will recreate the state, this prevents
736      // a recomposition loop when the webview updates the url itself.
737      remember {
738          WebViewState(
739              WebContent.Url(
740                  url = url,
741                  additionalHttpHeaders = additionalHttpHeaders
742              )
743          )
744      }.apply {
745          this.content = WebContent.Url(
746              url = url,
747              additionalHttpHeaders = additionalHttpHeaders
748          )
749      }
750  
751  /**
752   * Creates a WebView state that is remembered across Compositions.
753   *
754   * @param data The uri to load in the WebView
755   */
756  @Composable
757  @Deprecated(
758      """
759  accompanist/web is deprecated and the API is no longer maintained.
760  We recommend forking the implementation and customising it to your needs.
761  For more information please visit https://google.github.io/accompanist/web
762  """
763  )
rememberWebViewStateWithHTMLDatanull764  public fun rememberWebViewStateWithHTMLData(
765      data: String,
766      baseUrl: String? = null,
767      encoding: String = "utf-8",
768      mimeType: String? = null,
769      historyUrl: String? = null
770  ): WebViewState =
771      remember {
772          WebViewState(WebContent.Data(data, baseUrl, encoding, mimeType, historyUrl))
773      }.apply {
774          this.content = WebContent.Data(
775              data, baseUrl, encoding, mimeType, historyUrl
776          )
777      }
778  
779  /**
780   * Creates a WebView state that is remembered across Compositions.
781   *
782   * @param url The url to load in the WebView
783   * @param postData The data to be posted to the WebView with the url
784   */
785  @Composable
786  @Deprecated(
787      """
788  accompanist/web is deprecated and the API is no longer maintained.
789  We recommend forking the implementation and customising it to your needs.
790  For more information please visit https://google.github.io/accompanist/web
791  """
792  )
rememberWebViewStatenull793  public fun rememberWebViewState(
794      url: String,
795      postData: ByteArray
796  ): WebViewState =
797  // Rather than using .apply {} here we will recreate the state, this prevents
798      // a recomposition loop when the webview updates the url itself.
799      remember {
800          WebViewState(
801              WebContent.Post(
802                  url = url,
803                  postData = postData
804              )
805          )
806      }.apply {
807          this.content = WebContent.Post(
808              url = url,
809              postData = postData
810          )
811      }
812  
813  /**
814   * Creates a WebView state that is remembered across Compositions and saved
815   * across activity recreation.
816   * When using saved state, you cannot change the URL via recomposition. The only way to load
817   * a URL is via a WebViewNavigator.
818   *
819   * @param data The uri to load in the WebView
820   * @sample com.google.accompanist.sample.webview.WebViewSaveStateSample
821   */
822  @Composable
823  @Deprecated(
824      """
825  accompanist/web is deprecated and the API is no longer maintained.
826  We recommend forking the implementation and customising it to your needs.
827  For more information please visit https://google.github.io/accompanist/web
828  """
829  )
rememberSaveableWebViewStatenull830  public fun rememberSaveableWebViewState(): WebViewState =
831      rememberSaveable(saver = WebStateSaver) {
832          WebViewState(WebContent.NavigatorOnly)
833      }
834  
835  @Deprecated(
836      """
837  accompanist/web is deprecated and the API is no longer maintained.
838  We recommend forking the implementation and customising it to your needs.
839  For more information please visit https://google.github.io/accompanist/web
840  """
841  )
<lambda>null842  public val WebStateSaver: Saver<WebViewState, Any> = run {
843      val pageTitleKey = "pagetitle"
844      val lastLoadedUrlKey = "lastloaded"
845      val stateBundle = "bundle"
846  
847      mapSaver(
848          save = {
849              val viewState = Bundle().apply { it.webView?.saveState(this) }
850              mapOf(
851                  pageTitleKey to it.pageTitle,
852                  lastLoadedUrlKey to it.lastLoadedUrl,
853                  stateBundle to viewState
854              )
855          },
856          restore = {
857              WebViewState(WebContent.NavigatorOnly).apply {
858                  this.pageTitle = it[pageTitleKey] as String?
859                  this.lastLoadedUrl = it[lastLoadedUrlKey] as String?
860                  this.viewState = it[stateBundle] as Bundle?
861              }
862          }
863      )
864  }
865