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