Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Studio NDK開發

Android Studio NDK開發

編輯:關於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文件,實現頭文件中的方法:

#include 
#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");
}
5. 編寫Android.mk文件
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 
#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");
    */
}
然後修改Android.mk文件:
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啦!
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved