轉載請註明出處:http://blog.csdn.net/langtuteng136/article/details/50894142
前言: 在寫這篇博客前,找了很多關於Android jni 開發的教程,但大都是基於eclipse 中開發的,就算是找到了用Android studio開發的教程,也沒有一個能正確成功的,當時就感覺真是莫名的惱火,不過還好,最後按照自己的理解試成功了,下面就來仔細說下過程,有點多,因爲要把我自己遇到的坑說出來。
注意:因爲使用的工具和SDK版本不同,過程可能就不同,我把我試驗過的幾種情況都會說下。
一、工具和SDK版本:Android studio1.51, SDK版本:23 (最新的6.0)
二、工具和SDK版本:Android studio1.51, SDK版本:21
在這兩種情況之前你必須做好一件事:安裝NDK。過程如下:
在setting 中appearance -> Android SDK -> SDK Tools -> Android NDk 打鉤,然後點擊apply -> OK. 如下圖:
自動安裝好DN卡之後,會在 local.properties 中有顯示:如下圖
到此ND就安裝完成了,那麼接下來就是關鍵時刻了,先來看看情況一的具體過程:
1. 新建一個工程,就是一個簡單的空白工程,功能也沒有
2. 定義native 接口 和 加載即將生成的庫。就幾行代碼,代碼如下:
package zhanghuan.cn.jnitest1;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("JniTest");
}
public native String getStringFromNative();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView)findViewById(R.id.text);
textView.setText(getStringFromNative()); // 調用接口
}
}
3. 寫好接口之後接下來就是關鍵了,點擊 Build -> Make Project, 如下圖:
然後在底部的狀態欄Messages 中查看Build的情況,必須是0錯誤才行,如下圖:
4. Build 成功之後,就在Terminal 命令行中開始生成.h 文件
命令爲:
javah -d jni -classpath D:\tools\android-sdk\platforms\android-23\android.jar;D:\MyProject\AndroidStudio\JniTest1\app\src\main\java zhanghuan.cn.jnitest1.MainActivity
就是這一步卡了我好久,之前找的教程每個的命令都是這樣的:
javah -d jni -classpath D:\tools\android-sdk\platforms\android.jar;..\..\build\intermediates\classes\debug zhanghuan.cn.jnitest1.MainActivity
結果報錯 “找不到android.support.v7.app.AppCompatActivity的類文件” 如下圖:
迴歸正題,命令成功之後,在main 目錄下回生成jni目錄,然後還有一個.h 文件:如下圖:
我貼下.h 文件的代碼:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class zhanghuan_cn_jnitest1_MainActivity */
#ifndef _Included_zhanghuan_cn_jnitest1_MainActivity
#define _Included_zhanghuan_cn_jnitest1_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: zhanghuan_cn_jnitest1_MainActivity
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_zhanghuan_cn_jnitest1_MainActivity_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
5. 複製.h 文件放在相同的目錄下,改個名稱(名字任意)爲my.c , 代碼如下:
#include "zhanghuan_cn_jnitest1_MainActivity.h"
JNIEXPORT jstring JNICALL Java_zhanghuan_cn_jnitest1_MainActivity_getStringFromNative
(JNIEnv * env, jobject job) {
return (*env)->NewStringUTF(env, "Hello form JNI!");
}
但是這時你會發現有錯誤,NDK support is an experimental feature and all use cases are not yet supported, 如下圖:
解決方法是在 gradle.properties 文件中加入一句代碼:
android.useDeprecatedNdk=true
ndk{
moduleName "JniTest"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
我的build.gradle 文件代碼如下:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "zhanghuan.cn.jnitest1"
minSdkVersion 11
targetSdkVersion 23
versionCode 1
versionName "1.0"
ndk{
moduleName "JniTest"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.2.1'
}
到此,基本步驟就全部完成了,然後就直接運行一下,看下效果,效果圖如下:
成功完成!如果有興趣可以看下下面的第二種情況。
好了,接下來我們就看看第二種情況:不使用V7。
1. 前面的幾步步驟和第一種情況是一樣的,到第4步的命令行開始有重要的差別, 我就直接跳到命令行那步了,命令如下:
javah -d jni -classpath D:\tools\android-sdk\platforms\android-21\android.jar;D:\MyProject\AndroidStudio\JinTest\app\build\intermediates\classes\debug zhanghuan.cn.jintest.MainActivity
注意如果出錯要寫絕對的地址,網上的教程都是什麼”..\..\buidl\...“這種寫法,但是我一次都沒成功,折騰了很久都沒成功,如果你成功了就請告訴我。
最後生成的.h 文件代碼如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class zhanghuan_cn_jintest_MainActivity */
#ifndef _Included_zhanghuan_cn_jintest_MainActivity
#define _Included_zhanghuan_cn_jintest_MainActivity
#ifdef __cplusplus
extern "C" {
#endif
#undef zhanghuan_cn_jintest_MainActivity_BIND_ABOVE_CLIENT
#define zhanghuan_cn_jintest_MainActivity_BIND_ABOVE_CLIENT 8L
#undef zhanghuan_cn_jintest_MainActivity_BIND_ADJUST_WITH_ACTIVITY
#define zhanghuan_cn_jintest_MainActivity_BIND_ADJUST_WITH_ACTIVITY 128L
#undef zhanghuan_cn_jintest_MainActivity_BIND_ALLOW_OOM_MANAGEMENT
#define zhanghuan_cn_jintest_MainActivity_BIND_ALLOW_OOM_MANAGEMENT 16L
#undef zhanghuan_cn_jintest_MainActivity_BIND_AUTO_CREATE
#define zhanghuan_cn_jintest_MainActivity_BIND_AUTO_CREATE 1L
#undef zhanghuan_cn_jintest_MainActivity_BIND_DEBUG_UNBIND
#define zhanghuan_cn_jintest_MainActivity_BIND_DEBUG_UNBIND 2L
#undef zhanghuan_cn_jintest_MainActivity_BIND_IMPORTANT
#define zhanghuan_cn_jintest_MainActivity_BIND_IMPORTANT 64L
#undef zhanghuan_cn_jintest_MainActivity_BIND_NOT_FOREGROUND
#define zhanghuan_cn_jintest_MainActivity_BIND_NOT_FOREGROUND 4L
#undef zhanghuan_cn_jintest_MainActivity_BIND_WAIVE_PRIORITY
#define zhanghuan_cn_jintest_MainActivity_BIND_WAIVE_PRIORITY 32L
#undef zhanghuan_cn_jintest_MainActivity_CONTEXT_IGNORE_SECURITY
#define zhanghuan_cn_jintest_MainActivity_CONTEXT_IGNORE_SECURITY 2L
#undef zhanghuan_cn_jintest_MainActivity_CONTEXT_INCLUDE_CODE
#define zhanghuan_cn_jintest_MainActivity_CONTEXT_INCLUDE_CODE 1L
#undef zhanghuan_cn_jintest_MainActivity_CONTEXT_RESTRICTED
#define zhanghuan_cn_jintest_MainActivity_CONTEXT_RESTRICTED 4L
#undef zhanghuan_cn_jintest_MainActivity_MODE_APPEND
#define zhanghuan_cn_jintest_MainActivity_MODE_APPEND 32768L
#undef zhanghuan_cn_jintest_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING
#define zhanghuan_cn_jintest_MainActivity_MODE_ENABLE_WRITE_AHEAD_LOGGING 8L
#undef zhanghuan_cn_jintest_MainActivity_MODE_MULTI_PROCESS
#define zhanghuan_cn_jintest_MainActivity_MODE_MULTI_PROCESS 4L
#undef zhanghuan_cn_jintest_MainActivity_MODE_PRIVATE
#define zhanghuan_cn_jintest_MainActivity_MODE_PRIVATE 0L
#undef zhanghuan_cn_jintest_MainActivity_MODE_WORLD_READABLE
#define zhanghuan_cn_jintest_MainActivity_MODE_WORLD_READABLE 1L
#undef zhanghuan_cn_jintest_MainActivity_MODE_WORLD_WRITEABLE
#define zhanghuan_cn_jintest_MainActivity_MODE_WORLD_WRITEABLE 2L
#undef zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_DIALER
#define zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_DIALER 1L
#undef zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_DISABLE
#define zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_DISABLE 0L
#undef zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL
#define zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SEARCH_GLOBAL 4L
#undef zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL
#define zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SEARCH_LOCAL 3L
#undef zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SHORTCUT
#define zhanghuan_cn_jintest_MainActivity_DEFAULT_KEYS_SHORTCUT 2L
#undef zhanghuan_cn_jintest_MainActivity_RESULT_CANCELED
#define zhanghuan_cn_jintest_MainActivity_RESULT_CANCELED 0L
#undef zhanghuan_cn_jintest_MainActivity_RESULT_FIRST_USER
#define zhanghuan_cn_jintest_MainActivity_RESULT_FIRST_USER 1L
#undef zhanghuan_cn_jintest_MainActivity_RESULT_OK
#define zhanghuan_cn_jintest_MainActivity_RESULT_OK -1L
/*
* Class: zhanghuan_cn_jintest_MainActivity
* Method: getStringFromNative
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_zhanghuan_cn_jintest_MainActivity_getStringFromNative
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif
#endif
當然了,你還可以用第一種情況中的命令,也是OK的,同時不加上-classpath 和 android.jar,只指定要編譯的類文件和.h文件目錄就可以,如下:
javah -d jni D:\MyProject\AndroidStudio\JinTest\app\build\intermediates\classes\debug zhanghuan.cn.jintest.MainActivity
-d jni 是指定.h 生成後放的位置,不要自己建也是可以的。
最後生成的.so 文件在 app\build\intermediates\ndk\debug\lib 下,如下圖:
到此,全部的情況都已介紹完畢,當然了,如果你在做的時候有問題的話歡迎留言,我們大家一起討論交流。
源碼我放在了github上:
https://github.com/john123fd/AndroidJNI21
https://github.com/john123fd/AndroidJNIV7