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);
}
|