Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android JNI/NDK開發之基本姿勢(一)

Android JNI/NDK開發之基本姿勢(一)

編輯:關於Android編程

開發環境信息

列舉下本篇文章編寫的Demo基本信息
操作系統 Windows 10 家庭中文版 開發工具 Android Studio 2.1 SDK new NDK new

掃盲之SDK、JDK、NDK的區別

SDK 軟件開發工具包;英語全稱:Software Development Kit JDK Java語言的軟件開發工具包;英語全稱:Java Development Kit NDK 原生軟件開發工具包;英語全稱:Native Development Kit;被Google稱為NDK

由此可見,其實不管什麼XDK,都可以叫SDK,可能為了有很好的區分,便有了JDKNDK,所以我們有的時候常說的SDK並不是特指安卓開發工具包,而只是我們都是同行,交流的時候都知道指的是什麼,其實你們會發現,我們常常接三方平台的時候,那些工具包也是叫SDK,但可能我們在交流的時候就會加個前綴,比如:微信分享SDK、支付寶SDK、xxSDK。


學習目標

1.配置NDK環境並學會合理利用Android Studio工具進行NDK的編譯
2.點擊某個按鈕顯示由native方法返回的一段文本信息;java > native
3.點擊某個按鈕調用某個native方法,在由此native方法調用java方法;java > native > java

創建工程並配置NDK路徑

快速利用Android Studio創建一個簡單的Hello Word工程,相信這個大家都已經熟門熟路了,如果你還不知道使用Android Studio,我只能說你太不open了。

配置工程NDK有兩種方法,和配置SDK一模一樣,這裡就說說兩個SDK 1 的配置方法吧

1.直接在local.properties文件中手動配置

ndk.dir=E:\\Android\\sdk\\ndk-bundle   //NDK路徑
sdk.dir=E:\\Android\\sdk   //SDK路徑

2.Open Module Settings
選中工程名,鼠標右鍵>Open Module Settings或直接按下F4功能鍵

sdk-dir


編寫帶有Native方法的類

1.創建JniDemoClass文件並創建一個native方法public native String getHelloWordText(),用來獲取Hello Word文本

public class JniDemo {

    public native String getHelloWordText();

}

編譯含有Native方法的類

javac JniDemo.java

得到JniDemo.class文件後繼續用javah命令編譯JniDemo.class,格式:javah package name + class name,示例:

javah com.jay.ndkdemo.JniDemo

其中com.jay.ndkdemo是此類所在的包名,編譯成功會在當前目錄生成一個*.h文件,這種文件類是C或C++所支持的頭文件類型。內容如下:

/* DO NOT EDIT THIS FILE - it is machine generated */
#include 
/* Header for class com_jay_ndkdemo_JniDemo */

#ifndef _Included_com_jay_ndkdemo_JniDemo
#define _Included_com_jay_ndkdemo_JniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_jay_ndkdemo_JniDemo
 * Method:    getHelloWordText
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_jay_ndkdemo_JniDemo_getHelloWordText
  (JNIEnv *, jobject);

#ifdef __cplusplus
}
#endif
#endif

本文示例生成的名稱叫:com_jay_ndkdemo_JniDemo.h,很明顯,以包名+類名生成一個文件名,我們在工程中創建一個文件夾jni,此目錄與工程中的java目錄同級,並把生成的*.h文件放置到jni文件夾中。

jni


編寫C/C++代碼並實現*.h中聲明的方法

創建*.c*.cpp文件,編寫Code,本文編寫的是*.c文件,也就是采用C語法來實現

#include 

/*
 * Class:     com_jay_ndkdemo_JniDemo
 * Method:    getHelloWordText
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_jay_ndkdemo_JniDemo_getHelloWordText
  (JNIEnv * env, jobject obj)
{
 return (*env)->NewStringUTF(env,"Hello Word From Jni");
}

簡單說下編寫方法:
1.include 下我們前面生成的*.h文件
2.實現*.h中未實現的方法,注意方法名要與*.h中保持一致

到這裡,我們的工作已經完成了90%,剩下的只是配置與調用了


NDK編譯

這個時候我們就要發揮Android Studio工具的方便性了,怎麼利用NDK編譯了?前面我們已經配置好了NDK路徑,那麼直接利用Android Studio的菜單build > Rebuild Project,執行後發現失敗

ndk-build-error

錯誤信息:

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':app:compileDebugNdk'.
> Error: NDK integration is deprecated in the current plugin.  Consider trying the new experimental plugin.  For details, see http://tools.android.com/tech-docs/new-build-system/gradle-experimental.  Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration.

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

其實這個錯誤信息中已經告訴我們怎麼解決

Set "android.useDeprecatedNdk=true" in gradle.properties to continue using the current NDK integration

叫我們在gradle.properties文件中輸入android.useDeprecatedNdk=true,輸入後我們再次編譯,這次編譯成功,但發現一個警告:

ndk-build-warning

警告信息:

Warning: Native C/C++ source code is found, but it seems that NDK option is not configured.  Note that if you have an Android.mk, it is not used for compilation.  The recommended workaround is to remove the default jni source code directory by adding: 
 android {
    sourceSets {
        main {
            jni.srcDirs = []
        }
    }
}
to build.gradle, manually compile the code with ndk-build, and then place the resulting shared object in src/main/jniLibs.

大概意思就是我們缺少一個文件:Android.mk,但人家給了我們推薦的方法,那就是在對應module工程中的build.gradle文件中添加如下代碼:

sourceSets {
    main {
        jni.srcDirs = []
    }
}

添加後我們再次編譯,這次編譯成功並沒錯誤也沒警告,終於NDK編譯通過了,我們查看編譯結果:\NdkDemo\app\build\intermediates\ndk

ndk-build-result

我們可以看到,生成了一系列的*.so文件,是不是感覺很熟悉了?但我們發現*.so文件名叫libapp.so,這個文件名是怎麼來的了?可以更改嗎?答案是肯定的。

先說說默認文件名的生成格式:lib + module name.so

更改默認文件名名稱:

android {
    ......
    defaultConfig {
        ......
        ndk {
            moduleName 'jnidemo'//自定義名稱
        }
    }
}

好,我們再次編譯,編譯完成後我們查看編譯路徑下,悶B了吧,沒看到ndk目錄了,有人就會說了,你這個坑貨,騙人的,友誼的小船說翻就翻。

sourceSets {
    main {
//      jni.srcDirs=[]
      jniLibs.srcDir 'src/main/jni_src'//告知jni源碼目錄
    }
}

還記得這個配置不,對,就是我們之前第一次編譯的時候解決一個警告按照警告的推薦寫的配置代碼,只要改成和上面一樣,編譯後就又可以看到編譯目錄下的ndk文件夾了,查看編譯後的*.so文件,發現文件名已經改了,並且生成的格式和我之前說的一樣。

為什麼我們按照推薦方法會有問題了?
1.可能是bug
2.我覺得應該是我們既然了默認的一些參數,當然就要對其它參數做出相應的修改


好了,看完這篇文章,我們基本實現了我們的學習目標的第一點,後面兩點請看後續系列文章


  • 此處SDK包含NDK與安卓SDK ?
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved