Problem with getting Google reCaptcha Android to work in Unity

Hi guys! I’m trying to get this thing to work and my lack of knowledge of building Android plugin doesn’t help it ether. So here is situation:

  • I followed some tutorial of implementing Google reCaptcha for Android Studio and app itself works.
  • Next I build .jar from Android Studio and placed it inside Unity’s Plugin/Android.
  • I also placed play-services-safetynet-17.0.0.aar file inside Unity’s Plugin/Android and I also placed butterknife-10.0.0.aar and volley-1.1.0.aar even though I dont think its needed.

Now the problem is that Im getting this error in Logcat when I call validateCaptcha():

E/Unity: AndroidJavaException: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/android/gms/common/api/Api$ClientKey;

Here are the codes:

package com.example.recaptchaunity;

import android.os.Bundle;
import androidx.appcompat.widget.Toolbar;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.safetynet.SafetyNet;
import com.google.android.gms.safetynet.SafetyNetApi;
import com.google.android.gms.tasks.OnFailureListener;
import com.google.android.gms.tasks.OnSuccessListener;
import com.unity3d.player.UnityPlayerActivity;
import com.unity3d.player.UnityPlayer;

import com.unity3d.player.UnityPlayerNativeActivity;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class pluginCaptcha extends UnityPlayerActivity {

    private static final String TAG = pluginCaptcha.class.getSimpleName();

    // TODO - replace the SITE KEY with yours
    private static final String SAFETY_NET_API_SITE_KEY = "I inserted the right key";

    // TODO - replace the SERVER URL with yours

    private static final String URL_VERIFY_ON_SERVER = "I inserted the right url";
  //  @BindView(R.id.input_feedback)
    EditText inputFeedback;

   // @BindView(R.id.layout_feedback_form)
    LinearLayout layoutFeedbackForm;

  //  @BindView(R.id.message_feedback_done)
    TextView messageFeedbackDone;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

    //    Toolbar toolbar = findViewById(R.id.toolbar);
      //  setSupportActionBar(toolbar);
     //   getSupportActionBar().setTitle(getString(R.string.feedback));
     //   getSupportActionBar().setDisplayHomeAsUpEnabled(true);

     //   Toast.makeText(getApplicationContext(), "Always check Android Studio `LogCat` for errors!", Toast.LENGTH_LONG).show();
    }

  //  @OnClick(R.id.btn_send)
    public void validateCaptcha() {

               // Showing reCAPTCHA dialog
        SafetyNet.getClient(this).verifyWithRecaptcha(SAFETY_NET_API_SITE_KEY)
                .addOnSuccessListener(this, new OnSuccessListener<SafetyNetApi.RecaptchaTokenResponse>() {
                    @Override
                    public void onSuccess(SafetyNetApi.RecaptchaTokenResponse response) {
                        Log.d(TAG, "onSuccess");

                        if (!response.getTokenResult().isEmpty()) {

                            // Received captcha token
                            // This token still needs to be validated on the server
                            // using the SECRET key
                            verifyTokenOnServer(response.getTokenResult());
                        }
                    }
                })
                .addOnFailureListener(this, new OnFailureListener() {
                    @Override
                    public void onFailure(@NonNull Exception e) {
                        if (e instanceof ApiException) {
                            ApiException apiException = (ApiException) e;
                            Log.d(TAG, "Error message: " +
                                    CommonStatusCodes.getStatusCodeString(apiException.getStatusCode()));
                        } else {
                            Log.d(TAG, "Unknown type of error: " + e.getMessage());
                        }
                    }
                });
    }

    /**
     * Verifying the captcha token on the server
     * Post param: recaptcha-response
     * Server makes call to https://www.google.com/recaptcha/api/siteverify
     * with SECRET Key and Captcha token
     */
    public void verifyTokenOnServer(final String token) {
        Log.d(TAG, "Captcha Token" + token);

        StringRequest strReq = new StringRequest(Request.Method.POST,
                URL_VERIFY_ON_SERVER, new Response.Listener<String>() {

            @Override
            public void onResponse(String response) {
                Log.d(TAG, response.toString());

                try {
                    JSONObject jsonObject = new JSONObject(response);
                    boolean success = jsonObject.getBoolean("success");
                    String message = jsonObject.getString("message");

                    if (success) {
                        // Congrats! captcha verified successfully on server
                        // TODO - submit the feedback to your server

                        layoutFeedbackForm.setVisibility(View.GONE);
                        messageFeedbackDone.setVisibility(View.VISIBLE);
                    } else {
                        Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
                    }
                } catch (JSONException e) {
                    e.printStackTrace();
                    Toast.makeText(getApplicationContext(), "Json Error: " + e.getMessage(), Toast.LENGTH_LONG).show();
                }

            }
        }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Log.e(TAG, "Error: " + error.getMessage());
            }
        }) {
            @Override
            protected Map<String, String> getParams() {
                Map<String, String> params = new HashMap<>();
                params.put("recaptcha-response", token);

                return params;
            }
        };

        MyApplication.getInstance().addToRequestQueue(strReq);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PluginWrapper : MonoBehaviour
{

    private AndroidJavaObject javaClass;


    AndroidJavaObject javaObject;
    AndroidJavaClass unityClass;
    AndroidJavaObject unityActivity;

    // Start is called before the first frame update
    void Start()
    {
        javaClass = new AndroidJavaObject("com.example.recaptchaunity.MyApplication");
        javaClass.Call("ShowDebug");



    }
   
    public void Captcha()
    {
        //   javaClass = new AndroidJavaObject("com.example.recaptchaunity.MainActivity");
        // javaClass.Call("validateCaptcha");
        javaObject = new AndroidJavaObject("com.example.recaptchaunity.pluginCaptcha");
      //  unityClass = new AndroidJavaClass("com.unity3d.player.UnityPlayer");
    //    unityActivity = unityClass.GetStatic<AndroidJavaObject>("currentActivity");
        javaObject.Call("validateCaptcha");



    }


}

As you can see from my commented lines I’ve trying different ways to call plugin’s function, at the end I managed by creating new class “pluginCaptcha” and copied things from MainActivity class :smile:

I’ve been trying fro days to get this thing to work, in meantime I made a progress but I gor stuck on this part, please help. Thanks in advance!

UPDATE:
I found “solution”. I just exported my Unity Project inside Android Studio, not the best “solution” but it works at least.:smile: