Search code examples
objective-cmacosjava-native-interface

JNI header missing in Objective-C


I have a file.c in my project which has #include <jni.h> header file. What is the process to include this header file in project or macOS?


Solution

  • Let's say you have following code

    #include "jni.h"
    #import <Foundation/Foundation.h>
    
    int main(int argc, const char * argv[]) {
        @autoreleasepool {
            JNIEnv *env;
            JavaVM *jvm;
            JavaVMInitArgs vm_args;
            JavaVMOption options[3];
    
            options[0].optionString = "-Djava.class.path=_HERE_GOES_LOCATION_OF_JNICOOKBOK_/jnicookbook/recipeNo051/target";
    
            vm_args.options = options;
            vm_args.ignoreUnrecognized = 0;
            vm_args.version = JNI_VERSION_1_8;
            vm_args.nOptions = 1;           
    
            int status = JNI_CreateJavaVM (&jvm, (void **) &env, &vm_args);
            if (status < 0 || !env) {
              printf ("Error - JVM creation failed\n");
              return 1;
            }
    
            jclass cls_Main = (*env)->FindClass (env, "recipeNo051/Main");
    
            jmethodID method_displayMessage = (*env)->GetStaticMethodID (env, cls_Main, "displayMessage", "()V");
            (*env)->CallStaticVoidMethod(env, cls_Main, method_displayMessage);
    
            (*jvm)->DestroyJavaVM( jvm );
        }
    
        return 0;
    }
    

    in order to run it you will need

    • location of libjvm.dylib
    • location of headers
    • location of compiled Java classes that are called from main.m

    Let's start with libs and headers. You have to make sure that following paths are searched for includes (note that I am using jdk-11.0.4):

    /Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include
    /Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/include/darwin/
    

    You have to make sure that following path is added to Library Search Path and to Runpath Search Paths

    /Library/Java/JavaVirtualMachines/jdk-11.0.4.jdk/Contents/Home/lib/server
    

    You should have settings like that:

    enter image description here

    Make sure you are linking your code with libjvm.dylib. Add it inside Build Phases

    enter image description here

    where you can specify it's location by choosing Add Other...

    enter image description here

    Run your code, but! Make sure to ignore SIGSEGV before calling method JNI_CreateJavaVM. You can ignore it inside lldb console

    (lldb) process handle --pass true --stop false SIGSEGV
    

    enter image description here

    After you continue, you can see your JVM instance calling classes from the recipeNo051.

    enter image description here

    Source code of class: recipeNo051/Main can be found here: https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo051

    Update