Skip to content

Commit a173a1a

Browse files
CAMOBAPDSergiu
andauthored
feat: preload webview (#175)
* feat: create WebView before xml inflation * feat: compose-sdk wrap HCaptchaWebView into remember * chore: upgrade com.android.tools.build:gradle:8.7.3 * chore: bump version 4.1.0 * chore: make log statements follow format "identifier: message" Co-authored-by: Sergiu D. <danalachi.sergiu@gmail.com> --------- Co-authored-by: Sergiu D. <danalachi.sergiu@gmail.com>
1 parent c83aad6 commit a173a1a

File tree

22 files changed

+223
-130
lines changed

22 files changed

+223
-130
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
- name: 'HTML ES5 test'
3636
run: |
3737
npm install -g jshint
38-
java -cp sdk/build/intermediates/javac/release/classes com.hcaptcha.sdk.HCaptchaHtml > sdk/build/hcaptcha-form.html
38+
java -cp sdk/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes com.hcaptcha.sdk.HCaptchaHtml > sdk/build/hcaptcha-form.html
3939
jshint --extract=always sdk/build/hcaptcha-form.html
4040
- name: 'JitPack Test'
4141
run: ./gradlew publishReleasePublicationToMavenLocal

CHANGES.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
# 4.1.0
4+
5+
- Feat: preload WebView on `setup` call
6+
37
# 4.0.5
48

59
- compose-sdk: set minSdk to 21

benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaHtml.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
import androidx.annotation.NonNull;
44

5-
import com.hcaptcha.sdk.IHCaptchaHtmlProvider;
6-
75
class TestHCaptchaHtml implements IHCaptchaHtmlProvider {
86

97
@Override

benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaVerifier.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@
22

33
import android.app.Activity;
44

5+
import androidx.annotation.NonNull;
6+
57
public class TestHCaptchaVerifier implements IHCaptchaVerifier {
68

79
@Override
8-
public void startVerification(Activity activity) {
10+
public void startVerification(@NonNull Activity activity) {
911
// no implementation need for performance measurement
1012
}
1113

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ buildscript {
55
mavenCentral()
66
}
77
dependencies {
8-
classpath 'com.android.tools.build:gradle:8.1.4'
9-
classpath 'androidx.benchmark:benchmark-gradle-plugin:1.2.4'
8+
classpath 'com.android.tools.build:gradle:8.7.3'
9+
classpath 'androidx.benchmark:benchmark-gradle-plugin:1.3.3'
1010
classpath 'com.slack.keeper:keeper:0.16.0'
1111
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1212
}

compose-sdk/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ android {
2020
// See https://developer.android.com/studio/publish/versioning
2121
// versionCode must be integer and be incremented by one for every new update
2222
// android system uses this to prevent downgrades
23-
versionCode 44
23+
versionCode 45
2424

2525
// version number visible to the user
2626
// should follow semantic versioning (See https://semver.org)
27-
versionName "4.0.5"
27+
versionName "4.1.0"
2828

2929
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
3030
consumerProguardFiles "consumer-rules.pro"

compose-sdk/src/main/java/com/hcaptcha/sdk/HCaptchaCompose.kt

Lines changed: 16 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,43 @@
11
package com.hcaptcha.sdk
22

3-
import android.app.Activity
43
import android.os.Handler
54
import android.os.Looper
65
import androidx.compose.foundation.layout.fillMaxSize
76
import androidx.compose.foundation.layout.size
87
import androidx.compose.runtime.Composable
8+
import androidx.compose.runtime.mutableStateOf
9+
import androidx.compose.runtime.remember
910
import androidx.compose.ui.Modifier
11+
import androidx.compose.ui.platform.LocalContext
1012
import androidx.compose.ui.unit.dp
1113
import androidx.compose.ui.viewinterop.AndroidView
1214
import androidx.compose.ui.window.Dialog
1315
import androidx.compose.ui.window.DialogProperties
1416

1517
@Composable
1618
public fun HCaptchaCompose(config: HCaptchaConfig, onResult: (HCaptchaResponse) -> Unit) {
17-
val handler = Handler(Looper.getMainLooper())
18-
var helper: HCaptchaWebViewHelper? = null
19-
val verifier = object : IHCaptchaVerifier {
20-
override fun onLoaded() {
21-
onResult(HCaptchaResponse.Event(HCaptchaEvent.Loaded))
22-
if (config.hideDialog) {
23-
helper?.let {
24-
it.resetAndExecute()
25-
} ?: run {
26-
HCaptchaLog.w("HCaptchaWebViewHelper wasn't created, report but to developer")
27-
onResult(HCaptchaResponse.Failure(HCaptchaError.INTERNAL_ERROR))
28-
}
29-
}
30-
}
31-
32-
override fun onOpen() {
33-
onResult(HCaptchaResponse.Event(HCaptchaEvent.Opened))
34-
}
35-
36-
override fun onSuccess(result: String) {
37-
onResult(HCaptchaResponse.Success(result))
38-
}
39-
40-
override fun onFailure(exception: HCaptchaException) {
41-
onResult(HCaptchaResponse.Failure(exception.hCaptchaError))
42-
}
19+
HCaptchaLog.sDiagnosticsLogEnabled = config.diagnosticLog
4320

44-
override fun startVerification(activity: Activity) {
45-
error("startVerification should never be reached")
46-
}
21+
val context = LocalContext.current
22+
val handler = Handler(Looper.getMainLooper())
23+
val internalConfig = HCaptchaInternalConfig(com.hcaptcha.sdk.HCaptchaHtml())
4724

48-
override fun reset() {
49-
error("reset should never be reached")
25+
val helper = remember { mutableStateOf<HCaptchaWebViewHelper?>(null) }
26+
val verifier = remember { HCaptchaComposeVerifier(config, onResult, helper) }
27+
val preloadedWebView = remember {
28+
HCaptchaWebView(context).apply {
29+
helper.value = HCaptchaWebViewHelper(
30+
handler, context, config, internalConfig, verifier, this
31+
)
5032
}
5133
}
52-
val internalConfig = HCaptchaInternalConfig(com.hcaptcha.sdk.HCaptchaHtml())
53-
HCaptchaLog.sDiagnosticsLogEnabled = config.diagnosticLog
5434

5535
HCaptchaLog.d("HCaptchaCompose($config)")
5636

5737
if (config.hideDialog) {
5838
AndroidView(
5939
modifier = Modifier.size(0.dp),
60-
factory = { context ->
61-
HCaptchaWebView(context).apply {
62-
helper = HCaptchaWebViewHelper(
63-
handler,
64-
context,
65-
config,
66-
internalConfig,
67-
verifier,
68-
this
69-
)
70-
}
71-
}
40+
factory = { preloadedWebView }
7241
)
7342
} else {
7443
Dialog(
@@ -77,18 +46,7 @@ public fun HCaptchaCompose(config: HCaptchaConfig, onResult: (HCaptchaResponse)
7746
) {
7847
AndroidView(
7948
modifier = Modifier.fillMaxSize(),
80-
factory = { context ->
81-
HCaptchaWebView(context).apply {
82-
helper = HCaptchaWebViewHelper(
83-
handler,
84-
context,
85-
config,
86-
internalConfig,
87-
verifier,
88-
this
89-
)
90-
}
91-
}
49+
factory = { preloadedWebView }
9250
)
9351
}
9452
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.hcaptcha.sdk
2+
3+
import android.app.Activity
4+
import androidx.compose.runtime.State
5+
6+
internal class HCaptchaComposeVerifier(
7+
private val config: HCaptchaConfig,
8+
private val onResult: (HCaptchaResponse) -> Unit,
9+
private val helperState: State<HCaptchaWebViewHelper?>
10+
) : IHCaptchaVerifier {
11+
12+
override fun onLoaded() {
13+
onResult(HCaptchaResponse.Event(HCaptchaEvent.Loaded))
14+
if (config.hideDialog) {
15+
helperState.value?.resetAndExecute() ?: run {
16+
HCaptchaLog.w("HCaptchaWebViewHelper wasn't created, report but to developer")
17+
onResult(HCaptchaResponse.Failure(HCaptchaError.INTERNAL_ERROR))
18+
}
19+
}
20+
}
21+
22+
override fun onOpen() {
23+
onResult(HCaptchaResponse.Event(HCaptchaEvent.Opened))
24+
}
25+
26+
override fun onSuccess(result: String) {
27+
onResult(HCaptchaResponse.Success(result))
28+
}
29+
30+
override fun onFailure(exception: HCaptchaException) {
31+
onResult(HCaptchaResponse.Failure(exception.hCaptchaError))
32+
}
33+
34+
override fun startVerification(activity: Activity) {
35+
error("startVerification should never be reached")
36+
}
37+
38+
override fun reset() {
39+
error("reset should never be reached")
40+
}
41+
}

example-compose-app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ android {
1212
namespace 'com.hcaptcha.example.compose'
1313

1414
defaultConfig {
15-
minSdkVersion 23
15+
minSdkVersion 21
1616
targetSdkVersion intProp("exampleTargetSdkVersion", 35)
1717
versionCode 1
1818
versionName "0.0.1"

example-compose-app/src/main/java/com/hcaptcha/example/compose/ComposeActivity.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import com.hcaptcha.sdk.HCaptchaCompose
2121
import com.hcaptcha.sdk.HCaptchaConfig
2222
import com.hcaptcha.sdk.HCaptchaEvent
2323
import com.hcaptcha.sdk.HCaptchaResponse
24+
import com.hcaptcha.sdk.HCaptchaSize
2425

2526
class ComposeActivity : ComponentActivity() {
2627

@@ -33,7 +34,9 @@ class ComposeActivity : ComponentActivity() {
3334
var text by remember { mutableStateOf("") }
3435

3536
Column(
36-
modifier = Modifier.fillMaxSize().padding(16.dp),
37+
modifier = Modifier.fillMaxSize()
38+
.padding(WindowInsets.systemBars.asPaddingValues())
39+
.padding(16.dp),
3740
verticalArrangement = Arrangement.Bottom
3841
) {
3942
TextField(
@@ -91,6 +94,7 @@ class ComposeActivity : ComponentActivity() {
9194
HCaptchaCompose(HCaptchaConfig
9295
.builder()
9396
.siteKey("10000000-ffff-ffff-ffff-000000000001")
97+
.size(if (hideDialog) HCaptchaSize.INVISIBLE else HCaptchaSize.NORMAL)
9498
.hideDialog(hideDialog)
9599
.diagnosticLog(true)
96100
.build()) { result ->

gradle/shared/code-quality.gradle

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ checkstyle {
22
toolVersion = '8.45.1'
33
}
44

5-
task checkstyle(type: Checkstyle) {
5+
tasks.register('checkstyle', Checkstyle) {
66
description 'Check code standard'
77
group 'verification'
88
configFile file("${rootDir}/gradle/config/checkstyle.xml")
@@ -19,7 +19,7 @@ pmd {
1919
toolVersion = "6.51.0"
2020
}
2121

22-
task pmd(type: Pmd) {
22+
tasks.register('pmd', Pmd) {
2323
ruleSetFiles = files("${project.rootDir}/gradle/config/pmd.xml")
2424
ignoreFailures = false
2525
ruleSets = []
@@ -56,7 +56,8 @@ gradle.taskGraph.beforeTask { task ->
5656
}
5757

5858
// https://www.rallyhealth.com/coding/code-coverage-for-android-testing
59-
task jacocoUnitTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest']) {
59+
tasks.register('jacocoUnitTestReport', JacocoReport) {
60+
dependsOn['testDebugUnitTest']
6061
def coverageSourceDirs = [
6162
"src/main/java"
6263
]
@@ -79,6 +80,8 @@ task jacocoUnitTestReport(type: JacocoReport, dependsOn: ['testDebugUnitTest'])
7980
xml.required = true
8081
html.required = true
8182
}
83+
84+
inputs.files(tasks.named("testDebugUnitTest").get().outputs)
8285
}
8386

8487
check.dependsOn('checkstyle', 'pmd', 'jacocoUnitTestReport')
@@ -93,16 +96,16 @@ sonarqube {
9396
property "sonar.sourceEncoding", "utf-8"
9497

9598
property "sonar.sources", "src/main"
96-
property "sonar.java.binaries", "${project.buildDir}/intermediates/javac/debug/classes"
99+
property "sonar.java.binaries", layout.buildDirectory.dir("intermediates/javac/debug/compileDebugJavaWithJavac/classes").get().asFile.absolutePath
97100
property "sonar.tests", ["src/test/", "../test/src/androidTest/"]
98101

99-
property "sonar.android.lint.report", "${project.buildDir}/outputs/lint-results.xml"
100-
property "sonar.java.spotbugs.reportPaths", ["${project.buildDir}/reports/spotbugs/debug.xml", "${project.buildDir}/reports/spotbugs/release.xml"]
101-
property "sonar.java.pmd.reportPaths", "${project.buildDir}/reports/pmd/pmd.xml"
102-
property "sonar.java.checkstyle.reportPaths", "${project.buildDir}/reports/checkstyle/checkstyle.xml"
103-
property "sonar.coverage.jacoco.xmlReportPaths", "${project.buildDir}/reports/jacoco/jacocoUnitTestReport.xml"
102+
property "sonar.android.lint.report", layout.buildDirectory.dir("outputs/lint-results.xml").get().asFile.absolutePath
103+
property "sonar.java.spotbugs.reportPaths", ["debug", "release"].collect { layout.buildDirectory.dir("reports/spotbugs/${it}.xml").get().asFile.absolutePath }
104+
property "sonar.java.pmd.reportPaths", layout.buildDirectory.dir("reports/pmd/pmd.xml").get().asFile.absolutePath
105+
property "sonar.java.checkstyle.reportPaths", layout.buildDirectory.dir("reports/checkstyle/checkstyle.xml").get().asFile.absolutePath
106+
property "sonar.coverage.jacoco.xmlReportPaths", layout.buildDirectory.dir("reports/jacoco/jacocoUnitTestReport.xml").get().asFile.absolutePath
104107
}
105108
}
106109

107-
project.tasks["sonarqube"].dependsOn "check"
110+
project.tasks.named("sonarqube").configure { dependsOn "check" }
108111

gradle/shared/html-java-gen.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
android.libraryVariants.all { variant ->
22
def packageName = android.namespace
33
def variantName = variant.name.capitalize()
4-
def outputDir = file("${project.buildDir}/generated/source/hcaptcha/${variant.name}/${packageName.replaceAll('\\.', '/')}")
5-
def generateTask = project.task("generate${variantName}JavaClassFromStaticHtml") {
4+
def outputDir = layout.buildDirectory.dir("generated/source/hcaptcha/${variant.name}/${packageName.replaceAll('\\.', '/')}").get().asFile
5+
def generateTask = tasks.register("generate${variantName}JavaClassFromStaticHtml") {
66
group 'Generate'
77
description "Generate HTML java class"
88

@@ -27,5 +27,5 @@ android.libraryVariants.all { variant ->
2727
}
2828

2929
// preBuild.dependsOn generateTask
30-
variant.registerJavaGeneratingTask(generateTask, outputDir)
30+
variant.registerJavaGeneratingTask(generateTask.get(), outputDir)
3131
}

gradle/shared/size-check.gradle

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
android.libraryVariants.all { variant ->
22
def variantName = variant.name.capitalize()
3-
project.task("report${variantName}AarSize") {
3+
tasks.register("report${variantName}AarSize") {
44
group 'Help'
55
description "Report ${variant.name} AAR size"
66
dependsOn variant.packageLibraryProvider
@@ -12,7 +12,7 @@ android.libraryVariants.all { variant ->
1212
}
1313
}
1414

15-
project.tasks.findByName("check").dependsOn(project.task("check${variantName}AarSize") {
15+
tasks.register("check${variantName}AarSize") {
1616
group 'Verification'
1717
description "Checks ${variant.name} AAR size doesn't exceed ${project.ext}Kb"
1818
dependsOn variant.packageLibraryProvider
@@ -24,5 +24,7 @@ android.libraryVariants.all { variant ->
2424
throw new GradleException("${aarPath} size exceeded! ${aarSizeKb}Kbyte > ${MAX_AAR_SIZE_KB}Kbyte")
2525
}
2626
}
27-
})
27+
}
28+
29+
tasks.named("check").configure { dependsOn "check${variantName}AarSize" }
2830
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
44
zipStoreBase=GRADLE_USER_HOME
55
zipStorePath=wrapper/dists

sdk/build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ android {
2828
// See https://developer.android.com/studio/publish/versioning
2929
// versionCode must be integer and be incremented by one for every new update
3030
// android system uses this to prevent downgrades
31-
versionCode 44
31+
versionCode 45
3232

3333
// version number visible to the user
3434
// should follow semantic versioning (See https://semver.org)
35-
versionName "4.0.5"
35+
versionName "4.1.0"
3636

3737
buildConfigField 'String', 'VERSION_NAME', "\"${defaultConfig.versionName}_${defaultConfig.versionCode}\""
3838

sdk/src/main/java/com/hcaptcha/sdk/HCaptcha.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ void onFailure(final HCaptchaException exception) {
103103
.build();
104104
captchaVerifier = new HCaptchaHeadlessWebView(activity, this.config, internalConfig, listener);
105105
} else if (this.activity instanceof FragmentActivity) {
106-
captchaVerifier = HCaptchaDialogFragment.newInstance(inputConfig, internalConfig, listener);
106+
captchaVerifier = HCaptchaDialogFragment.newInstance(activity, inputConfig, internalConfig, listener);
107107
this.config = inputConfig;
108108
} else {
109109
throw new IllegalStateException("Visual hCaptcha challenge verification requires FragmentActivity.");

0 commit comments

Comments
 (0)