1.AS创建一个Android工程
(1)创建java和c的源文件,配置Cmake
1> 创建一个类名为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> 在src的main目录下面创建一个jni目录,在src/main/jni 下创建一个名bitmap-lib.c的文件,这里.c的命名就是Cmakelists
配置中所引用的文件
3>在app目录下面创建一个名称CMakeLists.txt的文件,内容和如下:
通过配置CMakeLists.txt就可以运用ndk中的cmake环境将bitamp-lib.c编译成android平台的so动态库
项目结构如下图:
(2)在modle的build.gradle中配置ndk
(3)编译工程
2、生成头文件
(1)打开as的Terminal终端,进入到ndk工具类NdkUtils.java所在的文件夹(不带包名的那一级,本示例见上图可知是
D:\WorkPlace\android\qianlifeng\BitampTool\app\src\main\java),注意:一定要到.java文件所在的目录里面,不
然生成头文件会出现各种莫名其妙得问题
执行 cd /
cd WorkPlace\android\qianlifeng\BitampTool\app\src\main\java 切换到如下图所示的路径下: (2)使用javah命令生成c代码的头文件
1>首先看一下javah命令的用法:
2>生成头文件的具体命令(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 目录下面,结构如下:
(3)在bitmap-lib.c文件中编写c代码:
1>导入头文件,把ndkdev_fcw_cn_bitamptool_NdkUtils.h中的方法拷贝过来,加上形参
2>写具体的c代码
示例一:通过java回调c,生成一个制定长度的字串
#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) { }
写Android的界面的逻辑
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动态库的目录:
运行效果如下图:
jni开发中常用的函数jstring和char*之间的相互转换
方法1:利用反射机制
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; }
下一篇 ndk处理bitmap