02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译
1? 編寫(xiě)以下案例(下面的三個(gè)按鈕都調(diào)用了底層的C語(yǔ)言):
項(xiàng)目案例的代碼結(jié)構(gòu)如下:
2 編寫(xiě)DataProvider的代碼:
| package com.example.ndkpassdata; ? public class DataProvider { ??? ??? /** ??? ?* 計(jì)算x和y的加法? apktools ??? ?* ??? ?* @param x ??? ?* @param y ??? ?* @return ??? ?*/ ??? public native int add(int x,int y); ??? ??? /** ??? ?* 給字符串后面拼接字符串?? 加密運(yùn)算?? web?? url ??? ?* @param s ??? ?* @return ??? ?*/ ??? public native String sayHelloInC(String s); ??? ??? /** ??? ?* 給C代碼傳遞int數(shù)組?? 讓C代碼給這個(gè)數(shù)組進(jìn)行操作 ??? ?* 圖形?? 聲音的處理 ??? ?* ??? ?* @param iNum ??? ?* @return ??? ?*/ ??? public native int[] intMethod(int[] iNum); } |
3 MainActivity的代碼如下:
| package com.example.ndkpassdata; ? import android.annotation.SuppressLint; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Toast; ? public class MainActivity extends Activity { ???????? DataProvider provider; ???????? static{ ?????????????????? System.loadLibrary("hello"); ???????? } ???????? ???????? @Override ???????? protected void onCreate(Bundle savedInstanceState) { ?????????????????? super.onCreate(savedInstanceState); ?????????????????? setContentView(R.layout.activity_main); ?????????????????? provider=new DataProvider(); ???????? } ???????? ???????? @SuppressLint("ShowToast") ???????? public void click1(View view){ ?????????????????? int result=provider.add(3, 5); ?????????????????? Toast.makeText(getApplicationContext(), "provider.add(3, 5) = " + result, 0).show(); ???????? } ???????? ???????? @SuppressLint("ShowToast") ???????? public void click2(View view){ ?????????????????? String str=provider.sayHelloInC("yll"); ?????????????????? Toast.makeText(getApplicationContext(), str, 0).show(); ???????? } ???????? ???????? public void click3(View view){ ?????????????????? int[] arr=new int[]{1,2,3,4,5}; ?????????????????? provider.intMethod(arr); ?????????????????? for(int i:arr){ ??????????????????????????? System.out.println(i); ?????????????????? } ???????? } } |
4 通過(guò)DataProvider生成C語(yǔ)言的頭文件
進(jìn)入/cygdrive/e/workspace/Android/NdkPassData/src目錄下:
查看DataProvider的全路徑:
在項(xiàng)目中生成頭文件
頭文件的內(nèi)容如下:
| /* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class com_example_ndkpassdata_DataProvider */ ? #ifndef _Included_com_example_ndkpassdata_DataProvider #define _Included_com_example_ndkpassdata_DataProvider #ifdef __cplusplus extern "C" { #endif /* ?* Class:???? com_example_ndkpassdata_DataProvider ?* Method:??? add ?* Signature: (II)I ?*/ JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add ? (JNIEnv *, jobject, jint, jint); ? /* ?* Class:???? com_example_ndkpassdata_DataProvider ?* Method:??? sayHelloInC ?* Signature: (Ljava/lang/String;)Ljava/lang/String; ?*/ JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC ? (JNIEnv *, jobject, jstring); ? /* ?* Class:???? com_example_ndkpassdata_DataProvider ?* Method:??? intMethod ?* Signature: ([I)[I ?*/ JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod ? (JNIEnv *, jobject, jintArray); ? #ifdef __cplusplus } #endif #endif |
5 在項(xiàng)目下創(chuàng)建一個(gè)文件夾jni,將上面生成的頭文件拷貝到這個(gè)文件夾下:
然后按照頭文件,編寫(xiě)hello.c,hello.c的代碼如下:
| #include <stdio.h> #include "com_example_ndkpassdata_DataProvider.h" #include <android/log.h> #include <string.h> #define LOG_TAG "clog" #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) ? /** ?* 將Java中的字符串轉(zhuǎn)換成為C語(yǔ)言的字符 ?*/ char*?? Jstring2CStr(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(env,jstr,mid,strencode); // String .getByte("GB2312"); ??? ?jsize?? alen?? =?? (*env)->GetArrayLength(env,barr); ??? ?jbyte*?? ba?? =?? (*env)->GetByteArrayElements(env,barr,JNI_FALSE); ??? ?if(alen?? >?? 0) ??? ?{ ??? ? rtn?? =?? (char*)malloc(alen+1);???????? //"\0" ??? ? memcpy(rtn,ba,alen); ??? ? rtn[alen]=0; ??? ?} ??? ?(*env)->ReleaseByteArrayElements(env,barr,ba,0);? // ??? ?return rtn; } ? JNIEXPORT jint JNICALL Java_com_example_ndkpassdata_DataProvider_add ? (JNIEnv * env, jobject jobject, jint x, jint y){ ??? // 想在logcat控制臺(tái)上 打印日志 ??? LOGD("x=%d",x); ??? LOGI("y=%d",y); ??? // log.i(TAG,"sss"); ??? return x+y; } ? JNIEXPORT jstring JNICALL Java_com_example_ndkpassdata_DataProvider_sayHelloInC ? (JNIEnv * env, jobject jobject, jstring str){ ? ??? char* c="hello"; ??? // 在C語(yǔ)言中不能直接操作java中的字符串 ??? // 把java中的字符串轉(zhuǎn)換成c語(yǔ)言中 char數(shù)組 ??? char* cstr=Jstring2CStr(env,str); ? ??? strcat(cstr,c); ??? LOGD("%s",cstr); ??? return? (*env)->NewStringUTF(env,cstr); } ? JNIEXPORT jintArray JNICALL Java_com_example_ndkpassdata_DataProvider_intMethod ? (JNIEnv * env, jobject jobject, jintArray jarray){ ??? // jArray? 遍歷數(shù)組?? jint*?????? (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*); ??? // 數(shù)組的長(zhǎng)度??? jsize?????? (*GetArrayLength)(JNIEnv*, jarray); ??? // 對(duì)數(shù)組中每個(gè)元素 +5 ??? int length=(*env)->GetArrayLength(env,jarray); ??? int* array=(*env)->GetIntArrayElements(env,jarray,0); ??? int i=0; ??? for(;i<length;i++){ ?????? *(array+i)+=5; ??? } ??? return jarray; } |
其中,上面的代碼中使用了NDK中打印日志的庫(kù),Log共享庫(kù)庫(kù)的位置在:
6 編寫(xiě)Android.mk文件,內(nèi)容如下:
| LOCAL_PATH := $(call my-dir) ? include $(CLEAR_VARS) ? #測(cè)試寫(xiě)了lib前綴的情況,如果不加lib,生成.so的時(shí)候回自動(dòng)加上lib前綴 LOCAL_MODULE??? := libhello LOCAL_SRC_FILES := hello.c ? #這里使用C語(yǔ)言打印日志,要引用log的共享庫(kù) #共享庫(kù)的位置在:\android-ndk-r9d\platforms\android-19\arch-arm\usr\lib LOCAL_LDLIBS??? += -llog ? include $(BUILD_SHARED_LIBRARY) |
7 使用ndk-build進(jìn)行交叉編譯:
F5刷新項(xiàng)目,發(fā)現(xiàn)項(xiàng)目下多了:
8? 編寫(xiě)布局文件:
| <RelativeLayout 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" ??? tools:context=".MainActivity" > ? ??? <TextView ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content" ??????? android:layout_centerHorizontal="true" ??????? android:layout_centerVertical="true" ??????? android:text="@string/hello_world" /> ? ??? <Button ??????? android:onClick="click1" ??????? android:id="@+id/button1" ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content" ??????? android:layout_alignParentLeft="true" ??????? android:layout_alignParentTop="true" ??????? android:text="C語(yǔ)言實(shí)現(xiàn)第一個(gè)方法" /> ? ??? <Button ??????? android:onClick="click2" ??????? android:id="@+id/button2" ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content" ??????? android:layout_alignParentLeft="true" ??????? android:layout_below="@+id/button1" ??????? android:text="C語(yǔ)言實(shí)現(xiàn)第二個(gè)方法" /> ? ??? <Button ???????? android:onClick="click3" ??????? android:id="@+id/button3" ??????? android:layout_width="wrap_content" ??????? android:layout_height="wrap_content" ??????? android:layout_alignParentLeft="true" ??????? android:layout_below="@+id/button2" ??????? android:text="C語(yǔ)言實(shí)現(xiàn)第三個(gè)方法" /> ? </RelativeLayout> |
9 編寫(xiě)Android清單文件:
| <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" ??? package="com.example.ndkpassdata" ??? android:versionCode="1" ??? android:versionName="1.0" > ? ??? <uses-sdk ??????? android:minSdkVersion="8" ??????? android:targetSdkVersion="19" /> ? ??? <application ???? ???android:allowBackup="true" ??????? android:icon="@drawable/ic_launcher" ??????? android:label="@string/app_name" ??????? android:theme="@style/AppTheme" > ??????? <activity ??????????? android:name="com.example.ndkpassdata.MainActivity" ??????????? android:label="@string/app_name" > ??????????? <intent-filter> ??????????????? <action android:name="android.intent.action.MAIN" /> ? ??????????????? <category android:name="android.intent.category.LAUNCHER" /> ??????????? </intent-filter> ??????? </activity> ??? </application> ? </manifest> |
接下來(lái)運(yùn)行應(yīng)用,就可以看到如下:
同時(shí)注意控制臺(tái),可以打印出日志信息。
?
?
?
總結(jié)
以上是生活随笔為你收集整理的02_JNI中Java代码调用C代码,Android中使用log库打印日志,javah命令的使用,Android.mk文件的编写,交叉编译的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 土鸡怎么样 了解土鸡的特点和饲养方法?
- 下一篇: 03_Android NDK中C语言调用