1.AS创建Android工程
(1)创建java源文件
创建一个类名为Ndkuitls的native工具类
public class NdkUtils {
static {
System.loadLibrary("bitmap-lib");
}
public static native int addByNdk(int m,int n);
public static native String getStringFromNdk(int k);
public static native Bitmap getBitmap();
public static native void doneBitmap(Bitmap bitmap, int r);
public static native void countPixels(int[] img, int w, int h, int r);
}
(2) 创建.c源文件
在src的main目录下面创建一个jni目录,在src/main/jni 下创建一个名bitmap-lib.c的文件
2、配置编译环境
(1)cmake构建文件
在app目录下面创建一个名称CMakeLists.txt的文件,内容和如下:
(2)build.gradle配置
在modle的build.gradle中配置ndk
项目结构如下图:
3、生成头文件
打开as的Terminal终端,进入到ndk工具类NdkUtils.java所在的文件夹(不带包名的那一级,本示例见上图可知是 D:\WorkPlace\android\qianlifeng\BitampTool\app\src\main\java),注意:一定要到.java文件所在的目录里面,不 然生成头文件会出现各种莫名其妙得问题
切换到如下图所示的路径下: 使用javah命令生成c代码的头文件,首先看一下javah命令的用法:
生成头文件的具体命令(javah -classpath ***.jar;. 包名+类名)
javah -classpath C:\sdk\platforms\android-26\android.jar;. ndkdev.fcw.cn.bitamptool.NdkUtils
此处有坑,一定要以上格式写,不然会报错,上面的命令可以分成3块:
执行完指令后会在src\main\java目录下生成一个名为 ndkdev_fcw_cn_bitamptool_NdkUtils.h的文件,将此文件剪切到 src/mian/jni 目录下面,结构如下:
4、编写c源码
在bitmap-lib.c文件中编写c代码,导入头文件,把ndkdev_fcw_cn_bitamptool_NdkUtils.h中的方法拷贝过来,加上形参
#include <jni.h>
#include <string.h>
#include "ndkdev_fcw_cn_bitamptool_NdkUtils.h"
JNIEXPORT jstring JNICALL Java_ndkdev_fcw_cn_bitamptool_NdkUtils_getStringFromNdk
(JNIEnv *env, jclass jb, jint n) {
if (n<0){
char* res="请输入大于0的数据";
return (*env)->NewStringUTF(env,res);
} else{
char *buffer[n];
int i;
for(i=0;i<n;i++){
buffer[i]=i%3==0?"Java":(i%3==1?"回调":"c/c++代码");
}
char res[1024]={0};
char res0[1024]={0};
for(i=0;i<n;i++){
char te[15]={0};
strcat(te,buffer[i]);
strcat(res,te);
}
return (*env)->NewStringUTF(env,strcat(res0,res));
}
}
JNIEXPORT jint JNICALL Java_ndkdev_fcw_cn_bitamptool_NdkUtils_addByNdk
(JNIEnv *env, jclass jb, jint m, jint n) {
}
5、编译工程
MainActivty的布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="ndkdev.fcw.cn.bitamptool.MainActivity">
<EditText
android:inputType="number"
android:maxEms="6"
android:layout_marginTop="10dp"
android:id="@+id/sample_text"
android:layout_width="200dp"
android:layout_height="40dp"
android:text=""
android:layout_gravity="center_horizontal"
/>
<TextView
android:layout_gravity="center_horizontal"
android:background="@color/colorPrimaryDark"
android:textColor="@color/colorAccent"
android:id="@+id/show_tv"
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_width="200dp"
android:minHeight="40dp"
android:layout_height="wrap_content" />
<TextView
android:layout_gravity="center_horizontal"
android:background="@color/colorPrimary"
android:text="点击"
android:id="@+id/done_tv"
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_width="200dp"
android:layout_height="40dp" />
</LinearLayout>
mainactiy的java代码:
public class MainActivity extends AppCompatActivity {
private EditText mSampleText;
private TextView mShowTv;
private TextView mDoneTv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSampleText = (EditText) findViewById(R.id.sample_text);
mShowTv = (TextView) findViewById(R.id.show_tv);
mDoneTv = (TextView) findViewById(R.id.done_tv);
mDoneTv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!TextUtils.isEmpty(mSampleText.getText().toString())){
int i = Integer.parseInt(mSampleText.getText().toString());
String res= NdkUtils.getStringFromNdk(i>0?i:1);
mShowTv.setText(res);
}
}
});
}
}
构建项目生成so动态库的目录:
运行效果如下图:
6、jni反射
jni开发中常用的函数jstring和char*之间的相互转换
jstring charTojstring(JNIEnv* env, const char* pat) {
jclass strClass = (*env)->FindClass(env,"Ljava/lang/String;");
jmethodID ctorID = (*env)->GetMethodID(env,strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = (*env)->NewByteArray(env,strlen(pat));
(*env)->SetByteArrayRegion(env,bytes, 0, strlen(pat), (jbyte*) pat);
jstring encoding = (*env)->NewStringUTF(env,"GB2312");
return (jstring) (*env)->NewObject(strClass, ctorID, bytes, encoding);
}
char* jstringToChar(JNIEnv* env, jstring jstr) {
char* rtn = NULL;
jclass clsstring = (*env)->FindClass(env,"java/lang/String");
jstring strencode = (*env)->NewStringUTF(env,"GB2312");
jmethodID mid = (*env)->GetMethodID(env,clsstring, "getBytes", "(Ljava/lang/String;)[B");
jbyteArray barr = (jbyteArray) (*env)->CallObjectMethod(jstr, mid, strencode);
jsize alen = (*env)->GetArrayLength(env,barr);
jbyte* ba = (*env)->GetByteArrayElements(env,barr, JNI_FALSE);
if (alen > 0) {
rtn = (char*) malloc(alen + 1);
memcpy(rtn, ba, alen);
rtn[alen] = 0;
}
free(rtn);
(*env)->ReleaseByteArrayElements(env,barr, ba, 0);
return rtn;
}