「Efficient Android Threading 笔记」- C1 Android Components and the Need for Multiprocessing Android RecyclerView Android Socket Programming Supporting Multiple Screens Make a Reusable UI in Android App Development 如何在 Android Studio 中包含 *.so library,并使用库中定义的方法? 使用 SpannableString 格式化字符串,实现前景色、下划线、超链接、图文混排等 如何使用 bound service 完成进程间通信? 创建自定义视图 Creating custom views 通过 Android Theme & Style 定制应用的样式 「译」Android ViewPropertyAnimator 介绍 Android Animation Interpolator - Android 动画插值器源码笔记 「译」Android Animation in Honeycomb by Chet Haase(Android 3.0系统中的动画机制) 从 Android Sample ApiDemos 中学习 android.animation API 的用法 如何学习 Android Animation? 如何实现 Android ListView「上拉加载更多」? 「译」向Big Nerd Ranch提问:为什么Fragment在Android App开发中非常重要? 分类整理我在 SegmentFault 上针对某些问题作的回答 Android Servcie 后台服务总结笔记 如何在Android设备旋转时暂存数据以保护当前的交互状态? Android Message Handler 消息处理机制总结笔记 如何获取FragmentTabHost中指定标签页的Fragment? Fragment子类必须包含一个public无参构造器 如何更新及替换ViewPager中的Fragment? 如何使用Android UI Fragment开发“列表-详情”界面? 一个Android音频文本同步的英文有声读物App的开发过程 「Android编程权威指南笔记」Android应用本地化 通过jfeinstein10/SlidingMenu实现Android侧滑菜单 为Ubuntu14.04部署Android App的Eclipse开发环境 「Android编程权威指南笔记」使用ListFragment显示列表 「Android编程权威指南笔记」SDK版本与兼容 「Android编程权威指南笔记」Android布局和组件 「Android编程权威指南笔记」UI Fragment 「Android编程权威指南笔记」Activity 第一次开发iOS App和Android的对比总结笔记 「App Training笔记」创建第一个应用 「App Training笔记」开发入门训练大纲 Android APP - 从远程FTP服务器下载文件到本地

如何在 Android Studio 中包含 *.so library,并使用库中定义的方法?

2016年04月13日

需要 3 步:

Step1 把 .so file 放到 Android Studio project 正确的路径中

需要新建一个名为 jniLibs 文件夹,根据目标机器的 CPU-ABI 类型,把 .so file 放入对应的路径下:

weiyi$ cd app/src/main/
weiyi$ tree -L 2
.
├── AndroidManifest.xml
├── java
├── jniLibs
│   ├── armeabi
│   │   └── libhello-jni.so
│   └── armeabi-v7a
│       └── libhello-jni.so
└── res

至于在其它编译器(eclipse等)中的路径,以及 armeabiarmeabi-v7a 的解释,参考 StackOverflow - System.loadLibrary(…) couldn’t find native library in my case

.so file 需要通过 NDK tool 编译 c/c++ 得到,可以从 android.googlesource.com 下载 libhello-jni.so

Step2 加载 .so library 并声明 native method

Java 端实现加载 .so library:(HelloJni.java)

package com.example.hellojni;

public class HelloJni {
    public native String stringFromJNI();
    
    static {
        System.loadLibrary("hello-jni");
    }
}

这篇开发文档 Developer - Sample: hello-jni 解释了 native 关键字。

Step3 最后就可以调用 .so library native method 了

类似调用任何一个类的方法:

    HelloJni helloJni = new HelloJni();
    LOGD(TAG, helloJni.stringFromJNI());

可以看到 log:Hello from JNI !。而整个工程目录应该是这样:

weiyiWorkCell:main weiyi$ tree -L 5
.
├── AndroidManifest.xml
├── java
│   └── com
│       ├── example
│       │   └── hellojni
│       │       └── HelloJni.java
├── jniLibs
│   ├── armeabi
│   │   ├── libhello-jni.so
│   └── armeabi-v7a
│       ├── libhello-jni.so
└── res

UnsatisfiedLinkError: No implementation found

在 step2 时,假如把 native method 声明在了一个随意命名的 package 或者随意命名的 java file 内,比如 com.example.hellojni21.HelloJni,你会遇到如下 exception:

java.lang.UnsatisfiedLinkError:
No implementation found for java.lang.String com.example.hellojni21.HelloJni.stringFromJNI() tried
Java_com_example_hellojni21_HelloJni_stringFromJNI and
Java_com_example_hellojni21_HelloJni_stringFromJNI__

这是因为命名存在一个默认的规则。
.so file 需要通过 NDK tool 编译 c/c++ 得到,c/c++ 实现 native method 时,要按如下规则命名,以 libhello-jni.so 为例:

jstring
Java_com_example_hellojni_HelloJni_stringFromJNI( JNIEnv* env, jobject thiz )
规则如下:
Java_package_file_method(...)

所以,Java 端的包名、文件名、方法名就被规定好了,包名必须是 com_example_hellojni,文件名必须是 HelloJni,native method 声明必须是 String stringFromJNI()

这篇开发文档 Developer - Sample: hello-jni 描述了命名规则。

我们还可以通过命令行列出 shared library 中的方法:

weiyi$ nm -D libhello-jni.so
00000b90 T Java_com_example_hellojni_HelloJni_stringFromJNI

参考:


知识共享许可协议
li2的博客WeiYi.Li 创作,采用 知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。
© 2011-2017. All rights reserved by WeiYi.Li. Powerd by Jekyll & LinAnYa's Theme