教育行業(yè)A股IPO第一股(股票代碼 003032)

全國(guó)咨詢(xún)/投訴熱線:400-618-4000

Android培訓(xùn)實(shí)戰(zhàn)教程之 Studio下JNI開(kāi)發(fā)

更新時(shí)間:2015年12月28日15時(shí)22分 來(lái)源:傳智播客Android培訓(xùn)學(xué)院 瀏覽次數(shù):

  一步一步做Android Studio下JNI開(kāi)發(fā)

  Android Studio是Google基于IntelliJ IDEA專(zhuān)門(mén)為Android開(kāi)發(fā)而定制的集成開(kāi)發(fā)環(huán)境。在2013年5月的Google大會(huì)上首次發(fā)布。Goolge宣布2015年底就中止Eclipse官方支持,所以是時(shí)候擁抱Android Studio了。

  先來(lái)看下相關(guān)知識(shí)背景

  1.什么是JNI?

  Java native interface是一種協(xié)議,并提供一套編程框架,讓java和本地語(yǔ)言(C/C++)之間能夠相互調(diào)用。

  2.為什么需要JNI呢?

  Java是一種平臺(tái)無(wú)關(guān)的語(yǔ)言,通過(guò)不同操作系統(tǒng)下具有相同功能的JVM實(shí)現(xiàn)一次編譯,可以到處運(yùn)行。也正是因?yàn)镴VM,使得Java程序運(yùn)行的效率相對(duì)于C/C++等本地語(yǔ)言較低,而且不能像C/C++一樣直接操作底層硬件。因?yàn)镃/C++本地語(yǔ)言編譯程序是直接被操作系統(tǒng)運(yùn)行,而不需要類(lèi)似Java的虛擬機(jī)。

  所以如果Android app需要操作底層硬件,或要求應(yīng)用的運(yùn)行效率,安全性,就可以使用JNI來(lái)實(shí)現(xiàn)java和本地C/C++語(yǔ)言之間的相互調(diào)用。

  3.那什么是NDK呢?

  Native Development Kit 本地開(kāi)發(fā)工具集。簡(jiǎn)單的說(shuō)就是一整套工具,用來(lái)構(gòu)建、編譯本地c/c++源程序,生成.so動(dòng)態(tài)庫(kù),加入本地庫(kù)中,讓Android應(yīng)用程序中Java程序通過(guò)jni調(diào)用。

  JNI和NDK關(guān)系見(jiàn)圖1

文本框: 圖1-JNI和NDK的關(guān)系
 

  4.怎樣進(jìn)行JNI開(kāi)發(fā)呢?

  之前大家使用Eclipse+CDT+NDK進(jìn)行JNI開(kāi)發(fā),轉(zhuǎn)到Android Studio后怎樣來(lái)進(jìn)行JNI開(kāi)發(fā)呢?

  需要指出的是Android Studio當(dāng)前對(duì)NDK的支持還處于測(cè)試階段,還未產(chǎn)生穩(wěn)定的支持。隨著Android Studio版本的升級(jí),開(kāi)發(fā)方式還在變化。本文使用的環(huán)境是Android Studio1.4穩(wěn)定版,gradle 2.4。

  下面就通過(guò)一個(gè)簡(jiǎn)單的例子介紹怎樣用Android Studio進(jìn)行JNI開(kāi)發(fā)。

  先上效果見(jiàn)圖2

  例子很簡(jiǎn)單,android應(yīng)用程序TestJni中java借助JNI調(diào)用本地C函數(shù),獲得一個(gè)字符串,并用Toast提示在界面上。

  step1:首先新建一個(gè)Module模塊,TestJni,新建一個(gè)包c(diǎn)om.itheima.jni

  ,和一個(gè)專(zhuān)門(mén)存放本地方法的類(lèi)JNI。然后用native關(guān)鍵字聲明本地方法helloFromC

  package com.itheima.jni; /** * Created by tim on 2015/12/15. */ public class JNI {

  //本地方法獲得字符串,本地方法由c/c++實(shí)現(xiàn) public static native String helloFromC(); }

  step2:在MainActivity類(lèi)中調(diào)用JNI類(lèi)中的本地方法,獲得字符串,并用Toast打印輸出

  package com.itheima.testjni; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import

  android.widget.Toast; import com.itheima.jni.JNI; public class MainActivity extends AppCompatActivity {

  @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main); JNI jni = new JNI(); Toast.makeText(this, jni.helloFromC(), Toast.LENGTH_SHORT).show(); } }

  step3:在testjni模塊中新建存放c源文件的jni文件夾

