Android開發中經常會使用到第三方的.so庫。在使用.so庫的時候就要用到JNI編程。JNI是Java Native Interface的縮寫。它提供了若干的API實現了Java和其它語言的通訊(主要是C&C++)。開發中通常都用第三方的庫,很是多時候也可能咱們本身來編寫C或者C++來實現JNI編程,這篇博客主要是介紹Android studio 使用NDK工具來開發JNI編程。java
JNI編程需要知足例如如下前提:android
個人ndk版本號爲 android-ndk-r10e。編程
除此以外,你還得新建一個CLASSPATH環境變量,變量名:CLASSPATH;變量值爲 .;%HOME_PATH%\lib; 一開始的 . 和;和最後的;都是需要的。bash
android.useDeprecatedNdk=true
假設沒有gradle.progerties文件,請直接在當前project下新建該文件就能夠。markdown
1.新建JniUtils類。用來調用jni方法。代碼例如如下:app
package com.example.xjp.myjnidmoe;
public class JniUtils {
//載入靜態庫
static {
System.loadLibrary("Test");//此處載入的是對應的模塊庫,名稱必須和 ndk的moduleName名同樣。
}
//定義本地方法
public native String getValue();
}
2.Build 編譯當前project,最後會在build文件夾下生成例如如下文件
該文件夾下生成了 JniUtils.class文件。編輯器
而後打開AS的Terminal終端,跳到debug文件夾下:
而後運行 javah -jni *(此處爲你的目標文件路徑。即JniUtils路徑)
最後會在debug文件夾如下生成 com_example_xjp_myjnidmoe_JniUtils.h 頭文件。代碼例如如下:ide
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_xjp_myjnidmoe_JniUtils */
#ifndef _Included_com_example_xjp_myjnidmoe_JniUtils
#define _Included_com_example_xjp_myjnidmoe_JniUtils
#ifdef __cplusplus
extern "C" {
#endif
/* * Class: com_example_xjp_myjnidmoe_JniUtils * Method: getValue * Signature: ()Ljava/lang/String; */
JNIEXPORT jstring JNICALL Java_com_example_xjp_myjnidmoe_JniUtils_getValue
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
以上代碼是本身主動生成的,無需開發人員去改動。工具
3.在你的main文件夾下新建jni子文件夾。例如如下:
將剛纔生成的 .h頭文件拷貝到該jni文件夾下。而後新建一個 test.c文件,test.c文件代碼例如如下:post
//
// Created by 850302 on 2016/4/26.
//
#include "com_example_xjp_myjnidmoe_JniUtils.h"
JNIEXPORT jstring JNICALL Java_com_example_xjp_myjnidmoe_JniUtils_getValue
(JNIEnv *env, jobject obj) {
return (*env)->NewStringUTF(env, "This is my first JNI demo!");
}
由於jni編程對方法的名稱有必定規則要求。開頭需要Java_ 後面依次是jni方法的java類路徑。以「_」切割。
開發人員爲了避免寫錯,可以直接將剛纔的.h頭文件中的方法 copy下來直接實現就能夠。
4.配置Gradle文件
首先你得配置當前project的 build.gradle文件,事實上配置很是easy,直接在原來的build.gradle文件中加入 ndk的配置就能夠。
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com.example.xjp.myjnidmoe"
minSdkVersion 21
targetSdkVersion 23
versionCode 1
versionName "1.0"
//這裏是配置ndk
ndk{
//定義庫的模塊名稱。該名稱用於System.loadLibrary("Test")
moduleName "Test"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
是否是很是easy。不過定義了 ndk 的moduleName的名稱而已。
其次是爲當前project配置指定的ndk,配置方法例如如下:右鍵當前project名。選擇Open Module Settings。彈出例如如下窗體。
如圖。1:sdk路徑;2:jdk路徑。3:ndk路徑;點擊ok以後。
會在local.properties文件下配置指定的sdk和ndk路徑:
#Tue Apr 26 18:36:18 CST 2016
ndk.dir=F\:\\Android\\SDK1\\android2\\android-ndk-r10e
sdk.dir=F\:\\Android\\SDK1\\android2\\sdk
如此,所有的準備工做都已經完畢。現在可以在你的代碼中使用Test庫了,調用代碼例如如下:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.text);
//start=====
JniUtils jniUtils = new JniUtils();
String content = jniUtils.getValue();
//end=====
textView.setText(content);
}
結果例如如下:
可能會有人問。代碼生成的libTest.so庫在哪裏呢?事實上生成的libTest.so庫已經打包到apk中去了,那麼假如我要把這個so庫給別人使用怎麼辦?很是easy,在你編譯的過程事實上已經生成了libTest.so,在哪裏呢?文件夾例如如下:bulid/intermediates/ndk文件夾下。該文件夾是編譯成功以後生成的。
看到沒?生成了不一樣平臺下的libTest.so庫。
該博客主要是記錄Android studio 下使用NDK工具實現JNI編程和生成so庫的整個過程。以便開發人員瞭解JNI編程的一個完整的過程。