Android NDK——使用Android Studio引用so库,jar包及module并使用JNI的正确姿势

转载于 http://blog.csdn.net/crazymo_/article/details/52815140

引言

由于项目中需要用到JNI,以前虽然在Eclipse上使用过JNI和SO 文件,移植到Android Studio上的时候是花费好些力气的,也处理过不少常见的错误,而且网上很多文章都是只写了大致的步骤,忽略了很多细节,为了让新手们少走弯路,同时也是加强自己的理解,把自己一步一步的操作记录下来。

一、Android studio引入jar

不同于eclipse的配置build path,Android Studio可以通过图形界面Project Structure来配置dependencies还可以通过gradle.build脚本来配置

1、先把对应jar包copy到libs或者jniLibs下再”Add As Library”(个人推荐)

  • 将jar文件复制、粘贴到app的libs或者jniLibs目录中
  • 右键点击jar文件,并点击弹出菜单中的“Add As Library”,将jar文件作为类库添加到项目中
  • 选择指定的类库。(高能提醒:如果不执行后两步,jar文件将不起作用,当然不能使用import语句引用。)

2、先copy再通过gradle.build脚本配置

  • 将jar文件复制、粘贴到app的libs或者jniLibs目录中

  • 在app下的build.gradle脚本里配置dependencies 节点(与android节点同级)

