我们在一步一步学习JNI(一)学习了怎么进行Jni开发,当时说道了怎么编写native函数,怎么进行加载,怎么进行so生成,当时的都是在eclipse下生成的。这里我们就来说说Android Studio下怎么进程开发。
在jni开发之前,需要先下载NDK。路径如下:
下载完成后,NDK是放置在SDK下的,有一个ndk-bundle文件夹。老版本是单独的一个目录,因此以下根据新旧版本来区分讲解。
第一步当然是创建一个Android工程了。创建完工程后主代码如下:
public class MainActivity extends Activity { private TextView showSum; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViews(); loadSum(); } private void findViews() { showSum = (TextView) findViewById(R.id.sum); } private void loadSum() { showSum.setText("Result=" + HelloJni.getSum(3, 5)); } }这里我们引用了一个HelloJni.getSum函数,主要逻辑在HelloJni里面。创建完工程后,主要有一下一些步骤:
我们来编写HelloJni类,首先是编写native函数。
public class HelloJni { static { System.loadLibrary("Hello"); } public static native int getSum(int a, int b); }这里代码很简单,跟一步一步学习JNI(一)很类似,主要是跟前面做一个对比,看看最终的效果。这里首先在静态块里面加载了so,之后有一个getSum的native函数。
首先将整个工程的gradle下的dependencies节点改成如下,需要gradle2.5版本以上:
dependencies { //classpath 'com.android.tools.build:gradle:2.1.0' classpath 'com.android.tools.build:gradle-experimental:0.7.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files }其次将app下的gradle改成如下,主要apply plugin从com.android.application变成了com.android.model.application,多了一层model节点,其他所有配置项都空格变成了等号。
apply plugin: 'com.android.model.application' model { android { compileSdkVersion = 23 buildToolsVersion = '23.0.2' defaultConfig { minSdkVersion.apiLevel = 14 targetSdkVersion.apiLevel = 23 } /* * native build settings: taking default for almost everything */ ndk { moduleName = 'Hello' toolchain = 'clang' CFlags.addAll(['-Wall']) } buildTypes { release { minifyEnabled = false proguardFiles.add(file('proguard-rules.txt')) } } productFlavors { // for detailed abiFilter descriptions, refer to "Supported ABIs" @ // https://developer.android.com/ndk/guides/abis.html#sa create("arm") { ndk.abiFilters.add("armeabi") } create("arm7") { ndk.abiFilters.add("armeabi-v7a") } create("arm8") { ndk.abiFilters.add("arm64-v8a") } create("x86") { ndk.abiFilters.add("x86") } create("x86-64") { ndk.abiFilters.add("x86_64") } create("mips") { ndk.abiFilters.add("mips") } create("mips-64") { ndk.abiFilters.add("mips64") } // To include all cpu architectures, leaves abiFilters empty create("all") } } } dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:23.4.0' }编译生成class文件很简单,只需要Build→Make project就好了。
最终生成的代码在工程/Jni/app/build/intermediates/classes/debug下,会有很多个class文件。
首先在新创建一个jni目录,默认在java节点下,目录名为jni:
创建完成后,在jni目录下新建一个.c文件,默认是一个空文件,手动添加#include <jni.h>,之后就可以到之前编写的native函数,这个地方可以用快捷键自动生成映射函数到新创建的.c文件下,生成的函数如下:
JNIEXPORT jint JNICALL Java_com_net_jni2_Hello_get(JNIEnv *env, jobject instance, jint a, jint b) { // TODO }有时可能需要clean一次,我出现了第一次运行后失败,clean才ok的,之后点击run:
同新版本
同新版本
生成class后就该生成.h文件了。我们可以在Android Studio中用命令行来生成。打开命令行窗口,路径如下View→Tool Window→Terminal:
在命令行输入生成.h文件的命令,我们将生成后的.h文件放置到app→src→main下,输入命令进入main文件夹下:
cd app/src/main/进入目录后输入生成.h的命令,在前面我们已经学习过怎么生成.h文件了。我们先看看之前的生成方式:
javah -d jni -classpath /Users/doc/Android/Jni/app/build/intermediates/classes/debug com.net.jni.HelloJni-jni为可选参数 -classpath 类查找路径 -d 生成的文件放到-d后指定的目录,如果不存在在生成,这里放到jni目录
可以看到在main下生成了jni文件夹,并且生成了一个com_net_jni_HelloJni.h的头文件。
这个地方我们是新建了一个类来实现JNI,但是如果你直接在Activity中使用native函数又该怎么办?输入如下的命令:
javah -d jni -classpath /Users/doc/Library/Android/sdk/platforms/android-23/android.jar;/Users/doc/Android/Jni/app/build/intermediates/classes/debug com.net.jni.HelloJni这里classpath里面多指定了一个路径,指向了sdk中的android.jar,这是因为在Activity中需要继承父类的Activity,需要用到android.jar中的文件。 不过编译命令后可能会出现如下的异常:
bash: /Users/doc/Android/Jni/app/build/intermediates/classes/debug: is a directory这是由于系统的不同classpath后的书写方式不同。将(分号);号改成(冒号):号。
-classpath /Users/doc/Library/Android/sdk/platforms/android-23/android.jar:/Users/doc/Android/Jni/app/build/intermediates/classes/debug com.net.jni.HelloJni在一步一步学习JNI(一)我们已经学习了怎么实现头文件,在jni文件夹下新建HelloJni.c文件,将头文件中的函数拷贝到HelloJni.c中,并实现。
#include "com_net_jni_HelloJni.h" #ifdef __cplusplus extern "C" { #endif /* * Class: com_net_jni_HelloJni * Method: getSum * Signature: (II)I */ JNIEXPORT jint JNICALL Java_com_net_jni_HelloJni_getSum (JNIEnv *env, jclass cls, jint a, jint b){ return a+b; } #ifdef __cplusplus } #endif在local.properties下指定NDK路径。
ndk.dir=/Users/doc/Library/Android/sdk/ndk-bundle开始配置build.gradle,gradle改成如下:
defaultConfig { applicationId "com.net.jni" minSdkVersion 14 targetSdkVersion 23 versionCode 1 versionName "1.0" ndk{ moduleName "Hello" } }还可以配置abiFilters等信息,之后Make project就可以生成so。
最终运行效果同新版本。
当升级了Android Studio后不能再用老的方式实现,不知道是不是我不知道怎么实现,如果有人知道望告知,升级后编写很简单,可以自动生成对应的jni函数,只需要实现里面的逻辑就好,这是老版本不能实现的。如果不知道怎么更改gradle可以去查看官方的文档,文档路径