一直想了解一下jni的開發流程是怎麼樣子的,剛好最近時間比較充裕,就學習了有關這方面的知識並且借鑑了一些優秀的blog。那爲啥學寫篇文章呢。。。主要是這個不常用,比較容易忘記,方便自己以後查看。當然了,如果能幫助到大家,那就更好了。好的。
接下來分兩步走,第一介紹ndk以及ndk配置,第二,介紹jni的開發流程。
ndk的詳細介紹
在Android developer上關於ndk的描述:The Native Development Kit (NDK) is a set of tools that allow you to leverage C and C++ code in your Android app. You can use it either to build from your own source code, or to take advantage of existing prebuilt libraries.
其大致意思就是:原生開發套件(NDK)是一套工具,使您能夠充分利用C和C++代碼在你的Android應用程序。你可以用它來建立你自己的源代碼,或者是利用現有的lib庫來創建你的應用程序。
ndk的下載,這裏提供了兩種途徑:
1.https://developer.android.com/ndk/downloads/index.html(Android官網)
2.http://www.androiddevtools.cn/(Android鏡像)
在Android Studio上ndk的配置。我用的是Android Studio 2.2 Prerview 6,其ndk可以在線下載,其ndk的配置步驟如下:
ndk的下載
1.進入Default Settings界面設置面板2.選中Android SDK一欄
3.點擊右側的SDK Tools
4.找到LLDB、NDK這兩項,勾選,點擊ok,進行下載。下載時間可能有點長,請耐心等待。(這個需要翻牆)
- ndk的配置
1.在Android Studio中,進入Default Settings -> Tools -> External Tools.
2.右側點擊“+”按鈕,增加編譯命令集成(個人叫法,不準勿怪啊)
3.增加3項編譯命令集成。分別是 javah、ndk-build、ndk-build clean。
4.其詳細添加如下(這個參考了別人的blog):
javah 用於生成頭文件
Program:$JDKPath$/bin/javah
注意:這個命令我加上了-encoding UTF-8 指定編碼,你可以改成你工程的編碼。
Parameters:-encoding UTF-8 -d ../jni -jni $FileClass$
Working directory:$SourcepathEntry$\..\java
ndk-build 用於構建 so 包
注意:MAC/Linux 用 ndk-build,沒有.cmd 後綴,這個是你自己的ndk-build路徑
Program:C:\Develop\Android\sdk\ndk-bundle\ndk-build.cmd
Parameters:什麼都不用填
Working directory:$ModuleFileDir$\src\main
ndk-build clean 清除 so 包
注意:MAC/Linux 用 ndk-build,沒有.cmd 後綴,這個是你自己的ndk-build路徑
Program:C:\Develop\Android\sdk\ndk-bundle\ndk-build.cmd
Parameters:clean
Working directory:$ModuleFileDir$\src\main
好的,到此,ndk的配置就完成了。
jni的開發流程 ##
1.新建一個Android Studio項目TestJniNdkDemo.
2.對TestJniNdkDemo這個項目進行配置。
- 在local.properties裏面加入ndk的路徑:
ndk.dir=C\:\\Users\\Administrator\\AppData\\Local\\Android\\Sdk\\ndk-bundle
在gradle.properties裏面末尾加入
android.useDeprecatedNdk=true
這段代碼在build.gradle(module:app)裏面進行修改
原來的代碼:
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.administrator.testjnindkdemo"
minSdkVersion 21
targetSdkVersion 24
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4'
testCompile 'junit:junit:4.12'
}
修改後的代碼:
//apply plugin: 'com.android.application'
apply plugin: 'com.android.model.application'//修改後的
model{
android {
compileSdkVersion 24
buildToolsVersion "24.0.1"
defaultConfig {
applicationId "com.example.administrator.testjnindkdemo"
minSdkVersion.apiLevel 14 //修改後的
targetSdkVersion.apiLevel 24 //修改後的
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
//新增
ndk {
moduleName "TestJniDemo"
}
buildTypes {
release {
minifyEnabled false
// proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
proguardFiles.add(file("proguard-rules.pro"))//修改後的
}
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:24.1.1'
compile 'com.android.support.constraint:constraint-layout:1.0.0-alpha4'
testCompile 'junit:junit:4.12'
}
- 在build.gradle(Project:TestJniNdkDemo)裏面修改。
原來的代碼:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0-alpha6'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
修改後的代碼:
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
}
dependencies {
// classpath 'com.android.tools.build:gradle:2.2.0-alpha6'
//修改後的代碼,注意最後面的版本,它對應着gradle-wrapper.properties裏面的
//distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip的版本號
/**對應關係如下所示
* Plugin Version | Gradle Version
* 0.1.0 | 2.5
* 0.2.0 | 2.5
* 0.3.0-alpha3 | 2.6
* 0.4.0 | 2.8
* 0.6.0-alpha1 | 2.8
* 0.6.0-alpha5 | 2.10
* 0.7.0-alpha1 | 2.10
* 0.7.0 | 2.10
* 0.7.3 | 2.14.1
* */
classpath "com.android.tools.build:gradle-experimental:0.7.0"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
3.項目配置完成後,進行第一次編譯。
4.創建一個java文件TestJniDemo,其代碼如下:
package com.example.administrator.testjnindkdemo;
/**
* Created by Administrator on 2016/8/19.
*/
public class TestJniDemo {
static {
//加載要使用的 so 文件
System.loadLibrary("TestJniDemo");
}
public static native String helloJni();
}
5.對TestJniDemo這個java類進行編譯。
6.編譯完成後,在cpp(或者是jni)文件夾下會生成一個.h文件。
com_example_administrator_testjnindkdemo_TestJniDemo.h,其內容如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_administrator_testjnindkdemo_TestJniDemo */
#ifndef _Included_com_example_administrator_testjnindkdemo_TestJniDemo
#define _Included_com_example_administrator_testjnindkdemo_TestJniDemo
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_example_administrator_testjnindkdemo_TestJniDemo
* Method: helloJni
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_example_administrator_testjnindkdemo_TestJniDemo_helloJni
(JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif
7.在cpp文件夾(或者是jni文件夾)下創建一個c語言代碼,後綴爲.cpp的TestJni的c代碼。代碼如下:
#include <com_example_administrator_testjnindkdemo_TestJniDemo.h>
JNIEXPORT jstring JNICALL Java_com_example_administrator_testjnindkdemo_TestJniDemo_helloJni
(JNIEnv *env, jclass type) {//該方法來自.h文件裏面的方法
return env->NewStringUTF("jni ndk sucess!!!");
}
8.對項目進行編譯
9.在cpp或者是jni文件下,創建兩個.mk文件。分別是Android.mk、Application.mk。
Android.mk文件內容如下:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := TestJniDemo //這個是build.gradle 裏面設的ndk的moduleName
LOCAL_SRC_FILES := TestJni.cpp //這個是c語言代碼類
include $(BUILD_SHARED_LIBRARY)
Application.mk文件內容如下:
APP_MODULES := TestJniDemo
APP_ABI := all
10.對jni或者是cpp文件夾進行ndk-build編譯。
11.在MainActivity裏面去調用TestJniDemo這個類。實現相應的功能。
代碼如下:
package com.example.administrator.testjnindkdemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv = (TextView) findViewById(R.id.tv);
tv.setText(TestJniDemo.helloJni());
}
}
12.在app上運行,得到正確的結果。
好了,到此爲止,jni的基本開發流程已經走通了。