<code class="hljs livecodeserver has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">dependencies {
    compile fileTree(<span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">include</span>: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.jar'</span>], dir: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'libs'</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">)//**主要是这两句</span>
    testCompile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'junit:junit:4.12'</span>
    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.android.support:appcompat-v7:24.0.0'</span>
    compile <span class="hljs-built_in" style="color: rgb(102, 0, 102); box-sizing: border-box;">files</span>(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'libs/konke-android-lib.jar'</span><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">)//**编译konke-android-lib.jar</span>
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li></ul>

3、通过Android Studio的图形界面

Open module setting——>Project Structure——>选中对应的module——>Dependencies——>”+“——>选择对应的jar包执行完毕之后会被添加到libs文件夹下(即Project模式下的libs) 
这里写图片描述

二、Android Studio依赖module

如图module app 依赖于zklibs: 
这里写图片描述

1、通过Android Studio的图形界面

Open module setting——>Project Structure——>选中对应的module——>Dependencies——>”+“——>选择对应的jar包

2、通过gradle.build脚本配置

<code class="hljs rust has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//app的gradle</span>
dependencies {
    compile fileTree(include: [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'*.jar'</span>], <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">dir</span>: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'libs'</span>)
    testCompile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'junit:junit:4.12'</span>
    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.android.support:appcompat-v7:24.0.0'</span>

    compile <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'com.google.code.gson:gson:2.7'</span>

    compile project(path: <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">':zklibs'</span>)<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//主要是这一句</span>

}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li></ul>

三、Android Studio使用SO文件

前面一篇Android NDK——配置NDK及使用Android studio开发Hello JNI并简单打包SO介绍了so文件,它是unix的动态连接库,是二进制文件,其本质就是本地语言(c/c++)程序文件,作用相当于windows下的.dll文件。而在Android中调用动态库文件(*.so)都是通过jni的方式。 
这里写图片描述

1、引入so文件到项目中

我们都知道Android Studio的项目结构与在Eclipse里的区别巨大,切换为Project模式和Android模式,显示的结构都有所不同,这也导致很多初学者有点迷了,当然也包括我,走过不少弯路,Google、StackOverFlow走了很多遍,折腾了一番,最后终于成功了,只需两步骤。

  • 把Android Studio 里的项目且为Project类型的结构,在xxx/src/main的目录下下新建名为 ”jniLibs“ 文件夹(注意大小写,与Java文件夹同级)

  • 再将so文件复制、粘贴到“jniLibs”目录内。(其实jniLibs文件里不仅仅可以放置so文件、也可以放置jar包类型的库)不需要再额外去配置Gradle了

<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//当然还有另一种引入so,就是放到libs下,我不喜欢用这种方式。。。</span>
<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**如果使用jniLibs文件夹导入so文件,不需要在gradle中配置了;如果将so文件添加在module的libs文件夹下,则需要在module的gradle配置中添加一下配置*/</span>
sourceSets {
    main {
        jniLibs.srcDirs = [<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">'libs'</span>]
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li></ul>

2、定义自己的本地jni接口类

2.1、获取so里定义的本地方法签名

借助是是Linux的一个命令:nm -D xxxx.so还可以设置-D以外的其他参数,不过-D已经足够

<code class="hljs mathematica has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">nm -<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">D</span>  libelia.so</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>

下图显示的就是联发科SmartLink方案的so库定义的方法签名还有其他信息,就不贴了 
这里写图片描述

2.2、实现自己的本地jni接口类

把所要使用的so文件复制粘贴到”jniLibs“文件夹之后,一般来说其他第三方的开放平台的so文件都是已经把对应的本地Java接口类一起封装到so或者其他库文件里了,我们不需要自己去定义自己的本地接口类,假如说第三方只是提供了so文件,那么就需要我们去定义jni接口类(这个类并不能是随意的,必须是和so文件里定义的方法名的一一对应,即包名和类名必须一致,否则会发生编译通过加载的时候就出错) 
这里写图片描述
假如so里是这样定义本地方法,那么对应的我们这个本地接口类,必须满足四个条件:

  1. 包名是crazymo.train.jnitraining

  2. 类名是MainActivity

  3. 定义的方法名为 helloJni

  4. 返回值类型为String

那么定义这个本地接口方法类的一般步骤是:

  1. 在项目里首先创建一个对应的包
  2. 再这个包里创建对应的公开类
  3. 最后在这个类里定义对应的本地接口方法(常规修饰符 native static 返回值类型 helloJni**当然static并不是必须的)

3、加载so文件

加载so文件很简单,如果你这个APP必须依赖于这个so才能运行的话,建议可以在自己的Application去实现

<code class="hljs cs has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"> System.loadLibrary(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"helloJni"</span>);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//加载so文件,不要带上前缀lib和后缀.so</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li></ul>
<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> crazymo.train.jni;

<span class="hljs-javadoc" style="color: rgb(136, 0, 0); box-sizing: border-box;">/**
 *<span class="hljs-javadoctag" style="color: rgb(102, 0, 102); box-sizing: border-box;"> @auther</span>: Crazy.Mo
 * Date: 2016/10/13
 * Time:15:22
 * Des:
 */</span>
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">HelloJNI</span> {</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">static</span> {
        System.loadLibrary(<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"helloJni"</span>);<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//引入你的so库文件,不要把前面的lib添加进来</span>
    }
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">native</span> String <span class="hljs-title" style="box-sizing: border-box;">helloJni</span>();
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li></ul>

4、利用本地jni接口类调用对应的接口方法

这个更简单了,就和我们普通java类的调用语法一样,如果是静态的就用类去调用,如果非静态则用对应的实例去调用,至于怎么调用到本地代码的,那部分工作由系统会根据你本地接口的包名、方法名去找到对应的C/C++代码,所以本地接口类往往是我们使用so时发生错误的罪魁祸首之一

<code class="hljs java has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">package</span> crazymo.train.jni;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.app.Activity;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.os.Bundle;
<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">import</span> android.widget.TextView;

<span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">public</span> <span class="hljs-class" style="box-sizing: border-box;"><span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">class</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">MainActivity</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">extends</span> <span class="hljs-title" style="box-sizing: border-box; color: rgb(102, 0, 102);">Activity</span> {</span>

    <span class="hljs-annotation" style="color: rgb(155, 133, 157); box-sizing: border-box;">@Override</span>
    <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">protected</span> <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">void</span> <span class="hljs-title" style="box-sizing: border-box;">onCreate</span>(Bundle savedInstanceState) {
        <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">super</span>.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ((TextView)findViewById(R.id.txt_usejni)).setText( <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">new</span> HelloJNI().helloJni());<span class="hljs-comment" style="color: rgb(136, 0, 0); box-sizing: border-box;">//使用jni方法</span>
    }
}</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li><li style="box-sizing: border-box; padding: 0px 5px;">4</li><li style="box-sizing: border-box; padding: 0px 5px;">5</li><li style="box-sizing: border-box; padding: 0px 5px;">6</li><li style="box-sizing: border-box; padding: 0px 5px;">7</li><li style="box-sizing: border-box; padding: 0px 5px;">8</li><li style="box-sizing: border-box; padding: 0px 5px;">9</li><li style="box-sizing: border-box; padding: 0px 5px;">10</li><li style="box-sizing: border-box; padding: 0px 5px;">11</li><li style="box-sizing: border-box; padding: 0px 5px;">12</li><li style="box-sizing: border-box; padding: 0px 5px;">13</li><li style="box-sizing: border-box; padding: 0px 5px;">14</li><li style="box-sizing: border-box; padding: 0px 5px;">15</li></ul>

5、简单使用so库项目的结构图

这里写图片描述

四、NDK调试

默认情况下是不支持NDK调试的,但我们只要做些简单配置即可实现支持。

1、打开JNI调试 openModuleSettings——>选中module——>Build Types——>Jni Debuggable为true——Apply

这里写图片描述

2、配置Android Native - Debugger run——>Edit configurations——>选中对应的module——>Debugger——>Debugger Type 选native——Apply

这里写图片描述

3、下载安装LLDB,Done。

五、使用so时常见错误

1、java.lang.UnsatisfiedLinkError: Couldn’t load library xxxx from loader dalvik.system.PathClassLoader

导致这个异常的根本原因就是系统在本地方法与我们本地方法接口类无法对应上,官方一点就是JVM找不到native method的native

  • 还未加载对应的so导致的Crash!xxxcouldn’t find “xxx.so”,因为apk打包安装时,系统会把apk中libs目录下armeabi的so拷贝到应用的私有目录下
<code class="hljs lua has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;">
Crash!java.lang.UnsatisfiedLinkError: dalvik.system.PathClassLoader[DexPathList<span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">[[zip file “/data/app/xxx],nativeLibraryDirectories=[/vendor/lib, /systemb]]</span>] couldn’t find “xxx.so”</code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li></ul>
  • 加载的so与所运行的设备的abi架构不一致,只要在在对应的文件夹里添加上相应的so文件即可

  • java.lang.UnsatisfiedLinkError:No implementation found for XXX 
    这种错误一般来就是我们本地方法接口类没有和c/c++里的方法对应上

2、java.lang.UnsatisfiedLinkError: com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader

原因是引用了多方的so,很常见的情况是libaxx.so在各个架构对应的文件夹中都存在,而另一个libcxx.so只存在于32位对应的armaebi文件下,其他架构的都没有,那么此时程序运行在非armaebi架构的设备时则会直接报错强退。错误的日志如下:

<code class="hljs vhdl has-numbering" style="display: block; padding: 0px; background: transparent; color: inherit; box-sizing: border-box; font-family: "Source Code Pro", monospace;font-size:undefined; white-space: pre; border-radius: 0px; word-wrap: normal;"><span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">10</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">15</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">42</span>:<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">28.122</span> <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5307</span>-<span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5307</span>/com.xiaoi.app.zkSmartHome E/AndroidRuntime: FATAL EXCEPTION: main
                                                                         <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">Process</span>: com.xiaoi.app.zkSmartHome, PID: <span class="hljs-number" style="color: rgb(0, 102, 102); box-sizing: border-box;">5307</span>
                                                                         java.lang.UnsatisfiedLinkError: com.android.tools.fd.runtime.IncrementalClassLoader$DelegateClassLoader[DexPathList[[dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-zxing_c557fb7a8d7e6e337af354ce06614692a32b946a-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-support-annotations-24.0.0_abdd7eb84ec5507286f957f2abccaca254128b0c-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_9-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_8-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_7-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_6-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_5-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_4-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_3-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_2-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_1-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-slice_0-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-rxjava-1.1.8_75fd2ee9fdad54b1b788e8d01c74e78698f28eae-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-retrofit-2.0.0-beta4_3efd0604843b4a6440028ce43f72e5845c1c3325-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-picasso-2.5.2_badcc59626c8bf60fbd570ba883ac0f8d5c9be7a-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-okio-1.6.0_c6c36c9266a53bff725e5087f6a3090b1d0ab593-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-okhttp-3.0.1_a35a122a63f63f6d2b3ba59d028c055fab521b52-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-io.reactivex-rxandroid-1.2.1_6e88671f81f408ad9e58406d59bc0cda6a6af625-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-internal_impl-24.0.0_1ca3cb52067dc09725d551b03ece99cd965979ac-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-in.srain.cube-ultra-ptr-1.0.11_b0a09794d2bb3bfed3ce82634bdccabed79fc5d0-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-gson-2.4_1cef8cfc76ca82a728656c88394ab94c85c46ee1-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-glide-3.6.1_f81c2f329f31a6fbb9641a61098e423c033cd42e-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-converter-gson-2.0.0-beta4_75a1a6273cb28d11375dfff6cd0aa45f11079258-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.orhanobut-logger-1.3_89736aa22bffa06d17995d9ad26acdfaf3572df7-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.android.support-support-vector-drawable-24.0.0_8d5d9e2412dc464146da0fdb00638a8cb0b0130d-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.android.support-support-v4-24.0.0_225ce4463e0d8c3e77ccfd8c1e749bd698e46fcc-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.android.support-recyclerview-v7-24.0.0_39a4b7cd3d134a80b92025fdd19f175953aa0dcc-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.android.support-cardview-v7-24.0.0_22b22b962be76ccc27cc64fad5c53d30515f6535-classes.dex"</span>, dex <span class="hljs-keyword" style="color: rgb(0, 0, 136); box-sizing: border-box;">file</span> <span class="hljs-string" style="color: rgb(0, 136, 0); box-sizing: border-box;">"/data/data/com.xiaoi.app.zkSmartHome/files/instant-run/dex/slice-com.android.support-appcompat-v7-24.0.0_4ce805b4f9e08926ae1</span></code><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul><ul class="pre-numbering" style="box-sizing: border-box; position: absolute; width: 50px; background-color: rgb(238, 238, 238); top: 0px; left: 0px; margin: 0px; padding: 6px 0px 40px; border-right: 1px solid rgb(221, 221, 221); list-style: none; text-align: right;"><li style="box-sizing: border-box; padding: 0px 5px;">1</li><li style="box-sizing: border-box; padding: 0px 5px;">2</li><li style="box-sizing: border-box; padding: 0px 5px;">3</li></ul>

解决方法: 
最佳的方案肯定是添加上对应的so到对应的文件夹下,不过由于某些原因,不能找到对应的so库,也可以采用投机取巧的方式,把armaebi下的copy到其他文件下或者删除其他的文件夹,总之,要保证你有我也有,不能你有我无。

3、还未发现…后面发现了再补充


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
好的,关于您的问题,我会尽力回答。在Android中,JNI可以用来与C/C++代码进行交互,我们可以利用JNI来读写SD卡。下面是一个简单的例子: 1. 首先,在您的Java代码中定义native方法: ``` public class MainActivity extends Activity { static { System.loadLibrary("native-lib"); } public native String readFromSDCard(String filePath); public native boolean writeToSDCard(String filePath, String content); } ``` 2. 然后,在您的C/C++代码中实现这些方法: ``` #include <jni.h> #include <string.h> #include <stdio.h> #include <android/log.h> JNIEXPORT jstring JNICALL Java_com_example_myapplication_MainActivity_readFromSDCard(JNIEnv *env, jobject instance, jstring filePath) { const char *path = env->GetStringUTFChars(filePath, 0); FILE *file = fopen(path, "r"); if (file == NULL) { __android_log_print(ANDROID_LOG_ERROR, "JNI", "readFromSDCard: fopen failed"); return NULL; } fseek(file, 0, SEEK_END); long size = ftell(file); fseek(file, 0, SEEK_SET); char *buffer = new char[size + 1]; fread(buffer, 1, size, file); buffer[size] = '\0'; fclose(file); env->ReleaseStringUTFChars(filePath, path); return env->NewStringUTF(buffer); } JNIEXPORT jboolean JNICALL Java_com_example_myapplication_MainActivity_writeToSDCard(JNIEnv *env, jobject instance, jstring filePath, jstring content) { const char *path = env->GetStringUTFChars(filePath, 0); const char *str = env->GetStringUTFChars(content, 0); FILE *file = fopen(path, "w"); if (file == NULL) { __android_log_print(ANDROID_LOG_ERROR, "JNI", "writeToSDCard: fopen failed"); return false; } fwrite(str, 1, strlen(str), file); fclose(file); env->ReleaseStringUTFChars(filePath, path); env->ReleaseStringUTFChars(content, str); return true; } ``` 3. 最后,在您的AndroidManifest.xml文件中添加以下权限: ``` <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> ``` 这样,您就可以在Java代码中调用这些native方法来读写SD卡了。 至于Android NDK使用实例——增量更新实战,这是一个比较复杂的话题,如果您有相关的需求,可以提出具体的问题,我会尽力为您解答。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值