今天說一下 studio ndk開發的環境搭建。相比之下比eclipse的簡化了許多,不需要麻煩的步驟。
先簡單說下環境搭建:
環境只需要安裝ndk就好。
如果沒有ndk,按照下面步驟。
其中ndk目錄是在sdk目錄下的 ndk-bundle下。一路next finish行了。
如果已經有ndk,配置上就可以了。
《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《《
配置完畢ndk正式開始例程。
總共分三個步驟
- 創建工程,修改工程配置
- 寫本地方法名,生產頭文件(如果需要)
編寫c/c++代碼
其中生產頭文件 不是必須。但推薦還是生產。頭文件包含方法的前面,自己寫很容易搞錯,非常容易寫錯。。。
正式開始
第一部創建配置工程
1.先創建一個model。檢查下local.properties文件是有了ndk目錄
ndk.dir=D:\Programming\Sdkstudiedo\ndk-bundle
sdk.dir=D:\Programming\Sdkstudiedo
沒有檢查ndk目錄。
2修改build.gradle。需要修改三處。
1)project的build.gradle
2)model的build.gradle
3)project的 gradle\wrapper\gradle-wrapper.properties
如圖
首先說project的build.gradle。
修改 classpath
classpath 'com.android.tools.build:gradle-experimental:0.2.0'。
如圖。
其次修改 project的gradle-wrapper.properties。修改distributionUrl=https://services.gradle.org/distributions/gradle-2.5-all.zip
如圖。
最後需要修改model的build.gradle。 挺多的
apply plugin: 'com.android.model.application'
model {
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.2"
tasks.withType(JavaCompile) {
//指定編譯JDK版本
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
defaultConfig.with {
applicationId = "cn.jni.com.jnidemo"
minSdkVersion.apiLevel = 19
// Unable to load class com.android.build.gradle.managed.ProductFlavor_Impl
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
android.ndk {
moduleName = "test"
ldLibs +="log"
abiFilters +="armeabi"
abiFilters +="armeabi-v7a"
abiFilters +="x86"
cppFlags += "-std=c++11"
cppFlags += "-fexceptions"
cppFlags += "-I${file("src/main/jni//include")}".toString()
ldLibs += ["android", "log"]
stl = "gnustl_shared"
}
android.productFlavors {
create("arm7") {
ndk.abiFilters.add("armeabi-v7a")
}
create("arm8") {
ndk.abiFilters.add("arm64-v8a")
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.0'
}
注意區別
1apply plugin: ‘com.android.application’改爲
apply plugin: ‘com.android.model.application’;
2.原來的 xxx : xx改爲xxx = ;
3.android目錄外層多了一層model
4.有些從android提出來了。結構改變
建議直接複製上面的,修改一下工程名字和庫名字直接用就行。
applicationId 和moduleName 修改。
修改完文件,進行第二步驟
第二步,創建本地方法,生產頭文件
1.首先新建一個java類,名字叫做。JniUtils
public class JniUtils {
static {
System.loadLibrary("test");//之前在build.gradle裏面設置的so名字,必須一致
}
public static native String getStringFormC();
}
其中靜態代碼塊裏面的是加載so庫,名字與model的build.gradle配置的 android.ndk 下面的 moduleName = “test”必須一樣。
然後聲明方法,方法比普通java方法多了native。
2.生產頭文件。由於方法名非常長非常噁心,容易寫錯,建議生產頭文件來copy方法簽名就行。
首先創建jni目錄,
然後使用javah 命令來生產頭文件。
javah -d 生產頭文件存放目錄 java類包名
比如我現在在main下面的java文件夾裏面,那我運行
javah -d ../jni cn.jni.com.jnidemo.JniUtils
就會在jni下生成。h了。studio裏面有控制檯,和cmd一樣。
最後一步編寫本地方法就行了
在jni目錄下新建一個c文件,名字隨意,打開剛纔生產的.h,然後複製剛纔的函數聲明。
JNIEXPORT jstring JNICALL Java_cn_jni_com_jnidemo_JniUtils_getStringFormC
(JNIEnv *, jclass);
方法名字就是很長。所以還是生成頭文件安全一點。
然後再。c文件裏面包含這個頭文件和jni.h,定義這個函數就可。代碼如下:
#include<jni.h>
#include"cn_jni_com_jnidemo_JniUtils.h"
JNIEXPORT jstring JNICALL Java_cn_jni_com_jnidemo_JniUtils_getStringFormC (JNIEnv *env, jobject obj){
return (*env)->NewStringUTF(env,"String from c");
}
這樣步驟都寫完了。只要在java層調用就行了
在activity裏面掉用和本地方法一樣
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView textView = (TextView) findViewById(R.id.tv);
textView.setText(JniUtils.getStringFormC());
}
}
經過以上三個步驟就完成了java調用c方法。運行結果
demo地址:http://download.csdn.net/detail/spinchao/9523830
下面發現了一種簡便的方法。
直接見一個常規項目,然後,寫本地方法,生產頭文件,比如在main的 java文件夾下執行
javah -d ../jni com.jniexample.spc.helloworld.MainActivity。
就會在main下面創建一個jni目錄,裏面有生產好的h頭文件, 然後再項目的build.gradle裏面配置一下so庫,在 defaultConfig 裏面配置
ndk{
moduleName “MyJni” //設置庫(so)文件名稱
}
然後ok,直接在文件裏面加載so 運行。
這樣還支持instant run。