diff --git a/CHANGES.md b/CHANGES.md
index 794f0e8e..46a78a95 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,5 +1,9 @@
# Changelog
+# 4.0.0
+
+- Feat (breaking change): accept `HCaptcha.getClient(Activity)` for passive sitekeys. (#112)
+
# 3.11.0
- Fix: handle null `internalConfig` in args for HCaptchaDialogFragment (#140)
diff --git a/README.md b/README.md
index 9d91f857..6f3e4319 100644
--- a/README.md
+++ b/README.md
@@ -39,7 +39,6 @@ See the code example below along with the possible customization to enable human
-
## Usage
There are multiple ways to run a hCaptcha human verification. See the below snippet for the overall flow.
@@ -116,6 +115,11 @@ To remove a specific listener you may use `HCaptcha.removeOn[Success|Failure|Ope
To remove all listeners you may use `HCaptcha.removeAllListener()`.
+Note ⚠️: For any sitekey that can show visual challenges, `HCaptcha.getClient(Activity)` must be called with `FragmentActivity` instance.
+
+`Activity` is allowed only when `hideDialog=true` and sitekey setting is Passive (Enterprise feature).
+
+
```java
...
OnSuccessListener firstListener = new OnSuccessListener() {
@@ -265,19 +269,19 @@ You can add logic to gracefully handle the errors.
The following is a list of possible error codes:
-| Name | Code | Description |
-|-------------------------------|------|----------------------------------------------------|
-| `NETWORK_ERROR` | 7 | There is no internet connection. |
-| `INVALID_DATA` | 8 | Invalid data is not accepted by endpoints. |
-| `CHALLENGE_ERROR` | 9 | JS client encountered an error on challenge setup. |
-| `INTERNAL_ERROR` | 10 | JS client encountered an internal error. |
-| `SESSION_TIMEOUT` | 15 | The challenge expired. |
-| `TOKEN_TIMEOUT` | 16 | The token expired. |
-| `CHALLENGE_CLOSED` | 30 | The challenge was closed by the user. |
-| `RATE_LIMITED` | 31 | Spam detected. |
-| `INVALID_CUSTOM_THEME` | 32 | Invalid custom theme. |
-| `INSECURE_HTTP_REQUEST_ERROR` | 33 | Insecure resource requested. |
-| `ERROR` | 29 | General failure. |
+| Name | Code | Description |
+|--------------------------------|------|----------------------------------------------------|
+| `NETWORK_ERROR` | 7 | There is no internet connection. |
+| `INVALID_DATA` | 8 | Invalid data is not accepted by endpoints. |
+| `CHALLENGE_ERROR` | 9 | JS client encountered an error on challenge setup. |
+| `INTERNAL_ERROR` | 10 | JS client encountered an internal error. |
+| `SESSION_TIMEOUT` | 15 | The challenge expired. |
+| `TOKEN_TIMEOUT` | 16 | The token expired. |
+| `CHALLENGE_CLOSED` | 30 | The challenge was closed by the user. |
+| `RATE_LIMITED` | 31 | Spam detected. |
+| `INVALID_CUSTOM_THEME` | 32 | Invalid custom theme. |
+| `INSECURE_HTTP_REQUEST_ERROR` | 33 | Insecure resource requested. |
+| `ERROR` | 29 | General failure. |
### Retry Failed Verification
@@ -339,6 +343,12 @@ final HCaptchaConfig config = HCaptchaConfig.builder()
.build();
```
+> HCaptcha constantly failing with IllegalStateException "Visual Challenge verification require FragmentActivity", how to fix it?
+
+SDK expect to be initialized with `FragmentActivity` instance in regular scenario.
+
+In case if you use passive `siteKey` make sure that you called `hideDialog(true)` on `HCaptchaCconfig.builder()`
+
## For maintainers
If you plan to contribute to the repo, please see [MAINTAINERS.md](./MAINTAINERS.md) for detailed build, test, and release instructions.
diff --git a/benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaVerifier.java b/benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaVerifier.java
index a7559a18..2a4f4f6b 100644
--- a/benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaVerifier.java
+++ b/benchmark/src/androidTest/java/com/hcaptcha/sdk/TestHCaptchaVerifier.java
@@ -1,11 +1,11 @@
package com.hcaptcha.sdk;
-import androidx.fragment.app.FragmentActivity;
+import android.app.Activity;
public class TestHCaptchaVerifier implements IHCaptchaVerifier {
@Override
- public void startVerification(FragmentActivity activity) {
+ public void startVerification(Activity activity) {
// no implementation need for performance measurement
}
diff --git a/sdk/build.gradle b/sdk/build.gradle
index 6e562061..95229952 100644
--- a/sdk/build.gradle
+++ b/sdk/build.gradle
@@ -24,11 +24,11 @@ android {
// See https://developer.android.com/studio/publish/versioning
// versionCode must be integer and be incremented by one for every new update
// android system uses this to prevent downgrades
- versionCode 38
+ versionCode 39
// version number visible to the user
// should follow semantic versioning (See https://semver.org)
- versionName "3.11.0"
+ versionName "4.0.0"
buildConfigField 'String', 'VERSION_NAME', "\"${defaultConfig.versionName}_${defaultConfig.versionCode}\""
diff --git a/sdk/src/main/java/com/hcaptcha/sdk/HCaptcha.java b/sdk/src/main/java/com/hcaptcha/sdk/HCaptcha.java
index 077516cf..8dc4ce02 100644
--- a/sdk/src/main/java/com/hcaptcha/sdk/HCaptcha.java
+++ b/sdk/src/main/java/com/hcaptcha/sdk/HCaptcha.java
@@ -1,5 +1,6 @@
package com.hcaptcha.sdk;
+import android.app.Activity;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.Bundle;
@@ -14,7 +15,7 @@ public final class HCaptcha extends Task implements IHCap
public static final String META_SITE_KEY = "com.hcaptcha.sdk.site-key";
@NonNull
- private final FragmentActivity activity;
+ private final Activity activity;
@Nullable
private IHCaptchaVerifier captchaVerifier;
@@ -25,7 +26,7 @@ public final class HCaptcha extends Task implements IHCap
@NonNull
private final HCaptchaInternalConfig internalConfig;
- private HCaptcha(@NonNull final FragmentActivity activity, @NonNull final HCaptchaInternalConfig internalConfig) {
+ private HCaptcha(@NonNull final Activity activity, @NonNull final HCaptchaInternalConfig internalConfig) {
this.activity = activity;
this.internalConfig = internalConfig;
}
@@ -33,14 +34,15 @@ private HCaptcha(@NonNull final FragmentActivity activity, @NonNull final HCaptc
/**
* Constructs a new client which allows to display a challenge dialog
*
- * @param activity The current activity
+ * @param activity FragmentActivity instance for a visual challenge verification,
+ * or any Activity in case of passive siteKey
* @return new {@link HCaptcha} object
*/
- public static HCaptcha getClient(@NonNull final FragmentActivity activity) {
+ public static HCaptcha getClient(@NonNull final Activity activity) {
return new HCaptcha(activity, HCaptchaInternalConfig.builder().build());
}
- static HCaptcha getClient(@NonNull final FragmentActivity activity,
+ static HCaptcha getClient(@NonNull final Activity activity,
@NonNull HCaptchaInternalConfig internalConfig) {
return new HCaptcha(activity, internalConfig);
}
@@ -100,9 +102,11 @@ void onFailure(final HCaptchaException exception) {
.loading(false)
.build();
captchaVerifier = new HCaptchaHeadlessWebView(activity, this.config, internalConfig, listener);
- } else {
+ } else if (this.activity instanceof FragmentActivity) {
captchaVerifier = HCaptchaDialogFragment.newInstance(inputConfig, internalConfig, listener);
this.config = inputConfig;
+ } else {
+ throw new IllegalStateException("Visual hCaptcha challenge verification requires FragmentActivity.");
}
} catch (AndroidRuntimeException e) {
listener.onFailure(new HCaptchaException(HCaptchaError.ERROR));
diff --git a/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaDialogFragment.java b/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaDialogFragment.java
index a9e137c6..18f8b518 100644
--- a/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaDialogFragment.java
+++ b/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaDialogFragment.java
@@ -239,8 +239,8 @@ public void onSuccess(final String token) {
}
@Override
- public void startVerification(@NonNull FragmentActivity fragmentActivity) {
- final FragmentManager fragmentManager = fragmentActivity.getSupportFragmentManager();
+ public void startVerification(@NonNull Activity fragmentActivity) {
+ final FragmentManager fragmentManager = ((FragmentActivity) fragmentActivity).getSupportFragmentManager();
final Fragment oldFragment = fragmentManager.findFragmentByTag(HCaptchaDialogFragment.TAG);
if (oldFragment != null && oldFragment.isAdded()) {
HCaptchaLog.w("DialogFragment was already added.");
diff --git a/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaHeadlessWebView.java b/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaHeadlessWebView.java
index 98440458..4302754e 100644
--- a/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaHeadlessWebView.java
+++ b/sdk/src/main/java/com/hcaptcha/sdk/HCaptchaHeadlessWebView.java
@@ -1,11 +1,11 @@
package com.hcaptcha.sdk;
+import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
-import androidx.fragment.app.FragmentActivity;
import lombok.Getter;
import lombok.NonNull;
@@ -25,7 +25,7 @@ final class HCaptchaHeadlessWebView implements IHCaptchaVerifier {
private boolean shouldExecuteOnLoad;
private boolean shouldResetOnLoad;
- HCaptchaHeadlessWebView(@NonNull final FragmentActivity activity,
+ HCaptchaHeadlessWebView(@NonNull final Activity activity,
@NonNull final HCaptchaConfig config,
@NonNull final HCaptchaInternalConfig internalConfig,
@NonNull final HCaptchaStateListener listener) {
@@ -44,7 +44,7 @@ final class HCaptchaHeadlessWebView implements IHCaptchaVerifier {
}
@Override
- public void startVerification(@NonNull FragmentActivity activity) {
+ public void startVerification(@NonNull Activity activity) {
if (webViewLoaded) {
// Safe to execute
webViewHelper.resetAndExecute();
diff --git a/sdk/src/main/java/com/hcaptcha/sdk/IHCaptchaVerifier.java b/sdk/src/main/java/com/hcaptcha/sdk/IHCaptchaVerifier.java
index 6b046f50..4370ed38 100644
--- a/sdk/src/main/java/com/hcaptcha/sdk/IHCaptchaVerifier.java
+++ b/sdk/src/main/java/com/hcaptcha/sdk/IHCaptchaVerifier.java
@@ -1,6 +1,6 @@
package com.hcaptcha.sdk;
-import androidx.fragment.app.FragmentActivity;
+import android.app.Activity;
import com.hcaptcha.sdk.tasks.OnFailureListener;
import com.hcaptcha.sdk.tasks.OnLoadedListener;
@@ -17,7 +17,7 @@ interface IHCaptchaVerifier extends
/**
* Starts the human verification process.
*/
- void startVerification(@NonNull FragmentActivity activity);
+ void startVerification(@NonNull Activity activity);
/**
* Force stop verification and release resources.
diff --git a/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java
index 1754eb8d..6c182af2 100644
--- a/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java
+++ b/test/src/androidTest/java/com/hcaptcha/sdk/HCaptchaTest.java
@@ -5,11 +5,15 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.app.Activity;
+import android.os.Looper;
+
import androidx.test.core.app.ActivityScenario;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import com.hcaptcha.sdk.tasks.OnSuccessListener;
import com.hcaptcha.sdk.test.TestActivity;
+import com.hcaptcha.sdk.test.TestNonFragmentActivity;
import org.junit.Rule;
import org.junit.Test;
@@ -121,4 +125,15 @@ public void e2eWithDebugTokenHeadlessWebView() throws Exception {
assertTrue(latch.await(E2E_AWAIT_CALLBACK_MS, TimeUnit.MILLISECONDS));
}
+
+ @Test(expected = IllegalStateException.class)
+ public void badActivity() {
+ Looper.prepare();
+ final Activity activity = new TestNonFragmentActivity();
+
+ HCaptcha.getClient(activity)
+ .verifyWithHCaptcha(config.toBuilder().hideDialog(false).diagnosticLog(true).build())
+ .addOnSuccessListener(response -> fail("No token expected"))
+ .addOnFailureListener(e -> fail("Wrong failure reason: " + e.getHCaptchaError()));
+ }
}
diff --git a/test/src/main/AndroidManifest.xml b/test/src/main/AndroidManifest.xml
index d9151625..e6434d05 100644
--- a/test/src/main/AndroidManifest.xml
+++ b/test/src/main/AndroidManifest.xml
@@ -16,6 +16,15 @@
+
+
+
+
+
+
+
diff --git a/test/src/main/java/com/hcaptcha/sdk/test/TestNonFragmentActivity.java b/test/src/main/java/com/hcaptcha/sdk/test/TestNonFragmentActivity.java
new file mode 100644
index 00000000..44d596ee
--- /dev/null
+++ b/test/src/main/java/com/hcaptcha/sdk/test/TestNonFragmentActivity.java
@@ -0,0 +1,4 @@
+package com.hcaptcha.sdk.test;
+
+public class TestNonFragmentActivity extends android.app.Activity {
+}
\ No newline at end of file