編輯:關於android開發
以前接觸過NDK的開發,是在Eclipse環境下開發的。今天嘗試了下用Android Studio來配置,結果真是處處都是坑,現在總結一下:
一、步驟
1. 首先創建MainActivity,添加native方法:
package com.jackie.hellondk; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { public native String getStringFromNative(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }注意,我用到了v7兼容包下的AppCompatActivity,下面編譯頭文件時,可能會用到這點知識。然後,一定要點擊下方的綠色箭頭,make project,確保生成了.class文件。
2. 在main目錄下創建一個jni目錄,用來放頭文件,可以用下面的方法:
3. 編譯頭文件
在Terminal中進入到項目的根目錄,對於Android Studio來說,切換到app\src\main就行,按照網上的說法,直接執行下面的命令:
javah -d jni com.jackie.hellondk.MainActivity(-d jni 指定頭文件生成在jni目錄下,如果沒有第二步創建jni文件夾,也會自動創建)
很明顯,找不到MainActivity的.class字節碼文件,然後按照官網的方法,指定MainActivity.class的路徑,在Android Studio中,所有的.class文件都生成在app\build\intermediates\classes\debug下面,所以,執行下面的命令:
javah -classpath ..\..\build\intermediates\classes\debug-d jni com.jackie.hellondk.MainActivity
這是什麼原因呢?這是由於我們上面的MainActivity繼承了AppCompatActivity,這個類是在Android v7的兼容包下,所以還需要v7的兼容包加入到classpath中:
javah -classpath D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity
同樣,也需要將v4的兼容包加入到classpath中:
javah -classpathD:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity
無語了,真是處處都是坑啊,繼續把android.jar添加到classpath中呗!
javah -classpathD:\DevTools\studio_sdk\platforms\android-23\android.jar;D:\DevTools\studio_sdk\extras\android\support\v4\android-support-v4.jar;D:\DevTools\studio_sdk\extras\android\support\v7\appcompat\libs\android-support-v7-appcompat.jar;..\..\build\intermediates\classes\debug -d jni com.jackie.hellondk.MainActivity
終於成功生成了頭文件,如下:
注意,我上面之所以需要添加如此多的classpath,是由於我用到AppCompatActivity,一般情況下只需要將android.jar和.class文件的目錄(app\build\intermediates\classes\debug)添加到classpath中就行,在實際開發中,如果大家出現找不到類的錯誤,請自行添加classpath就行,注意,中間用分號隔開。另外,如果覺得每次敲這麼多命令太麻煩,也可以將上面的classpath配置到系統的環境變量中,至於怎麼弄,相信大家都OK啦!這裡不作詳細講述。
4. 實現native方法
在jni目錄新建一個hello.c文件,實現頭文件中的方法:
#include5. 編寫Android.mk文件#include #include "com_jackie_hellondk_MainActivity.h" JNIEXPORT jstring JNICALL Java_com_jackie_hellondk_MainActivity_getStringFromNative (JNIEnv *env, jclass jclass) { return (*env)->NewStringUTF(env, "Hello from JNI"); }
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c include $(BUILD_SHARED_LIBRARY)
6. 編譯動態鏈接庫so,注意要切換到jni所在的目錄,執行ndk-build之前,還需要配置環境變量。
生成目錄如下:
6. 引用
package com.jackie.hellondk; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.widget.TextView; public class MainActivity extends AppCompatActivity { static { System.loadLibrary("hello"); } TextView mTextView; public native String getStringFromNative(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView.setText(getStringFromNative()); } }編譯會出現下面的錯誤:
在gradle.properties添加下面一句:
android.useDeprecatedNdk=true
繼續編譯,錯誤如下:
配置如下:
編譯後,安裝完成後,還是會出現java.lang.UnsatisfiedLinkErrorcouldn't find libhello.so的錯誤。
修改build.gradle配置,在defaultConfig裡面新增一下代碼:
ndk {
moduleName "hello"
abiFilters "armeabi", "armeabi-v7a", "x86"
}
注意,這裡的moduleName一定要和System.loadLibrary以及Android.mk中定義的名稱一致。
最後一次運行,終於看到了久違的界面啊!
走了很多彎路,真是處處都是坑,做個記錄,希望對你們有所幫助。最後說一點,上面用ndk-build來編譯生成動態鏈接庫libhello.so,然後在Java中通過loadLibrary來加載。在實際開發過程中,完全可以省去ndk-build這一步,開發好jni程序後,直接運行程序,Android Studio會自動幫我們編譯動態鏈接庫,親測成功!
二、打印log信息
相信很多人在剛開始學習Android JNI編程的時候,需要輸出Log,於是按照下面的方法修改hello.c文件:
#include然後修改Android.mk文件:#include #include "com_jackie_hellondk_MainActivity.h" #include #define TAG "Jackie" #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__) JNIEXPORT jstring JNICALL Java_com_jackie_hellondk_MainActivity_getStringFromNative (JNIEnv *env, jclass jclass) { LOGV("log from native"); /** * c語言 */ return (*env)->NewStringUTF(env, "Hello from JNI"); /** * C++ * return env->NewStringUTF("Hello from JNI"); */ }
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := hello.c # for logging LOCAL_LDLIBS += -llog include $(BUILD_SHARED_LIBRARY)
運行時,總是出現undefined reference to '__android_log_print'的錯誤,有的同學可能很奇怪,Android.mk文件和android/log.h頭文件都引入了,怎麼還會有這個錯呢?
Android Studio的Android.mk是自動生成的,就算修改也是沒用了,實際Android Studio的Android.mk是根據gradle文件生成的,那麼就需要修改gradle文件。如果不修改gradle,直接使用__android_log_print就會報錯。
Error:(36) undefined reference to '__android_log_print'
現在只需要在module的build.gradle中添加下面的代碼即可實現輸出Log:1
添加箭頭的部分,就OK啦!Android Studio下NDK的使用 當我們在開發android程序的過程中,有時候需要應用程序對底層硬件的調用。android官方給我們提供NDK以便於我們
Android 面試題--Activity,android--activity1、什麼是 Activity?Activity是Android組件中最基本也是最為常見用的四
android --多線程下載過程分析 多線程下載文件的過程是: (1)首先獲得下載文件的長度,然後設置本地文件的長度。 HttpURLConnection.getCo
在eclipse中安裝上genymotion插件,eclipsegenymotion1.安裝genymotion-vbox,選擇安裝目錄。 具體安裝過程可見http://