Use C++ lib via Cordova (JNI)

Use C++ lib via Cordova (JNI)

  

Hello,

For an customer whe are developing an OutSystems Mobile App. We need to create an Cordova plugin where we can call native functions.

We are trying to run an SO lib on an Android phone via an Cordova pulgin and the Java Native Interface (JNI) The Toasty sample works fine but if we introduce our LIB we can not call the function.

Has anyone ever done this and is there an example for it?


We are using an SO file that is made of the next C++ cpp

The SO file is placed in 

src\android\nl\xservices\plugins\libs\arm64-v8a and src\android\nl\xservices\plugins\libs\armeabi-v7a

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
nl_xservices_plugins_HelloCJni_hello(
        JNIEnv *env, jobject /* this */, jstring j_input) {

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

The JNI file in src\android\nl\xservices\plugins named  HelloCJni.java looks like:

package nl.xservices.plugins;

public class HelloCJni {

    // C-function interface
public static native String hello(String input);

    // load library
    static {
        System.loadLibrary("native-lib");
    }
}

The ToastyPlugin we have changed the hello call will NOT work the show call works so the Cordova plugin works.

The file looks like:

package nl.xservices.plugins;
// The native Toast API
import android.widget.Toast;
// Cordova-required packages
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class ToastyPlugin extends CordovaPlugin {
private static final String DURATION_LONG = "long";
@Override
public boolean execute(String action, JSONArray args,
        final CallbackContext callbackContext) {
// Verify that the user sent a 'show' action
//if (!action.equals("show")) {
//  callbackContext.error("\"" + action + "\" is not a recognized action.");
//  return false;
//}

try {
if (action.equals("hello")) {
JSONObject options = args.getJSONObject(0);
String input = options.getString("input");
String jniOutput = HelloCJni.hello(input);
//String jniOutput = input;
String output = "Android says: " + jniOutput;
callbackContext.success(output);
return true;
}
else if (action.equals("show")) {

String message;
String duration;
try {
JSONObject options = args.getJSONObject(0);
message = options.getString("message");
duration = options.getString("duration");
} catch (JSONException e) {
callbackContext.error("Error encountered: " + e.getMessage());
return false;
}
// Create the toast
Toast toast = Toast.makeText(cordova.getActivity(), message,
                             DURATION_LONG.equals(duration) ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
// Display toast
toast.show();
// Send a positive result to the callbackContext
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
callbackContext.sendPluginResult(pluginResult);
return true;
}
else {
callbackContext.error("\"" + action + "\" is not a recognized action.");
return false;
}
}
catch (Exception e) {
callbackContext.error("Error encountered (catch): " + e.getMessage());
return false;
}
}

}

We have added the complete Cordova ZIP file.

Can someone help use please,


Kind regards, Robert and Mark



Hi Robert,


Never did it but found your question interesting and did some search/reading.


This guy reports success on doing it:

https://stackoverflow.com/questions/35442243/accessing-c-code-in-apache-cordova-for-android


Taking a quick glance, he seems to have a header file for the C++ function while you do not have.

#include "CppLibrary.h"



Cheers,

Renato


Robert de Vries wrote:

Hello,

For an customer whe are developing an OutSystems Mobile App. We need to create an Cordova plugin where we can call native functions.

We are trying to run an SO lib on an Android phone via an Cordova pulgin and the Java Native Interface (JNI) The Toasty sample works fine but if we introduce our LIB we can not call the function.

Has anyone ever done this and is there an example for it?


We are using an SO file that is made of the next C++ cpp

The SO file is placed in 

src\android\nl\xservices\plugins\libs\arm64-v8a and src\android\nl\xservices\plugins\libs\armeabi-v7a

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
nl_xservices_plugins_HelloCJni_hello(
        JNIEnv *env, jobject /* this */, jstring j_input) {

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

The JNI file in src\android\nl\xservices\plugins named  HelloCJni.java looks like:

package nl.xservices.plugins;

public class HelloCJni {

    // C-function interface
public static native String hello(String input);

    // load library
    static {
        System.loadLibrary("native-lib");
    }
}

The ToastyPlugin we have changed the hello call will NOT work the show call works so the Cordova plugin works.

The file looks like:

package nl.xservices.plugins;
// The native Toast API
import android.widget.Toast;
// Cordova-required packages
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class ToastyPlugin extends CordovaPlugin {
private static final String DURATION_LONG = "long";
@Override
public boolean execute(String action, JSONArray args,
        final CallbackContext callbackContext) {
// Verify that the user sent a 'show' action
//if (!action.equals("show")) {
//  callbackContext.error("\"" + action + "\" is not a recognized action.");
//  return false;
//}

try {
if (action.equals("hello")) {
JSONObject options = args.getJSONObject(0);
String input = options.getString("input");
String jniOutput = HelloCJni.hello(input);
//String jniOutput = input;
String output = "Android says: " + jniOutput;
callbackContext.success(output);
return true;
}
else if (action.equals("show")) {

String message;
String duration;
try {
JSONObject options = args.getJSONObject(0);
message = options.getString("message");
duration = options.getString("duration");
} catch (JSONException e) {
callbackContext.error("Error encountered: " + e.getMessage());
return false;
}
// Create the toast
Toast toast = Toast.makeText(cordova.getActivity(), message,
                             DURATION_LONG.equals(duration) ? Toast.LENGTH_LONG : Toast.LENGTH_SHORT);
// Display toast
toast.show();
// Send a positive result to the callbackContext
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK);
callbackContext.sendPluginResult(pluginResult);
return true;
}
else {
callbackContext.error("\"" + action + "\" is not a recognized action.");
return false;
}
}
catch (Exception e) {
callbackContext.error("Error encountered (catch): " + e.getMessage());
return false;
}
}

}

We have added the complete Cordova ZIP file.

Can someone help use please,


Kind regards, Robert and Mark





We have found the answer. The problem was the namespace in the C++ did not map exactly.

The solution was adding Java_ before the function.

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring JNICALL
Java_nl_xservices_plugins_HelloCJni_hello(
        JNIEnv *env, jobject /* this */, jstring j_input) {

    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

If someone has to deal with this kind off problems use de adb logcat. When we used this we could pinpoint the problem.

The two links we used to install adb and use the logcat function

https://www.xda-developers.com/install-adb-windows-macos-linux/

https://developer.android.com/studio/command-line/logcat

Maybee this is some help for others

With kind regards Robert and Mark.