AS下JNI编程实例并生成so库 - 网络参考版

最近需要使用JNI编程,学了下JNI,并且在Android Studio下实现了一个小demo。这期间有一些坑,还好都解决了,想分享出来,希望大家少走弯路。本文中采用的平台是Windows,NDK环境已经搭建好,这方面资料很多,大家可以自行百度。

参考文档:https://www.cnblogs.com/jymblog/p/5526865.html

本文分为两个部分:

1.如何通过编写Jni实现native方法的调用。

2.怎样生成.so动态库提供给第三方使用。

以下是正文:

一.编写jni文件,实现本地方法

1. 建立一个新工程,只有一个MainActivity,里面加载库文件并且声明和调用若干本地方法,然后build-makeProject生成MainActivity对应的.class文件。

publicclassMainActivityextendsActivity {

private final String TAG = "JNITEST"

@Override

protectedvoid onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);

        String s=returnString();

        Log.d(TAG,s);

        inta=1000;        Log.d(TAG,sayhello(a));    }

//加载jni

static {

        System.loadLibrary("nativeTest");    }

//声明native方法

privatenativeintsayhello(int t);

    privatenative String returnString();

}

2. 生成.h头文件,该文件即连接java和c(c++)的桥梁,里面有Android工程里本地方法的声明。这个文件可以在控制台用javah命令自动生成。注意,这里可能会碰到问题,比如我第一次就出现了找不到app.activity ,即找不到类文件,这种问题一般是没有理解javah的用法造成的。可以采用以下两种方法:

方法1:   cd到       E:\shijue\JniHello\app\src\main

然后输入      javah -d jni -classpath I:\Andriod\AndroidSDK\platforms\android-15\android.jar;

E:\shijue\JniHello\app\build\intermediates\classes\debug com.example.machenike_pc.jnihello.MainActivity

说明:javah是生成头文件的命令,深绿色为生成文件夹jni,紫红色为android.jar所在的位置,浅绿色为class文件的路径+类全名(路径最后一个文件夹是debug之后空格+类全名)

(这里补充下-classpath的含义:javah操作是针对类文件,-bootclasspath和-classpath就是指定在哪里进行类文件搜索。JDK搜索类文件先后顺序如下:Bootstrap classes,User classes。Bootstrap默认的是JDK自带的jar或zip文件,它包括jre\lib下rt.jar等文件,JDK首先搜索这些文件.可以通过-bootclasspath来设置它。文件之间用分号";"进行分割。User classes搜索顺序为当前目录、环境变量CLASSPATH、-classpath。它们用于告知JDK搜索类文件根目录名、jar文档名、zip文档名,用分号";"进行分隔。)

方法2:   cd到E:\shijue\JniHello\app\build\intermediates\classes\debug目录下,直接javah -d jni com.example.machnike_pc.jnihello.MainActivity 即可

3. 在生成的jni目录下写一个c或者c++文件,文件名随意,实现本地方法 ,之后需要在该路径下再加一个空的cpp或c文件(估计是软件的bug,不加的话很可能出ndk错误),比如我加了个util.cpp的文件,里面什么都不写。

 下面是我的c++文件代码

#include#include#include#ifdef __cplusplus

extern "C" {

#endif

JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello

  (JNIEnv *, jobject, jint);

JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString

  (JNIEnv *, jobject);

#ifdef __cplusplus

}

#endif

JNIEXPORT jint JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_sayhello

    (JNIEnv * env, jobject jobj, jint jnumber)

    {

        intmodify=jnumber+1;

        return modify;

    }

JNIEXPORT jstring JNICALL Java_com_example_machenike_1pc_jnitest2_MainActivity_returnString

    (JNIEnv *env, jobject jobj)

    {

      returnenv->NewStringUTF("I'm comes from to Native Function!");

}

4,如果ndk版本不是最新的,需要在gradle.properties文件下加入:

android.useDeprecatedNdk=true  


5,配置ndk路径,这里也可以在AS的设置里面配置。我采用的方法是在local.properties文件最后一行加入:

ndk.dir=I\:\\Andriod\\NDK\\android-ndk-r10b


6,build.gradle(app下):文件下加入:(defaultconfig里面)

ndk{

moduleName "nativeTest"

}

此时运行程序已经可以实现本地方法了,之后可以再生成so库文件,方便使用。


二,生成.so动态库

(这里说一下,貌似Android studio已经写好了.mk文件,上面的步骤完成后,直接rebuild一下就自动生成为了.so动态库,下面的方法也能生成,可以看一下,很有用)

1,在jni文件夹下新建Android.mk文件,写入以下内容:

LOCAL_PATH := $(call my-dir)          //固定写法,把路径赋给LOCAL_PATH变量

include $(CLEAR_VARS)                  //清除其他LOCAL变量

LOCAL_MODULE := nativeTest            //这个模块的名字,最后生成的.so的名字就是它,要跟java里面的loadLibray的名字一样。

LOCAL_SRC_FILES := nativeTest.cpp\    //这里是要编译的文件,\ 符号是换行

            util.cpp

include $(BUILD_SHARED_LIBRARY)        //SHARED_LIBRARY就是动态库,即.so文件

 这里的写法是最简单的一个例子,用的时候把注释去掉。每一行都是很关键,不能省略。至于makefile怎么编写内容比较多,此处不赘述。

2,在工程根目录下新建application.make文件,写入以下内容:

APP_PROJECT_PATH := $(call my-dir)

APP_MODULES := nativeTest

3,在命令行下,cd到jni目录(就是之前javah -d jni生成的那个文件夹)下,输入指令: ndk-build,等一会即可生成.so文件。位于lib目录下,将其放到app/src/main/jniLibs目录下就能用了。


FAQ:

1,生成的so文件在使用时需要注意:包名不能变,拿上文举例,本地方法位于com_example_machenike_pc_jnitest2_MainActivity这个类下,如果在别的地方用,需要完整的建立这个包名和类。

2,c和cpp文件均可以用来写jni,写法上略有不同。

3,需要注意java里面成员方法和静态方法通过javah生成的头文件略有不同,一个参数是jclass,另一个是jobject。

4,不用javah生成头文件也行,推荐第一次写的时候用javah生成,后面修改的时候(比如参数改变)可以直接在c文件里手动修改。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容