c知識html
stdlib 頭文件即standard library標準庫頭文件 經常使用系統函數,跟系統調用相關的,好比內存申請malloc和釋放free
stdio是標準io函數,好比printf和scanf函數
windows和linux文件區別
windows .exe .dll .batjava
linux .elf .so .shlinux
x86對 jni兼容性能不好android
因爲ndk一開始是作給linux下用的,全部wind下用ndk會有不少問題。
因此還要裝個軟件 cygwin
只要裝2個功能 devel shellsshell
ndk環境變量設置windows
windows下 1.直接解壓縮ndk,而後搭建環境變量. 在path目錄下面C:\android-ndk-r7b . 這是直接在cmd命令行下運行 ndk-buildapp
Cygwin Terminal下 這個配置環境變量在 cygwin/etc/profile的32行ide
/cygdrive/c/android-ndk-r7b 把這個添加 不一樣ndk的安裝路徑不同函數
每一個環境變量用:分隔.工具
在cygwin下配置了環境便利ndk可是在別的目錄 運行ndk-build一直找不到目錄 .
執行./ndk-build -C samples/hello-jni 這個代碼可解決 博客:http://blog.sina.com.cn/s/blog_4c73bcc80101177e.html
Jni.h 目錄:C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\include
log.h目錄:C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\include\android
實現步驟
1 定義一個c方法的接口 至關於在java代碼中定義了一個接口 接口的實現方法是C語言實現的
2 步 實現C代碼
3步驟 建立android.mk 告訴編譯器 如何把c代碼打包成函數庫
4步 把c代碼 打包成函數庫 用到了安裝的環境 經過cygwin terminal
5 步在java代碼中 引入庫函數
static{
System.loadLibrary("hello");// 注意事項 去掉前面的lib 後面的.so
}
6 使用方法
Anroid.mk 文件
LOCAL_PATH := $(call my-dir) // 返回當前c代碼目錄
include $(CLEAR_VARS) // 清楚了全部 已local 開頭的配置文件 惟獨不清楚LOCAL_PATH
LOCAL_MODULE := hello // 庫函數的名字 嚴格遵照makefile 格式 lib .so 若是前面加lib 不會自動生成了
LOCAL_SRC_FILES := Hello.c
include $(BUILD_SHARED_LIBRARY) // 加入庫函數
jni 常見的錯誤
1錯誤1 忘記方法的參數
2 錯誤2 203-28 03:41:56.758: E/AndroidRuntime(821): java.lang.UnsatisfiedLinkError: Native method not found: com.example.error.DemoActivity.helloWorld:()Ljava/lang/String; 方法名錯誤
3 錯誤3 通常沒有日誌打印 直接報錯工程中止 通常c代碼有運行錯誤
4 錯誤4 在交叉編譯的工具鏈上報錯 c代碼有編譯錯誤 好比 一些函數沒有聲明 一些類型沒有聲明 少符號
5 錯誤5 沒有Android.mk 文件
6 錯誤6 Android.mk 文件有錯
7 錯誤7 引用別人.so 函數庫 須要你本身native方法對應類的包名 和以前打包成.so函數庫的包名一致
使用javah時 有時一直報錯:找不到類文件 要添加環境變量classpath
把安卓adt adt\adt\adt-bundle-windows-x86_64-20140702\sdk\platforms\android-10
這個目錄下的android.jar 解壓出來.而後把這個目錄放在classpath裏面加入
例: classpath:.;D:\Program Files\Android\android-sdk\platforms\android-8\android
而後到src目錄下 javah 包名.類名. 若是報錯找不到類文件就到 bin/classes下
獲取方法簽名:
使用javap -s 獲取內部類型簽名 這個在反射方法時候要用到
在bin/classes 下執行:javap -s 包名.類名字
1
|
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )<br>解釋:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
可變參數宏 ...和__VA_ARGS_ _
__VA_ARGS__ 是一個可變參數的宏,不多人知道這個宏,這個可變參數的宏是新的C99規範中新增的,目前彷佛只有gcc支持(VC6.0的編譯器不支持)。
實現思想就是宏定義中參數列表的最後一個參數爲省略號(也就是三個點)。這樣預約義宏_ _VA_ARGS_ _就能夠被用在替換部分中,替換省略號所表明的字符串。好比:
#define PR(...) printf(__VA_ARGS__)
int
main()
{
int
wt=1,sp=2;
PR(
"hello\n"
);
PR(
"weight = %d, shipping = %d"
,wt,sp);
return
0;
}
輸出結果:
hello
weight = 1, shipping = 2
省略號只能代替最後面的宏參數。
#define W(x,...,y)錯誤!
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
把java裏的string轉成c裏面的
char
*
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;
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
經過反射 調用java代碼 原理同樣
java裏面的反射
Class<?> forName = Class.forName(
"com.example.ndkcallback.DataProvider"
);
Method declaredMethod = forName.getDeclaredMethod(
"helloFromJava"
,
new
Class[]{});
declaredMethod.invoke(forName.newInstance(),
new
Object[]{});
c裏面反射java
///jclass (*FindClass)(JNIEnv*, const char*);
jclass clazz=(*env)->FindClass(env,
"com/example/ndkcallback/DataProvider"
);
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
// 方法簽名 參數和返回值
jmethodID methodId=(*env)->GetMethodID(env,clazz,
"helloFromJava"
,
"()V"
);
// void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallVoidMethod(env,jobject,methodId);
|
第一個:helloworld
建立jni目標.
建立Hello.c
#include<stdio.h> #include<jni.h> jstring Java_com_example_myhello_MainActivity_helloworldFromc(JNIEnv* env,jobject obj){ return (*env)->NewStringUTF(env,"onehello"); }
建立Android.mk
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hello LOCAL_SRC_FILES := Hello.c include $(BUILD_SHARED_LIBRARY)
而後activity裏面加載library
package com.example.myhello; import android.app.Activity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.widget.Toast; public class MainActivity extends Activity { public native String helloworldFromc(); static{ System.loadLibrary("hello"); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void click(View view) { // TODO Auto-generated method stub Toast.makeText(getApplicationContext(), helloworldFromc(), 0).show(); } }
c代碼調用java代碼事例
要調用的方法
1
2
3
4
5
6
7
|
package
com.example.threehello;
public
class
DataProvider {
public
native
int
add(
int
x,
int
y);
public
native
String sayHello(String s);
public
native
int
[] intMethod(
int
[]iNum);
}
|
在c裏面的實現
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
|
#include <stdio.h>
#include <com_example_threehello_DataProvider.h>
#include <android/log.h> //調用java代碼log的時候導入這個頭文件
#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__ )
char
* Jstring2CStr(JNIEnv* env, jstring jstr)
//java裏的string轉 c的char*
{
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_threehello_DataProvider_add
(JNIEnv * env, jobject jobject, jint x, jint y){
LOGD(
"x=%d"
,x);
LOGI(
"y=%d"
,y);
return
x+y;
}
JNIEXPORT jstring JNICALL Java_com_example_threehello_DataProvider_sayHello
(JNIEnv * env, jobject jobject, jstring str){
//jstring NewStringUTF(const char* bytes)
char
*c=
"hello"
;
char
*strs = Jstring2CStr(env,str);
strcat
(strs,c);
LOGD(
"%s"
,strs);
return
(*env)->NewStringUTF(env,strs);
}
JNIEXPORT jintArray JNICALL Java_com_example_threehello_DataProvider_intMethod
(JNIEnv * env, jobject jobject, jintArray jarray){
// jsize (*GetArrayLength)(JNIEnv*, jarray);
// jint* (*GetIntArrayElements)(JNIEnv*, jintArray, jboolean*);
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;
}
|
c代碼調用java代碼 log
先導入 頭文件 : #include <android/log.h>
在 Android.mk 裏面加入 LOCAL_LDLIBS += -llog 這個動態連接庫在C:\android-ndk-r7b\platforms\android-14\arch-arm\usr\lib 目錄下
c代碼回調java代碼
事例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package
com.example.fourhello;
public
class
DataProvider {
public
void
helloFromJava(){
System.out.println(
"haha我被調用了"
);
}
public
int
Add(
int
x,
int
y){
int
result = x+y;
System.out.println(result);
return
result;
}
public
void
printString(String s){
System.out.println(s);
}
public
native
void
callMethod1();
public
native
void
callMethod2();
public
native
void
callMethod3();
}
|
至關於java的反射
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#include<stdio.h>
#include<string.h>
#include<com_example_fourhello_DataProvider.h>
JNIEXPORT
void
JNICALL Java_com_example_fourhello_DataProvider_callMethod1
(JNIEnv * env, jobject jobject){
//jclass (*FindClass)(JNIEnv*, const char*);
// jmethodID (*GetMethodID)(JNIEnv*, jclass, const char*, const char*);
//void (*CallVoidMethod)(JNIEnv*, jobject, jmethodID, ...);
jclass clazz = (*env)->FindClass(env,
"com/example/fourhello/DataProvider"
);
jmethodID methodID = (*env)->GetMethodID(env,clazz,
"helloFromJava"
,
"()V"
);
(*env)->CallVoidMethod(env,jobject,methodID);
}
JNIEXPORT
void
JNICALL Java_com_example_fourhello_DataProvider_callMethod2
(JNIEnv * env, jobject jobject){
jclass clazz = (*env)->FindClass(env,
"com/example/fourhello/DataProvider"
);
jmethodID methodID = (*env)->GetMethodID(env,clazz,
"Add"
,
"(II)I"
);
// jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
(*env)->CallIntMethod(env,jobject,methodID,3,5);
}
JNIEXPORT
void
JNICALL Java_com_example_fourhello_DataProvider_callMethod3
(JNIEnv * env, jobject jobject){
jclass clazz = (*env)->FindClass(env,
"com/example/fourhello/DataProvider"
);
jmethodID methodID = (*env)->GetMethodID(env,clazz,
"printString"
,
"(Ljava/lang/String;)V"
);
// jint (*CallIntMethod)(JNIEnv*, jobject, jmethodID, ...);
//jstring (*NewStringUTF)(JNIEnv*, const char*);
jstring str = (*env)->NewStringUTF(env,
"i do call back"
);
(*env)->CallVoidMethod(env,jobject,methodID,str);
}
|
c代碼調用java 其餘類裏的方法
1
2
3
4
5
6
7
|
public
class
MainActivity
extends
Activity {
public
void
hellocall(){
System.out.println(
"main activity callback"
);
}
}
|
1
2
3
4
5
6
7
8
|
JNIEXPORT
void
JNICALL Java_com_example_fourhello_DataProvider_callMethod4
(JNIEnv * env, jobject j){
jclass clazz = (*env)->FindClass(env,
"com/example/fourhello/MainActivity"
);
jmethodID methodID = (*env)->GetMethodID(env,clazz,
"hellocall"
,
"()V"
);
//jobject (*AllocObject)(JNIEnv*, jclass); 獲取jobject對象
jobject jj = (*env)->AllocObject(env,clazz);
(*env)->CallVoidMethod(env,jj,methodID);
}
|
c代碼回調java的靜態方法
1
2
3
|
public
static
void
mystatic(){
System.out.println(
"呵呵我是靜態方法"
);
}
|
1
2
3
4
5
6
7
8
|
JNIEXPORT
void
JNICALL Java_com_example_fourhello_DataProvider_callMethod5
(JNIEnv * env, jobject jobject){
jclass clazz = (*env)->FindClass(env,
"com/example/fourhello/DataProvider"
);
// jmethodID (*GetStaticMethodID)(JNIEnv*, jclass, const char*, const char*);
jmethodID methodID = (*env)->GetStaticMethodID(env,clazz,
"mystatic"
,
"()V"
);
// void (*CallStaticVoidMethod)(JNIEnv*, jclass, jmethodID, ...);
(*env)->CallStaticVoidMethod(env,clazz,methodID);
}
|
jni在項目開發的用途 經過jni直接調用c方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
package
com.example.fivehello;
import
android.app.Activity;
import
android.os.Bundle;
import
android.view.Menu;
import
android.view.MenuItem;
import
android.view.View;
import
android.widget.Toast;
public
class
MainActivity
extends
Activity {
static
{
System.loadLibrary(
"hello"
);
}
public
native
int
login(String password);
@Override
protected
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public
void
onclick(View view){
int
login = login(
"123"
);
Toast.makeText(getApplicationContext(), login+
""
,
0
).show();
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
#include<stdio.h>
#include<com_example_fivehello_MainActivity.h>
#include<string.h>
int
login(
char
* psw){
char
* rightword =
"123"
;
int
i =
strcmp
(rightword,psw);
if
(i==0){
return
200;
}
else
{
return
302;
}
}
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_fivehello_MainActivity_login
(JNIEnv * env, jobject jobject, jstring str){
char
*c = Jstring2CStr(env,str);
return
login(c);
}
|