JNI 全称为 Java Native Interface,它提供了实现Java与其他语言通信的API。注意,JNI可能会导致丧失平台可移植性。下面是调用JNI的步骤。
构建Java类
public class Main {
    static {
        System.load("/Users/YI/Documents/Worksplace/SICILY/Products/KeyboardService.jnilib");
    }
    public native ArrayList<String> search(String key);
    public static void main(String[] args)
    {
        ArrayList<String> results = new Main().search("keyi");
        for(String s : results){
            System.out.println(s);
        }
    }
}
System.load的参数是后面编译生成后的jnilib库的目录。
search方法就是需要使用C++语言实现的方法定义。
编译Java类
javac Main.java
javah -jni Main
编译完成后,在目录下将生成Main.h文件
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class Main */
#ifndef _Included_Main
#define _Included_Main
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     Main
 * Method:    search
 * Signature: (Ljava/lang/String;)Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_Main_search
  (JNIEnv *, jobject, jstring);
#ifdef __cplusplus
}
#endif
#endif
可见,Java_Main_search即是我们要实现的方法。
构建C++工程

注意,在Mac系统下,会找不到JNI文件,需要先找出JDK所在的目录,命令:
/usr/libexec/java_home -V
可以看到JDK的目录为:
到该目录的include文件夹中,将jni.h和darwin文件夹中的jawt_md.h、jni_md.h共三个文件拷贝到工程中。
此时,Main.h会报错,修改一下即可。
#include <jni.h> 改成 #include "jni.h"
实现Java_Main_search方法
JNIEXPORT jobject JNICALL Java_Main_search(JNIEnv *env, jobject obj, jstring str)
{
    init();
    search(jstring2String(env, str));
    jclass clazz = env->FindClass("java/util/ArrayList");
    jobject list = env->NewObject(clazz, env->GetMethodID(clazz, "<init>", "()V"));
    for (int i = 0; i < results.size(); ++i)
    {
        jstring tmpStr = env->NewStringUTF(results[i].c_str());
        env->CallObjectMethod(list, env->GetMethodID(clazz,"add","(Ljava/lang/Object;)Z"), tmpStr);
    }
    return list;
}
其中,JNI的对象构造和字符串转换参考:Java-JNI对象构造和字符串转换。
编写自动编译脚本
在Xcode > Target > BuildPhases面板中,增加Run Script一项。

并在RunSctipt中输入以下脚本:
INSTALL_DIR=${SRCROOT}/Products/
if [ -d "${INSTALL_DIR}" ]
    then
rm -rf "${INSTALL_DIR}"
fi
mkdir -p "${INSTALL_DIR}"
cd "${INSTALL_DIR}"
g++ -o KeyboardService.o -c ${SRCROOT}/SICILY/    KeyboardService.cpp
g++ -dynamiclib -o KeyboardService.jnilib     KeyboardService.o /Applications/Xcode.app/Contents/    Developer/Platforms/MacOSX.platform/Developer/SDKs/    MacOSX10.11.sdk/usr/lib/libsqlite3.tbd 
open "${INSTALL_DIR}"
脚本先在项目下新建Products目录,将生成后的dynamiclib库放到目录中,并打开该目录。(由于项目中用到了sqlite库,所以将该库一同压到dynamiclib包中。)
运行
修改1中的dynamiclib库的路径,并运行,可看到结果。

如果运行时,出现以下异常:
Exception in thread "main"             
java.lang.UnsatisfiedLinkError: no HelloWorld in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1758)
at java.lang.Runtime.loadLibrary0(Runtime.java:823)
at java.lang.System.loadLibrary(System.java:1045)
at HelloWorld.(HelloWorld.java:7)
则是dynamiclib库的路径不正确。