JNI入门学习笔记

最近因公司业务需要,将一部分逻辑代码从java移入JNI中。本着现学现用的精神,终于在deadline前完成交付。现记下此文作为我学习JNI过程中的点滴。

废话不多说,直接开干

##搭建环境

我用的开发工具是MAC,AS。关于安装NDK网上有很多方法,我用的是最懒的方法,如图 这里写图片描述

因为我这已经下载好了NDK,所以没有显示。 未下载NDK时会提示,是否下载,我是直接点击 load ndk让AS帮我下载好的。

友情提示:

此法下载需要科学上网

##编写java文件 我新建了两个java文件,JNIFragment用于调用底层方法并显示处理结果,JNICalc 声明了一个简单的计算方法。 JNIFragment.java ``` public class JNIFragment extends BaseFragment { @Override public String getTAG() { return JNIFragment.class.getSimpleName(); }

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    LinearLayout linearLayout = new LinearLayout(getActivity());
    linearLayout.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
    linearLayout.setOrientation(LinearLayout.VERTICAL);

    Button button = new Button(getActivity());
    button.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
    button.setText("32+44=?");
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            LogDetails.i(JNICalc.calc(32,44));
            showToastShort(JNICalc.calc(32,44)+"");
        }
    });
    linearLayout.addView(button);

    return linearLayout;
} } ```  JNICalc.java
public class JNICalc {
    public static native int calc(int a,int b);
    static {
        System.loadLibrary("jniDemo"); // 标记1
    }
}

##生成.h文件

依次点击 Build->clean project->rebuild project运行结束后, 找到class文件所在路径app/build/intermediates/classes/tt/blue/com/bruce/demo/studydata/fragments/jnidemo/JNICalc.class

打开终端输入命令 javah -jni 包名JNICalc 如果包名不正确就会报错

Exception in thread "main" java.lang.IllegalArgumentException: Not a valid class name

或者 > <p align='left'>error occurred during initialization of VM java.lang.Error: Properties init: Could not determine current working directory. at java.lang.System.initProperties(Native Method) at java.lang.System.initializeSystemClass(System.java:1163)</p>

或者 > <p align='left'>javah -jni com.bruce.demo.studydata.fragments.jnidemo.JNICalc 错误: 找不到 com.bruce.demo.studydata.fragments.jnidemo.JNICalc 的类文件。</p>

对于我的demo中的正确的输入方法如下 进入JNICalc.class文件所在路径的根目录 cd app/build/intermediates/classes/tt/blue/

编译生成.h文件,文件路径app/build/intermediates/classes/tt/blue/

javah -jni com.bruce.demo.studydata.fragments.jnidemo.JNICalc

编写native文件

在main目录下新建jni文件夹,并将上面生成的.h文件copy到这个文件夹下,新建 cppcalc.cpp文件 #include <com_bruce_demo_studydata_fragments_jnidemo_JNICalc.h> JNIEXPORT jint JNICALL Java_com_bruce_demo_studydata_fragments_jnidemo_JNICalc_calc (JNIEnv *, jclass, jint a, jint b){ return a+b; }

编写.mk

编写Android.mk文件 ``` LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE := jniDemo
LOCAL_SRC_FILES := cppcalc.cpp

include $(BUILD_SHARED_LIBRARY) ``` 这里需要注意的地方有两处: >LOCAL_MODULE 填写的jniDemo必须与 标记1相同 >LOCAL_SRC_FILES 填写的 cppcalc.cpp就是上面的cpp文件名称必须 一 一对应

生成.so

输入 ndk-build 生成.so 这里也要注意 可能输入完这条命令会出现以下错误 >

  1. Android NDK: Could not find application project directory ! Android NDK: Please define the NDK_PROJECT_PATH variable to point to it. /Users/XXX/Library/Android/sdk/ndk-bundle/build/core/build-local.mk:151: Android NDK: Aborting . Stop.

  2. Android NDK: Your APP_BUILD_SCRIPT points to an unknown file: app/src/jni/Android.mk/jni/Android.mk /Users/XXX/Library/Android/sdk/ndk-bundle/build/core/add-application.mk:198: *** Android NDK: Aborting... . Stop.

解决办法是进入到当前工程所在目录,build时指明源文件所在路径的父路径 ``` cd asstudydemo

ndk-build NDK_PROJECT_PATH=app/src/main/ ``` 这样就生成了若干个.so包

在工程上使用.so

生成的.so包考入main包下的jniLibs中或者lib中都可以,打包安装,测试。 此过程中可能会出现

NDK integration is deprecated in the current plugin. Consider trying the new experimental plugin.For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental. Set "Android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

的错误,则需要修改 gradle.properties文件增加 android.useDeprecatedNdk=true 即可

demo 参考资料: NDK integration is deprecated解决方法 https://developer.android.com/ndk/guides/android_mk.html

Written on December 1, 2016