最近在接触 Dex 底层操作时,了解了下 NDK 的开发。
虽然 Android Studio 对于 NDK 开发还是实验性的支持。但是对于我个人入门来说。
我感觉比基于 Eclipse 的 NDK 开发方便很多。
但是当我后面用 JNI 实现的一个 sayHi
的方法之后。
我竟然心里突然觉得 Java 这个语言真是太方便好用了。
然后修改 项目目录的 local.properties
添加 NDK-SDK 的路径配置。
根据安装的位置自行修改路径,如下:
ndk.dir=/Users/youjianame/android-ndk-r10e
修改项目目录下的 build.gradle
编译插件路径,由
classpath com.android.tools.build:gradle:1.3.0
改为
classpath com.android.tools.build:gradle-experimental:0.2.1
app/build.gradle
应用的 DSL 需要的修改会比较大。
由原来生成的:
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
defaultConfig {
applicationId "com.banxi1988.ndk_jni_helloworld"
minSdkVersion 16
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.0'
}
修改为如下:
apply plugin: 'com.android.model.application'
model{
android {
compileSdkVersion = 23
buildToolsVersion = "23.0.1"
defaultConfig.with{
applicationId = "com.banxi1988.ndk_jni_helloworld"
minSdkVersion.apiLevel = 16
targetSdkVersion.apiLevel = 23
versionCode = 1
versionName = "1.0"
}
compileOptions.with{
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
}
compileOptions.with {
sourceCompatibility = JavaVersion.VERSION_1_7
targetCompatibility = JavaVersion.VERSION_1_7
}
android.buildTypes {
release {
minifyEnabled = false
proguardFiles += file('proguard-rules.pro')
}
}
android.ndk{
moduleName = "hello-jni"
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:23.1.0'
}
在应用主包下创建一个 名为 NativeGreetings
的类
如下:
package com.banxi1988.ndk_jni_helloworld;
public class NativeGreetings {
public native String helloWorld();
}
此时将光标停留在 helloWorld
方法名上面,左右会出现一个修复错误的提示。
点击小灯泡之后就会弹出如下修复菜单:
第一个菜单项即是:
Create function Java_com_banxi1988_ndk_1jni_1helloworld_NativeGreetings_helloWorld
选择创建之后就会自动为我们创建相应的 C 函数文件及对应的方法。
为我们创建了如下的文件 app/src/main/jni/nativegreetings.c
#include <jni.h>
JNIEXPORT jstring JNICALL
Java_com_banxi1988_ndk_1jni_1helloworld_NativeGreetings_helloWorld(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, returnValue);
}
下面只是简单的实现如下:
JNIEXPORT jstring JNICALL
Java_com_banxi1988_ndk_1jni_1helloworld_NativeGreetings_helloWorld(JNIEnv *env, jobject instance) {
return (*env)->NewStringUTF(env, "A Hello World Greeting From JNI! ");
}
将 NativeGreetings 类修改如下。增加一个 static 区,在其中加载静态链接库。
库名称即是我们在 android.ndk
中配置的 moduleName
public class NativeGreetings {
public native String helloWorld();
static{
System.loadLibrary("hello-jni");
}
}
NativeGreetings greetings = new NativeGreetings();
TextView greetingsView = (TextView) findViewById(R.id.greetings);
greetingsView.setText(greetings.helloWorld());
运行即可看到效果了。
在 Java 代码中添加一个 sayHi
的方法声明
同时添加一模型字段。如下:
public native String sayHi();
public String firstName;
public String lastName;
public NativeGreetings(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
这个 sayHi
想要实现的是类似下面的效果:
public String sayHi(){
return "Hi, "+this.firstName+" "+this.lastName;
}
下面是对应的 JNI 代码:
JNIEXPORT jstring JNICALL
Java_com_banxi1988_ndk_1jni_1helloworld_NativeGreetings_sayHi(JNIEnv *env, jobject instance) {
jclass class = (*env)->GetObjectClass(env,instance);
jfieldID firstNameID = (*env)->GetFieldID(env,class,"firstName","Ljava/lang/String;");
jfieldID lastNameID = (*env)->GetFieldID(env,class,"lastName","Ljava/lang/String;");
jstring firstName = (*env)->GetObjectField(env,instance,firstNameID);
jstring lastName = (*env)->GetObjectField(env,instance,lastNameID);
jbyte *firstNameBytes = (*env)->GetStringUTFChars(env,firstName,NULL);
jbyte *lastNameBytes = (*env)->GetStringUTFChars(env,lastName,NULL);
char * hi = "Hi, ";
char * greetingChars = malloc(strlen(hi) + strlen(firstNameBytes) + strlen(" ") +strlen(lastNameBytes) + 1);
strcpy(greetingChars,hi);
strcat(greetingChars,firstNameBytes);
strcat(greetingChars," ");
strcat(greetingChars,lastNameBytes);
jstring greeting = (*env)->NewStringUTF(env,greetingChars);
(*env)->ReleaseStringUTFChars(env,firstName,firstNameBytes);
(*env)->ReleaseStringUTFChars(env,lastName,lastNameBytes);
free(greetingChars);
return greeting;
}
1
ylqhust 2015-10-22 22:49:29 +08:00
楼主有没有源码分享一下
|
2
jukka 2015-10-22 23:19:03 +08:00
不用去纠结 android studio, ndk-build , android.mk 走起。
|
3
ybjaychou 2015-10-23 00:47:33 +08:00 via Android
我也是这几天在搞一个串口通讯的,结果老是 tcsetattr 函数报错,后来搞了好久原来是编译的时候需要把版本设置成跟目标机器一样的 SDK 版本才行……之前是直接在 mk 里面写的,现在好像是根据 build.gradle 里面的编译版本来的…
|
4
r00tt 2015-10-23 09:08:55 +08:00
还是喜欢直接写好代码,写好 android.mk 然后 ndk-build
|