step4:在jni文件夾下新建c/c++源文件,這里新建了hello-jni.h和hello-jni.c

可選.c/.h用C語(yǔ)言實(shí)現(xiàn),或者.cpp/.h用C++語(yǔ)言實(shí)現(xiàn)
新建完成后得到hello-jni.c源文件和相關(guān)的hello-jni.h頭文件
 
 
step5: 編譯一下module testini,生成.class字節(jié)碼文件,進(jìn)入testjni\build\intermediates\classes\debug目錄下,在Terminal窗口利用javah命令生成jni相關(guān)頭文件

 
 
Terminal窗口中執(zhí)行命令> javah    存放JNI類(lèi)的包名.JNI類(lèi)名

 
生成com_itheima_jni_JNI.h頭文件,將這個(gè)頭文件拷貝到j(luò)ni文件夾下
 
在hello-jni.c文件開(kāi)頭包含生成的頭文件com_itheima_jni_JNI.h
#include "com_itheima_jni_JNI.h" //包含生成的頭文件
并將com_itheima_jni_JNI.h頭文件中,本地方法對(duì)應(yīng)函數(shù)聲明拷貝到hello-jni.c文件中,方便下一步來(lái)實(shí)現(xiàn)這個(gè)函數(shù)
step6:實(shí)現(xiàn)本地方法相應(yīng)的Java_com_itheima_jni_JNI_helloFromC函數(shù)功能,返回一個(gè)Java中的String字符串對(duì)象
 

  JNIEXPORT jstring JNICALL Java_com_itheima_jni_JNI_helloFromC

  (JNIEnv * env, jclass obj){

  char buf[] = "Hello world from C!";

  //env調(diào)用struct JNINativeInterface中的函數(shù)指針

  //實(shí)現(xiàn)轉(zhuǎn)換c里面的char *字符串為java中的String對(duì)象

  return (*env)->NewStringUTF(env, buf); }

 
step7:需要給Android Studio指定NDK路徑
 
step8:在module的build.gradle文件中指定生成的.so動(dòng)態(tài)庫(kù)名hello-jni,這個(gè)庫(kù)名需要在JNI類(lèi)中加載

  在defaultConfig{}中添加ndk{}

  defaultConfig { applicationId "com.itheima.testjni" minSdkVersion 10 targetSdkVersion 23 versionCode 1 versionName "1.0" ndk{ //指定生成模塊名字,也就是最終的動(dòng)態(tài)庫(kù)名hello-jni,相應(yīng)庫(kù)文件名libhello-jni.so moduleName "hello-jni" //指定生成哪些處理器架構(gòu)的動(dòng)態(tài)庫(kù)文件,如果要運(yùn)行在x86架構(gòu)處理器一定需要指定 abiFilters "armeabi" , "x86" } }

  step9:在JNI類(lèi)中加載動(dòng)態(tài)庫(kù)

  package com.itheima.jni; /** * Created by tim on 2015/12/15. */ public class JNI { static{ //指定庫(kù)名,加載動(dòng)態(tài)庫(kù),需要和build.gradle中指定的庫(kù)名一致 System.loadLibrary("hello-jni"); } //本地方法獲得字符串,本地方法由c/c++實(shí)現(xiàn) public static native String helloFromC(); }

  step10:編譯這個(gè)模塊


  等待結(jié)果......結(jié)果,納尼?編譯報(bào)錯(cuò)了!

  Error:(14, 1) A problem occurred evaluating project ':testjni'.

  > 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.

  淡定!

  仔細(xì)一讀,原來(lái)是NDK集成在當(dāng)前Gradle插件中棄用,建議用新的實(shí)驗(yàn)性插件,或者在工程中g(shù)radle.proerties中設(shè)置android.useDeprecatedNdk=true

  ok照辦。


再次編譯成功,部署到模擬器上看效果
 
流程到此結(jié)束。
后面再更實(shí)驗(yàn)性gradle插件開(kāi)發(fā)jni時(shí)有多強(qiáng)大!
 
 
 

參考:

https://zh.wikipedia.org/wiki/Android_Studio

本文版權(quán)歸傳智播客Android培訓(xùn)學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!
作者:傳智播客Android培訓(xùn)學(xué)院
首發(fā):http://oisangadgets.com/android/
0 分享到:
和我們?cè)诰€交談!