哪些应用比较适合使用NDK开发?
- 在平台之间移植其应用
- 重复使用现有库或者提供自己的库供重复使用
- 在某些情况下提高性能,特别是像游戏这种计算密集型应用。
其中第二条就是因为可以将代码生成.so文件,放在其他项目中使用。
一、使用Android Studio生成.so文件的步骤:
1、首先电脑中要安装并配置NDK环境。
下载ndk并解压 https://developer.android.google.cn/ndk/downloads/revision_history
打开终端,输入open -e .bash_profile
在. bash_profile文件中编辑:
export ANDROID_NDK_ROOT=/Users/lxy/Library/Android/android-ndk-r16b(解压出下载的ndk文件路径)
export PATH=$PATH:$ANDROID_NDK_ROOT
2、创建一个GetNum.java文件,用于加载JNI库并定义Native方法。
package com.lxy.sky.obtainsofile;
public class GetNum {
static {
System.loadLibrary("GetNum");
}
public static native int getNum(int num);
}
3、将该文件进行编译产生GetNum.class文件。
在终端中定位到GetNum类所在的文件夹,然后进行编译,编译后会发现该文件夹中多了一个GetNum.class文件
lxydeMacBook-Pro:java lxy$ cd /Users/lxy/Documents/ObtainSoFile/app/src/main/java/com/lxy/sky/obtainsofile
lxydeMacBook-Pro:obtainsofile lxy$ javac GetNum.java
4、利用javah生成GetNum.class文件对应的native头文件,并将其移至jni文件夹下,改名为GetNum.h
lxydeMacBook-Pro:obtainsofile lxy$ cd /Users/lxy/Documents/ObtainSoFile/app/src/main/java
lxydeMacBook-Pro:java lxy$ javah com.lxy.sky.obtainsofile.GetNum
产生的头文件如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_lxy_sky_obtainsofile_GetNum */
#ifndef _Included_com_lxy_sky_obtainsofile_GetNum
#define _Included_com_lxy_sky_obtainsofile_GetNum
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_lxy_sky_obtainsofile_GetNum
* Method: getNum
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_lxy_sky_obtainsofile_GetNum_getNum
(JNIEnv *, jclass, jint);
#ifdef __cplusplus
}
#endif
#endif
5、重新创建一个C文件,GetNum.c,并实现头文件中的方法。
GetNum.c文件中如下编写:
//
// Created by lxy on 2019/2/12.
//
#include <jni.h>
jint JNICALL Java_com_lxy_sky_obtainsofile_GetNum_getNum
(JNIEnv* env, jclass jc, jint num){
return 2*num;
}
6、在jni文件夹下创建两个文件,Android.mk和Application.mk。
在jni文件夹下创建Android.mk,其中添加如下内容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := GetNum
LOCAL_SRC_FILES := GetNum.c
include $(BUILD_SHARED_LIBRARY)
在jni文件夹下创建Android.mk,其中添加如下内容:
APP_PLATFORM := android-14
APP_ABI :=all
这两个文件创建完后编写会出现红色波浪线,可以使用mark as plain text,就不会报错了
7、使用ndk-build命令生成.so文件。
在终端跳转到jni目录下,输入ndk-build就会在jni同级目录出现libs和obj两个文件夹,里面就是.so文件
lxydeMacBook-Pro:java lxy$ cd /Users/lxy/Documents/ObtainSoFile/app/src/main/jni
lxydeMacBook-Pro:jni lxy$ ndk-build
然后就会出现以下效果,就说明好了。
[arm64-v8a] Compile : GetNum <= GetNum.c
[arm64-v8a] SharedLibrary : libGetNum.so
[arm64-v8a] Install : libGetNum.so => libs/arm64-v8a/libGetNum.so
[x86_64] Compile : GetNum <= GetNum.c
[x86_64] SharedLibrary : libGetNum.so
[x86_64] Install : libGetNum.so => libs/x86_64/libGetNum.so
[armeabi-v7a] Compile thumb : GetNum <= GetNum.c
[armeabi-v7a] SharedLibrary : libGetNum.so
[armeabi-v7a] Install : libGetNum.so => libs/armeabi-v7a/libGetNum.so
[x86] Compile : GetNum <= GetNum.c
[x86] SharedLibrary : libGetNum.so
[x86] Install : libGetNum.so => libs/x86/libGetNum.so
到这里.so文件就生成了。
二、下面就是这些.so文件是如何使用,在本地如何使用,在其他工程时如何使用的?
1、首先是在本工程中使用,此时jni文件夹下的所有文件都是可以删除掉的,有没有都是可以使用的了。
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("GetNum");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toast.makeText(this, "输出的数字是:"+GetNum.getNum(4), Toast.LENGTH_SHORT).show();
}
}
2、其他工程的话需要新建一个包,要和刚才的包名相同,com.lxy.sky.obtainsofile。如果你有一个本地(native)方法,就会自动根据路径去查找C语言方法,比如以上的native getnum()方法,就会自动查询Java_com_lxy_sky_obtainsofile_GetNum_getNum,如果没有就会报错,所以想要试用该方法,就要创建一个相同的包名,这个路径是和该方法所在的包有关的,类名和方法名也要相同。
要将.so文件粘贴到libs和jnilibs(可以没有)目录下,类及其内容如上图即可,在build. gradle中添加如下代码
sourceSets {
main {
jniLibs.srcDirs = ['libs']
}
}
现在就可以在你需要的地方调用了:
GetNum jniUtils=new GetNum();
Toast.makeText(this, "输出的数字是:"+ jniUtils.getNum(4), Toast.LENGTH_SHORT).show();
这样就全部完成了。
三、过程当中遇到的异常
1、java.lang.UnsatisfiedLinkError so库找不到
java.lang.UnsatisfiedLinkError: No implementation found for int com.lxy.sky.obtainsofile.GetNum.getNum(int)
(tried Java_com_lxy_sky_obtainsofile_GetNum_getNum and Java_com_lxy_sky_obtainsofile_GetNum_getNum__I)
这有两种可能,一个是没有加载so库
System.loadLibrary("GetNum");
另一种可能就是创建的包名不对。
2、Android NDK: Could not find application project directory !
在使用终端使用ndk-build命令的时候报的错误,这是因为没有事先定位到当前工程的jni目录所导致的