Jump to content
Drummer1972

Accessing a Java class from my application...

Recommended Posts

Posted (edited)

hello. 
I have been trying for three weeks to get my app to access a simple java class I have created and I always get the same error when executing the line 'Error: Java class not found: com/my/MySimpleClass'.

    const char* jclassName = com/embarcadero/MySimpleClass”;

    jClass = env->FindClass(jclassName);

MySimpleClass.java is :

 

package com.embarcadero;

 import android.util.Log;

 public class MySimpleClass {

 

    public void loadLibrary(String jarPath) {

        try {

                 Log.d("MySimpleClass", "Load JAR : " + jarPath);

             }  catch (Exception e) {

               Log.e("MySimpleClass", "loading error JAR: " + e.getMessage());

           }

      }

    public void sayHello()

     {

        Log.d("MySimpleClass", "¡Hello from the Java class!");

    }

}

The code that I use from my small app (it only consists of one Form) is

#ifndef MenuH
#define MenuH
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <FMX.Controls.hpp>
#include <FMX.Forms.hpp>
#include <FMX.StdCtrls.hpp>
#include <Androidapi.JNI.hpp>           // Importante para JNI
#include <Androidapi.JNI.JavaTypes.hpp> // Importante para JNI
#include <System.Rtti.hpp>
#include <FMX.Objects.hpp>
#include <FMX.Types.hpp>


class TFMenu : public TForm
{
__published:    // IDE-managed Components
    TText *Text1;
private:    // User declarations

    jclass jClass;
    jobject jObject;
    jmethodID methodId;

public:        // User declarations
    __fastcall TFMenu(TComponent* Owner);
    __fastcall ~TFMenu();  //Destructor

};

#include <fmx.h>
#pragma hdrstop

#include "Menu.h"
#include <Androidapi.Helpers.hpp> // Para usar JNI
#include <System.SysUtils.hpp> // Para la función Try
#include <Androidapi.JNIBridge.hpp>

#pragma package(smart_init)
#pragma resource "*.fmx"

TFMenu *FMenu;

__fastcall TFMenu::TFMenu(TComponent* Owner)
    : TForm(Owner), jClass(nullptr), jObject(nullptr), methodId(nullptr) // Inicializar los punteros
{
    JNIEnv* env = TJNIResolver::GetJNIEnv();

    const char* jclassName = "com/embarcadero/MySimpleClass";

    try {
        jClass = env->FindClass(jclassName);

        if (jClass == nullptr) {
            throw Exception("Error: Clase Java no encontrada: " + String(jclassName));
        }

        jClass = (jclass)env->NewGlobalRef(jClass); 

        jmethodID constructor = env->GetMethodID(jClass, "<init>", "()V");

        if (constructor == nullptr) {
            throw Exception("Error: Constructor Java no encontrado");
        }

        jObject = env->NewObject(jClass, constructor);

        if (jObject == nullptr) {
            throw Exception("Error: No se pudo crear la instancia de la clase Java");
        }

        jObject = env->NewGlobalRef(jObject); // **¡IMPORTANTE: Referencia Global!**

        methodId = env->GetMethodID(jClass, "savHello", "()V");

        if (methodId == nullptr) {
            throw Exception("Error: Método Java no encontrado");
        }

        env->CallVoidMethod(jObject, methodId);


    } catch (const Exception& e) {
        ShowMessage(e.Message);
        if (jClass) {
            env->DeleteGlobalRef(jClass);
            jClass = nullptr;
        }
        if (jObject) {
            env->DeleteGlobalRef(jObject);
            jObject = nullptr;
        }
        methodId = nullptr;  
    }
}


__fastcall TFMenu::~TFMenu() {
    JNIEnv* env = TJNIResolver::GetJNIEnv();
    if (jClass) {
        env->DeleteGlobalRef(jClass);
    }
    if (jObject) {
        env->DeleteGlobalRef(jObject);
    }
}

I created the MySimpleClass.jar file and  included  in MyProyect/Java/ and  it in my remote path (deployment) “.\library”.

 

My configuration is C++BUILDER 11.1, Android Platform 32 bits, java 1.8, sdk 25, ndk 22;

 

Please, I am very frustrated. Can anyone help me? thank.

Edited by Drummer1972

Share this post


Link to post
Posted (edited)

Why are you putting your Java class in an Embarcadero package?  You should be creating your own package.

 

How does your C++ project refer to your MySimpleClass.jar file? Did you use the Project Manager, or a manual classes.dex file?

 

Have you considered creating a JNI Bridge to your class, instead of manually using JNI methods directly?

 

Using a Custom Set of Java Libraries In Your RAD Studio Android Apps

Creating and Deploying a classes.dex File Manually

Adding A Java Library to Your Application Using the Project Manager

 

Something else to keep in mind (not sure if this applies here):

 

https://stackoverflow.com/a/20843365/65863

Quote

The FindClass method should be called from Java thread only. FindClass's implementation is looking for a ClassLoader by traversing the current call-stack. Since you are trying to call the FindClass from a native thread, there is no ClassLoader to look for. Take a look at this JNI FAQ

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×