Skip to content

Commit 1566341

Browse files
authored
Configure script based on remote config (#7036)
Task/Issue URL: https://app.asana.com/1/137249556945/project/72649045549333/task/1211755269770777?focus=true ### Description Configure script based on remote config ### Steps to test this PR _Feature 1_ - [x] Apply [patch](https://duckduckgo-my.sharepoint.com/:u:/p/cbarreiro/Ecfv-0RF5YhEmBLE4e5PIh4BxUsIvZVRz0v2rbsak99Ilg?e=mfUf0W) - [x] Clean install app - [x] Wait for WebView to load and filter logcat by "Cris" - [x] Check there's a log with the script that has been injected, and it contains the following - [ ] const delay = 10; - [ ] const postInitialPing = true; - [ ] const replyToNativeMessages = true; ### UI changes n/a
1 parent c06a4fc commit 1566341

File tree

3 files changed

+115
-1
lines changed

3 files changed

+115
-1
lines changed

app/src/main/java/com/duckduckgo/app/browser/BrowserTabFragment.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ import com.duckduckgo.savedsites.api.models.SavedSitesNames
329329
import com.duckduckgo.savedsites.impl.bookmarks.BookmarksBottomSheetDialog
330330
import com.duckduckgo.savedsites.impl.bookmarks.FaviconPromptSheet
331331
import com.duckduckgo.savedsites.impl.dialogs.EditSavedSiteDialogFragment
332-
import com.duckduckgo.serp.logos.api.SerpLogoScreens.*
332+
import com.duckduckgo.serp.logos.api.SerpLogoScreens.EasterEggLogoScreen
333333
import com.duckduckgo.serp.logos.api.SerpLogos
334334
import com.duckduckgo.site.permissions.api.SitePermissionsDialogLauncher
335335
import com.duckduckgo.site.permissions.api.SitePermissionsGrantedListener
@@ -599,6 +599,9 @@ class BrowserTabFragment :
599599
@Inject
600600
lateinit var omnibarFeatureRepository: OmnibarFeatureRepository
601601

602+
@Inject
603+
lateinit var webViewCompatTestHelper: WebViewCompatTestHelper
604+
602605
/**
603606
* We use this to monitor whether the user was seeing the in-context Email Protection signup prompt
604607
* This is needed because the activity stack will be cleared if an external link is opened in our browser
@@ -3246,6 +3249,9 @@ class BrowserTabFragment :
32463249
onInContextEmailProtectionSignupPromptShown = { showNativeInContextEmailProtectionSignupPrompt() },
32473250
)
32483251
configureWebViewForBlobDownload(it)
3252+
lifecycleScope.launch {
3253+
webViewCompatTestHelper.configureWebViewForWebViewCompatTest(it)
3254+
}
32493255
configureWebViewForAutofill(it)
32503256
printInjector.addJsInterface(it) { viewModel.printFromWebView() }
32513257
autoconsent.addJsInterface(it, autoconsentCallback)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2025 DuckDuckGo
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+
* http://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+
package com.duckduckgo.app.browser
18+
19+
import com.duckduckgo.app.browser.webview.WebViewCompatFeature
20+
import com.duckduckgo.app.browser.webview.WebViewCompatFeatureSettings
21+
import com.duckduckgo.browser.api.webviewcompat.WebViewCompatWrapper
22+
import com.duckduckgo.common.utils.DispatcherProvider
23+
import com.duckduckgo.di.scopes.FragmentScope
24+
import com.squareup.anvil.annotations.ContributesBinding
25+
import com.squareup.moshi.Moshi
26+
import dagger.SingleInstanceIn
27+
import kotlinx.coroutines.withContext
28+
import javax.inject.Inject
29+
30+
private const val delay = "\$DELAY$"
31+
private const val postInitialPing = "\$POST_INITIAL_PING$"
32+
private const val replyToNativeMessages = "\$REPLY_TO_NATIVE_MESSAGES$"
33+
34+
interface WebViewCompatTestHelper {
35+
suspend fun configureWebViewForWebViewCompatTest(webView: DuckDuckGoWebView)
36+
}
37+
38+
@ContributesBinding(FragmentScope::class)
39+
@SingleInstanceIn(FragmentScope::class)
40+
class RealWebViewCompatTestHelper @Inject constructor(
41+
private val dispatchers: DispatcherProvider,
42+
private val webViewCompatFeature: WebViewCompatFeature,
43+
private val webViewCompatWrapper: WebViewCompatWrapper,
44+
moshi: Moshi,
45+
) : WebViewCompatTestHelper {
46+
47+
private val adapter = moshi.adapter(WebViewCompatFeatureSettings::class.java)
48+
49+
override suspend fun configureWebViewForWebViewCompatTest(webView: DuckDuckGoWebView) {
50+
val script = withContext(dispatchers.io()) {
51+
if (!webViewCompatFeature.self().isEnabled()) return@withContext null
52+
53+
val webViewCompatSettings = webViewCompatFeature.self().getSettings()?.let {
54+
adapter.fromJson(it)
55+
}
56+
webView.resources?.openRawResource(R.raw.webviewcompat_test_script)?.bufferedReader().use { it?.readText() }.orEmpty()
57+
.replace(delay, webViewCompatSettings?.jsInitialPingDelay?.toString() ?: "0")
58+
.replace(postInitialPing, webViewCompatFeature.jsSendsInitialPing().isEnabled().toString())
59+
.replace(replyToNativeMessages, webViewCompatFeature.jsRepliesToNativeMessages().isEnabled().toString())
60+
} ?: return
61+
62+
withContext(dispatchers.main()) {
63+
webViewCompatWrapper.addDocumentStartJavaScript(webView, script, setOf("*"))
64+
}
65+
}
66+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* Copyright (c) 2024 DuckDuckGo
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+
* http://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+
package com.duckduckgo.app.browser.webview
18+
19+
import com.duckduckgo.anvil.annotations.ContributesRemoteFeature
20+
import com.duckduckgo.di.scopes.AppScope
21+
import com.duckduckgo.feature.toggles.api.Toggle
22+
import com.duckduckgo.feature.toggles.api.Toggle.DefaultFeatureValue
23+
24+
@ContributesRemoteFeature(
25+
scope = AppScope::class,
26+
featureName = "webViewCompat",
27+
)
28+
interface WebViewCompatFeature {
29+
30+
@Toggle.DefaultValue(DefaultFeatureValue.FALSE)
31+
fun self(): Toggle
32+
33+
@Toggle.DefaultValue(DefaultFeatureValue.FALSE)
34+
fun jsSendsInitialPing(): Toggle
35+
36+
@Toggle.DefaultValue(DefaultFeatureValue.FALSE)
37+
fun jsRepliesToNativeMessages(): Toggle
38+
}
39+
40+
data class WebViewCompatFeatureSettings(
41+
val jsInitialPingDelay: Long = 0,
42+
)

0 commit comments

Comments
 (0)