Reputation: 1
I'm building a simple Android app in Qt Creator 5.4 using JNI to make calls in C++ to Android's bluetooth APIs. I've spent hours looking over JNI tutorials and I can't for the life of me get this really simple class to work. Every time I run my app, it crashes immediately with the following console output:
JNI_OnLoad(JavaVM*, void*)): Can't find getDefaultAdapter
D/AndroidRuntime(15795): Shutting down VM
E/AndroidRuntime(15795): FATAL EXCEPTION: main
E/AndroidRuntime(15795): Process: org.qtproject.example.HostSim, PID: 15795
E/AndroidRuntime(15795): java.lang.UnsatisfiedLinkError: JNI_ERR returned from JNI_OnLoad in "/data/app/org.qtproject.example.HostSim-1/lib/arm/libHostSim.so"
E/AndroidRuntime(15795): at java.lang.Runtime.loadLibrary(Runtime.java:371)
E/AndroidRuntime(15795): at java.lang.System.loadLibrary(System.java:989)
E/AndroidRuntime(15795): at org.qtproject.qt5.android.bindings.QtActivity.loadApplication(QtActivity.java:252)
E/AndroidRuntime(15795): at org.qtproject.qt5.android.bindings.QtActivity.startApp(QtActivity.java:655)
E/AndroidRuntime(15795): at org.qtproject.qt5.android.bindings.QtActivity.onCreate(QtActivity.java:895)
E/AndroidRuntime(15795): at android.app.Activity.performCreate(Activity.java:5933)
E/AndroidRuntime(15795): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
E/AndroidRuntime(15795): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
E/AndroidRuntime(15795): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
E/AndroidRuntime(15795): at android.app.ActivityThread.access$800(ActivityThread.java:144)
E/AndroidRuntime(15795): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
E/AndroidRuntime(15795): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(15795): at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime(15795): at android.app.ActivityThread.main(ActivityThread.java:5221)
E/AndroidRuntime(15795): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime(15795): at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime(15795): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
E/AndroidRuntime(15795): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
I/Process (15795): Sending signal. PID: 15795 SIG: 9
Right now I have a class called androidBluetoothService.cpp and I'm just trying to create the BluetoothAdapter object using getDefaultAdapter(). I've already added android.permission.BLUETOOTH and android.permission.BLUETOOTH_ADMIN in my manifest file. Below is my code:
#include <Qdebug>
#include "androidBluetoothService.h"
// JNI properties
static JavaVM* jvm = 0;
static jclass bluetoothAdapterClassID = 0;
static jmethodID getDefaultAdapterMethodID=0;
//File path for Java classes
const char *bluetoothAdapterClassPath = "android/bluetooth/BluetoothAdapter";
// AndroidBluetoothService Constructor
androidBluetoothService::androidBluetoothService()
{
JNIEnv* env;
// Qt is running in a different thread than android UI, so you always Java VM *MUST* be attached to current thread
if (jvm->AttachCurrentThread(&env, NULL)<0)
{
qCritical()<<"AttachCurrentThread failed";
return;
}
// Start bluetoothAdapter with BluetoothAdapter.getDefaultAdapter()
bluetoothAdapter = env->CallStaticObjectMethod(bluetoothAdapterClassID,getDefaultAdapterMethodID);
if (!bluetoothAdapter)
{ qCritical()<<"Can't getDefaultAdapter";
return;}
else {
qDebug() << "Bluetooth ready";
}
jvm->DetachCurrentThread();
}
// this method is called immediately after the module is load
JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{
JNIEnv* env;
if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
qCritical()<<"Can't get the enviroument";
return JNI_ERR;}
else{
qDebug() << "JRE ready"; }
jvm = vm;
// search for our class
jclass clazz=env->FindClass(bluetoothAdapterClassPath);
if (!clazz)
{ qCritical()<<"Can't find BluetoothAdapter class";
return JNI_ERR;}
else{ qDebug() << "BluetoothAdapter class found";}
// keep a global reference to it
bluetoothAdapterClassID = (jclass)env->NewGlobalRef(clazz);
//FIXME: Still causes fatal exception
// search for getDefaultAdapter
getDefaultAdapterMethodID = env->GetStaticMethodID(bluetoothAdapterClassID, "getDefaultAdapter", "()Landroid/bluetooth/BluetoothAdapter"); //This is where exception occurs
if (!getDefaultAdapterMethodID) {
qCritical()<<"Can't find getDefaultAdapter";
return JNI_ERR; }
qDebug()<<"Method registering finished";
return JNI_VERSION_1_6;
}
I understand that the Unsatisfied link error means JNI can't find the method but I've checked the signature and name multiple times and have found identical calls on other people's code and it works for them. Please advise.
I'm using Android SDK 21 and Qt Creator 5.4
Upvotes: 0
Views: 731
Reputation: 58497
The signature you're specifying for getDefaultAdapter
is incorrect. When you specify a class name starting with L
you should end it with a semicolon, as in:
"()Landroid/bluetooth/BluetoothAdapter;"
Upvotes: 2