@@ -38,6 +38,7 @@ import org.dweb_browser.dwebview.polyfill.FaviconPolyfill
3838import org.dweb_browser.dwebview.wkWebsiteDataStore
3939import org.dweb_browser.helper.JsonLoose
4040import org.dweb_browser.helper.PureBounds
41+ import org.dweb_browser.helper.SafeHashSet
4142import org.dweb_browser.helper.Signal
4243import org.dweb_browser.helper.SimpleSignal
4344import org.dweb_browser.helper.collectIn
@@ -76,6 +77,8 @@ import platform.WebKit.javaScriptEnabled
7677@OptIn(ExperimentalForeignApi ::class )
7778internal val dwebHelper = DwebHelper ()
7879
80+ typealias CompletionHandler = (Any? , platform.Foundation .NSError ? ) -> Unit
81+
7982@Suppress(" CONFLICTING_OVERLOADS" )
8083@OptIn(ExperimentalForeignApi ::class , ExperimentalResourceApi ::class )
8184class DWebViewEngine (
@@ -224,18 +227,19 @@ class DWebViewEngine(
224227 httpLocalhostGatewaySuffix
225228 )
226229 ) {
227- " dweb+" + inputUrl.replace(inputHostWithPort, inputHostWithPort.substring(
228- 0 , inputHostWithPort.length - httpLocalhostGatewaySuffix.length
229- ).let { dwebHost ->
230- val hostInfo = dwebHost.split(' -' )
231- val port = hostInfo.last().toUShortOrNull()
232- if (port != null ) {
233- hostInfo.toMutableList().run {
234- removeLast()
235- joinToString(" -" )
236- } + " :$port "
237- } else dwebHost
238- })
230+ " dweb+" + inputUrl.replace(
231+ inputHostWithPort, inputHostWithPort.substring(
232+ 0 , inputHostWithPort.length - httpLocalhostGatewaySuffix.length
233+ ).let { dwebHost ->
234+ val hostInfo = dwebHost.split(' -' )
235+ val port = hostInfo.last().toUShortOrNull()
236+ if (port != null ) {
237+ hostInfo.toMutableList().run {
238+ removeLast()
239+ joinToString(" -" )
240+ } + " :$port "
241+ } else dwebHost
242+ })
239243 } else inputUrl
240244 }
241245 }
@@ -258,8 +262,7 @@ class DWebViewEngine(
258262 internal val urlObserver = DWebUrlObserver (this )
259263 val loadStateFlow =
260264 setupLoadStateFlow(this , dwebNavigationDelegate, urlObserver, configuration, options.url)
261- val beforeUnloadSignal =
262- setupBeforeUnloadSignal(this , dwebNavigationDelegate, loadStateFlow)
265+ val beforeUnloadSignal = setupBeforeUnloadSignal(this , dwebNavigationDelegate, loadStateFlow)
263266 val overrideUrlLoadingHooks by lazy { setupOverrideUrlLoadingHooks(this , dwebNavigationDelegate) }
264267
265268 init {
@@ -372,8 +375,8 @@ class DWebViewEngine(
372375 override fun setFrame (frame : CValue <CGRect >) {
373376 super .setFrame(frame)
374377 scrollView.contentInset = cValue { UIEdgeInsetsZero };
375- if (! UIEdgeInsetsEqualToEdgeInsets (scrollView.adjustedContentInset,
376- cValue { UIEdgeInsetsZero })
378+ if (! UIEdgeInsetsEqualToEdgeInsets (
379+ scrollView.adjustedContentInset, cValue { UIEdgeInsetsZero })
377380 ) {
378381 val insetToAdjust = scrollView.adjustedContentInset;
379382 scrollView.contentInset =
@@ -411,6 +414,11 @@ class DWebViewEngine(
411414 return deferred
412415 }
413416
417+ /* *
418+ * 因为函数倒挂给 WKWebView,所以存在内存问题,这里强制存储回调,避免被 kotlin 回收。
419+ */
420+ private val completionHandlers = SafeHashSet <CompletionHandler >()
421+
414422 suspend fun <T > awaitAsyncJavaScript (
415423 functionBody : String ,
416424 arguments : Map <Any ?, * >? = null,
@@ -419,7 +427,7 @@ class DWebViewEngine(
419427 afterEval : (suspend () -> Unit )? = null,
420428 ): T {
421429 val deferred = CompletableDeferred <T >()
422- callAsyncJavaScript(functionBody, arguments, inFrame, inContentWorld) { result, error ->
430+ val ch : CompletionHandler = { result, error ->
423431 if (error == null ) {
424432 deferred.complete(result as T )
425433 } else {
@@ -437,9 +445,19 @@ class DWebViewEngine(
437445 )
438446 }
439447 }
448+ callAsyncJavaScript(
449+ functionBody = functionBody,
450+ arguments = arguments,
451+ inFrame = inFrame,
452+ inContentWorld = inContentWorld,
453+ completionHandler = ch,
454+ )
440455 afterEval?.invoke()
441456
442- return deferred.await()
457+ completionHandlers.add(ch)
458+ return deferred.await().also {
459+ completionHandlers.remove(ch)
460+ }
443461 }
444462
445463 /* *
0 commit comments