ksnowlv

回顾过去,总结以往;立足现在,铭记当下;技术为主,笔记而已.

Android通过jni间接调用c++

| Comments

本篇重点内容,C如何调用C++类,思路是JAVA通过JNI直接调用C,C调用C++相关的类。

1.JAVA层接口Person类相关接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class JavaCallJNI {

  static  {
      System.loadLibrary("JNITest");
  }
  
  
  public static native int showValue(int value);
  
  public static native long  createPerson();
  public static native void destroyPerson(long person);
  public static native void setPersonAge(long person,  int age);
  public static native int personAge(long person);
  public static native void setPersonName(long person, String name);
  public static native String  personName(long person);

}

2.C接口及实现

com_ksnowlv_hellojniforjava_JavaCallJNI.h内容如下

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
63
64
65
66
67
68
69
  #include <jni.h>
  /* Header for class com_ksnowlv_hellojniforjava_JavaCallJNI */
  
  #ifndef _Included_com_ksnowlv_hellojniforjava_JavaCallJNI
  #define _Included_com_ksnowlv_hellojniforjava_JavaCallJNI
  #ifdef __cplusplus
  extern "C" {
  #endif
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    showValue
  * Signature: (I)I
  */
  JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_showValue
    (JNIEnv *, jclass, jint);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    createPerson
  * Signature: ()J
  */
  JNIEXPORT jlong JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_createPerson
    (JNIEnv *, jclass);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    destroyPerson
  * Signature: (J)V
  */
  JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_destroyPerson
    (JNIEnv *, jclass, jlong);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    setPersonAge
  * Signature: (JI)V
  */
  JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_setPersonAge
    (JNIEnv *, jclass, jlong, jint);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    personAge
  * Signature: (J)I
  */
  JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_personAge
    (JNIEnv *, jclass, jlong);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    setPersonName
  * Signature: (JLjava/lang/String;)V
  */
  JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_setPersonName
    (JNIEnv *, jclass, jlong, jstring);
  
  /*
  * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
  * Method:    personName
  * Signature: (J)Ljava/lang/String;
  */
  JNIEXPORT jstring JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_personName
    (JNIEnv *, jclass, jlong);
  
  #ifdef __cplusplus
  }
  #endif
  #endif
  

com_ksnowlv_hellojniforjava_JavaCallJNI.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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include "com_ksnowlv_hellojniforjava_JavaCallJNI.h"
#include "PersonExtension.hpp"
#include "JNILog.h"
#include <stdlib.h>
#include <string.h>

JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_showValue
  (JNIEnv * enc, jclass cls , jint value) {

    LOGI("jni value = %d",value);
  value = value + 1;
  LOGI("jni value +1 = %d",value);
    return value;
  }


/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    createPerson
 * Signature: ()Ljava/lang/Object;
 */
JNIEXPORT jlong JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_createPerson
  (JNIEnv *env, jclass cls) {


    void *p = createPerson();

    return (jlong)p;
  }

/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    destroyPerson
 * Signature: (Ljava/lang/Object;)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_destroyPerson
  (JNIEnv *env, jclass cls, jlong o) {

      destroyPerson((void*)o);
  }

/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    setPersonAge
 * Signature: (Ljava/lang/Object;I)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_setPersonAge
  (JNIEnv *env, jclass cls, jlong o, jint value) {
    setPersonAge((void*)o,value);
  }

/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    personAge
 * Signature: (Ljava/lang/Object;)I
 */
JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_personAge
  (JNIEnv *env, jclass cls, jlong o) {
   return personAge((void*)o);
  }

/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    setPersonName
 * Signature: (Ljava/lang/Object;Ljava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_setPersonName
  (JNIEnv *env, jclass cls, jlong o, jstring string) {

    int length1 = (*env)->GetStringLength(env, string);
    const jchar * jcstr = (*env)->GetStringChars(env, string, NULL);


     jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");  //String
     jstring   code   =   (*env)->NewStringUTF(env,"UTF-8"); //"UTF-8"
     jmethodID   methodID   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B"); //getBytes();
     jbyteArray   byteArray =   (jbyteArray)(*env)->CallObjectMethod(env,string,methodID,code);
     jsize   length   =   (*env)->GetArrayLength(env,byteArray);
     jbyte*   bytes   =   (*env)->GetByteArrayElements(env,byteArray,JNI_FALSE);


     if( length > 0){

        char* buf =   (char*)malloc(length+1);         //"\0"
        memcpy(buf,bytes,length);
        buf[length]=0;
        setPersonName((void*)o, buf);
        LOGI("set name = %s",buf);
        free(buf);
     }else{
        setPersonName((void*)o, NULL);
     }

     (*env)->ReleaseByteArrayElements(env,byteArray,bytes,0);  //释放内存空间
  }

/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    personName
 * Signature: (Ljava/lang/Object;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_personName
  (JNIEnv *env, jclass cls, jlong o) {

    LOGI("jni get name");
    const char *name = personName((void*)o);

    if ( name != NULL ) {
        LOGI("jni name = %s",name);
        return  (*env)->NewStringUTF(env,name);
    }else {
        return (*env)->NewStringUTF(env,"");
    }
  }

3.JAVA调用

1
2
3
4
5
6
7
8
9
10
11
int value =  JavaCallJNI.showValue(1);
Log.i("------Android ","" + value);

long p =  JavaCallJNI.createPerson();
JavaCallJNI.setPersonAge(p,10);
int age = JavaCallJNI.personAge(p);
Log.i("------Android ","" + age);
JavaCallJNI.setPersonName(p,"ksnowlv(律威)");
String name = JavaCallJNI.personName(p);
Log.i("------Android ",name);
JavaCallJNI.destroyPerson(p);

4.日志输出

28410-28410/com.ksnowlv.hellojniforjava I/------JNITest: jni value = 1
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------JNITest: jni value +1 = 2
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------Android: 2
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------Android: 10
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------JNITest: set name = ksnowlv(律威)
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------JNITest: jni get name
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------JNITest: jni name = ksnowlv(律威)
2019-04-24 16:42:40.759 28410-28410/com.ksnowlv.hellojniforjava I/------Android: ksnowlv(律威)

Android通过jni调用c++

| Comments

本篇重点内容在于如何把C++的类通过JNI转换为JAVA的类

1.创建JAVA类:JavaPerson

public class JavaPerson {


private long mNativePerson;

public JavaPerson()
{
    mNativePerson = init();
}

public int getAge()
{
    return this.native_getAge(mNativePerson);
}

public void setAge(int age)
{
    native_setAge(mNativePerson, age);
}

public String getName() {
    return native_getName(mNativePerson);
}

public void setName(String name) {
    native_setName(mNativePerson, name);
}


@Override
protected void finalize() throws Throwable {

    if (mNativePerson != 0) {
        finalizer(mNativePerson);
    }

    super.finalize();
}

    static {
        System.loadLibrary("jniPerson");
    }

    private native long  init();
    private native void finalizer(long aPerson);
    private native int native_getAge(long aPerson);
    private native void native_setAge(long aPerson, int age);
    private native String native_getName(long aPerson);
    private native void native_setName(long aPerson, String name);
}

2.通过Terminal生成c++头文件:com_ksnowlv_jnicallc_JavaPerson.h

#ifndef _Included_com_ksnowlv_jnicallc_JavaPerson
#define _Included_com_ksnowlv_jnicallc_JavaPerson
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    init
 * Signature: ()J
 */
JNIEXPORT jlong JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_init
  (JNIEnv *, jobject);

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    finalizer
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_finalizer
  (JNIEnv *, jobject, jlong);

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_getAge
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1getAge
  (JNIEnv *, jobject, jlong);

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_setAge
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1setAge
  (JNIEnv *, jobject, jlong, jint);

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_getName
 * Signature: (J)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1getName
  (JNIEnv *, jobject, jlong);

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_setName
 * Signature: (JLjava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1setName
  (JNIEnv *, jobject, jlong, jstring);

#ifdef __cplusplus
}
#endif
#endif

3.添加c++实现文件:com_ksnowlv_jnicallc_JavaPerson.cpp

//
// Created by ksnowlv on 2019-04-18.
//

#include"com_ksnowlv_jnicallc_JavaPerson.h"
#include "Person.hpp"
#include "JNILog.h"
#include <string.h>

extern "C"
{

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    init
 * Signature: ()I
 */
JNIEXPORT jlong JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_init
  (JNIEnv *, jobject) {

      LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_init");
      Person *person = new Person();
      return (jlong)person;

  }

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    finalizer
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_finalizer
  (JNIEnv *, jobject cls, jlong thisObject) {

    LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_finalizer");

    Person *person = (Person *)thisObject;

    if (NULL != person) {
        delete person;
        person = NULL;
    }

  }

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_getAge
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1getAge
  (JNIEnv *evn, jobject cls, jlong thisObject ) {

    Person *person = (Person *)thisObject;

    LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1getAge= %d", person->age());

    if (NULL != person) {

        return person->age();
    }

    return -1;
  }

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_setAge
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1setAge
  (JNIEnv *env, jobject cls, jlong thisObject, jint age ) {

      LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1setAge = %d", age);

      Person *person = (Person *)thisObject;

      if ( NULL != person ) {
        person->setAge(age);
      }
  }

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_getName
 * Signature: (J)I
 */
JNIEXPORT jstring JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1getName
  (JNIEnv *env, jobject cls, jlong thisObject) {
      LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1getName");

      Person *person = (Person *)thisObject;

      if ( NULL != person ) {
          const char *name = person->name();
          if ( name != NULL ) {
               // LOGI("JNI name = %s",name);
                return  env->NewStringUTF(name);
           }
       }

    return env->NewStringUTF("");
  }

/*
 * Class:     com_ksnowlv_jnicallc_JavaPerson
 * Method:    native_setName
 * Signature: (JLjava/lang/String;)V
 */
JNIEXPORT void JNICALL Java_com_ksnowlv_jnicallc_JavaPerson_native_1setName
  (JNIEnv *env, jobject cls, jlong thisObject, jstring string) {

    LOGE("JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1setName");

     jclass   clsstring   =   env->FindClass("java/lang/String");  //String
     jstring   code   =   env->NewStringUTF("UTF8"); //"UTF8"
     jmethodID   methodID   =   env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); //getBytes(String);
     jbyteArray   byteArray =   (jbyteArray)env->CallObjectMethod(string,methodID,code); // String .getByte("UTF8");
     jsize   length   =   env->GetArrayLength(byteArray);
     jbyte*   bytes   =   env->GetByteArrayElements(byteArray,JNI_FALSE);

    Person *person = (Person *)thisObject;

    if ( NULL != person ) {
       if( length > 0){
            char* buf =   new char[length+1];
            memset(buf,0,length+1);
            memcpy(buf,bytes,length);
            person->setName(buf);
            LOGE("JNI set name = %s",buf);
            delete []buf;
         }else{
            person->setName(NULL);
         }
    }



     env->ReleaseByteArrayElements(byteArray,bytes,0);  //释放内存空间
  }

}

static  JNINativeMethod methods[] = {

        {"init", "()J", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_init},
        {"finalizer", "(J)V", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_finalizer},
        {"native_getAge", "(J)I", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_native_1getAge},
        {"native_setAge", "(JI)V", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_native_1setAge},
        {"native_getName", "(J)Ljava/lang/String;", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_native_1getName},
        {"native_setName", "(JLjava/lang/String;)V", (void *)Java_com_ksnowlv_jnicallc_JavaPerson_native_1setName},
};





static const char * classPathName = "com/ksnowlv/jnicallc/JavaPerson";
/*
 * Register several native methods for one class.
 */
static int registerNativeMethods(JNIEnv* env, const char* className,
                                 JNINativeMethod* gMethods, int numMethods)
{
    jclass clazz;
    clazz = env->FindClass(className);
    if (clazz == NULL) {
        LOGE("JavaPerson Native registration unable to find class '%s'", className);
        return JNI_FALSE;
    }
    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
        LOGE("JavaPerson RegisterNatives failed for '%s'", className);
        return JNI_FALSE;
    }

    LOGE("JavaPerson registerNativeMethods OK");
    return JNI_TRUE;
}
/*
 * Register native methods for all classes we know about.
 *
 * returns JNI_TRUE on success.
 */
static int registerNatives(JNIEnv* env)
{
    if (!registerNativeMethods(env, classPathName,
                               methods, sizeof(methods) / sizeof(methods[0]))) {
        LOGE("JavaPerson class registerNatives FAIL");
        return JNI_FALSE;
    }

    LOGE("JavaPerson registerNatives OK");
    return JNI_TRUE;
}
// ----------------------------------------------------------------------------
/*
 * This is called by the VM when the shared library is first loaded.
 */

typedef union {
    JNIEnv* env;
    void* venv;
} UnionJNIEnvToVoid;

jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
    UnionJNIEnvToVoid uenv;
    uenv.venv = NULL;
    jint result = -1;
    JNIEnv* env = NULL;

    LOGE("JNI_OnLoad");
    if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
        LOGE("ERROR: GetEnv failed");
        goto bail;
    }
    env = uenv.env;
    if (registerNatives(env) != JNI_TRUE) {
        LOGE("ERROR: registerNatives failed");
        goto bail;
    }

    result = JNI_VERSION_1_4;

    LOGE("JNI_OnLoad OK");
    bail:
    return result;
}

4.在Android中的调用

   JavaPerson person = new JavaPerson();
    person.setAge(10);
    Log.i("------JNICallC++: Android person age =  ","" + person.getAge());
    person.setName("ksnowlv(律威)");
    Log.i("------JNICallC++: Android person name =  ","" + person.getName());   

5.输出

2019-04-19 17:02:27.114 30422-30422/? E/------JNICallC++: JNI_OnLoad
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JavaPerson registerNativeMethods OK
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JavaPerson registerNatives OK
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JNI_OnLoad OK
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JNI Java_com_ksnowlv_jnicallc_JavaPerson_init
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1setAge = 10
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1getAge= 10
2019-04-19 17:02:27.115 30422-30422/? I/------JNICallC++: Android person age =: 10
2019-04-19 17:02:27.115 30422-30422/? E/------JNICallC++: JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1setName
2019-04-19 17:02:27.116 30422-30422/? E/------JNICallC++: JNI set name = ksnowlv(律威)
2019-04-19 17:02:27.116 30422-30422/? E/------JNICallC++: JNI Java_com_ksnowlv_jnicallc_JavaPerson_native_1getName
2019-04-19 17:02:27.116 30422-30422/? I/------JNICallC++: Android person name =: ksnowlv(律威)

6.说明

  • C++Person类同上一工程 。
  • 注意JNI调用C++和C的区别。
    • JNI_OnLoad相关:像JNINativeMethod methods注意函数映射参数,classPathName类路径等
    • env调用方式
    • C++对象回收内存

Android-jni-demo

| Comments

1.创建app/src/main/jniLibs目录

2.把so库拷贝到jniLibs目录。

3.JavaCallJNI内容如下

···objective-c

public class JavaCallJNI {

static  {
    System.loadLibrary("JNITest");
}


public static native int showValue(int value);

}

···

4.com_ksnowlv_hellojniforjava_JavaCallJNI.h内容如下:

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
/* DO NOT EDIT THIS FILE - it is machine generated */

#include <jni.h>

/* Header for class com_ksnowlv_hellojniforjava_JavaCallJNI */

#ifndef _Included_com_ksnowlv_hellojniforjava_JavaCallJNI

#define _Included_com_ksnowlv_hellojniforjava_JavaCallJNI

#ifdef __cplusplus

extern "C" {

#endif
/*
 * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
 * Method:    showValue
 * Signature: (I)I
 */

JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_showValue
  (JNIEnv *, jclass, jint);

  #ifdef __cplusplus
}

#endif

#endif

5.com_ksnowlv_hellojniforjava_JavaCallJNI.c内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "com_ksnowlv_hellojniforjava_JavaCallJNI.h"
#include "PersonExtension.hpp"
#include "JNILog.h"


JNIEXPORT jint JNICALL Java_com_ksnowlv_hellojniforjava_JavaCallJNI_showValue
  (JNIEnv * enc, jclass cls , jint value) {

    LOGI("jni value = %d",value);
  value = value + 1;
  LOGI("jni value +1 = %d",value);
    return value;
  }

6。Android中调用如下:

1
2
  int value =  JavaCallJNI.showValue(1);
  Log.e("#### value ","" + value);

Android

”mac下配置jni开发环境(二)“

| Comments

创建android基础工程

1.JNI java文件创建

1
2
3
4
5
6
7
8
public class JavaCallJNI {

    static  {
        System.loadLibrary("JniTest");
    }

    public static native int showValue(int value);
}

image

2.在app/scr/main/目录下,创建目录jni

3.在jni目录下,创建Android.mk文件

文件内容如下:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)


LOCAL_MODULE := jniTest
LOCAL_SRC_FILES := com_ksnowlv_hellojniforjava_JavaCallJNI.c

include $(BUILD_SHARED_LIBRARY)

其中

  • LOCAL_MODULE := JniTest

      这里JniTest,是将要生成的`.so`库的名字,会自动加上 lib前缀,
      最终生成库文件:libJniTest.so
      如果要引用该库:System.loadLibrary("JniTest")
    
  • LOCAL_SRC_FILES := com_ksnowlv_hellojniforjava_JavaCallJNI

      JNI头文件com_ksnowlv_hellojniforjava_JavaCallJNI.h对应的.c文件
      命名方式:包名+类名+.c
    

terminal中生成com_ksnowlv_hellojniforjava_JavaCallJNI.h头文件

ksnowlvdeMacBook-Pro:java ksnowlv$ javac com/ksnowlv/   hellojniforjava/JavaCallJNI.java 
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
ksnowlvdeMacBook-Pro:java ksnowlv$ javah -d ../jni  com.ksnowlv.hellojniforjava.JavaCallJNI
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
ksnowlvdeMacBook-Pro:java ksnowlv$ cd ..

image

实现文件中内容如下

#include "com_ksnowlv_hellojniforjava_JavaCallJNI.h"

JNIEXPORT jint JNICALL  Java_com_ksnowlv_hellojniforjava_JavaCallJNI_showValue(JNIEnv * enc, jclass cls , jint value) {
    value = value + 1;
    return value;
}

4.在jni目录下,创建Application.mk文件

内容如下:

APP_ABI := all  

会生成所有主流 ABI 类型的 .so 库

5.更新在当前模块下build.gradle文件

  • defaultConfig下增加ndk配置

      ndk {
          moduleName "JniTest" //System.loadLibrary("JniTest");
      }
    
  • 在buildTypes上面添加jni.srcDirs的配置

      sourceSets {
         main {//建议这里直接使用'libs'目录,
         //因为当使用其他包有.so文件时,一般习惯也是直接拷贝进入libs目录
          jni.srcDirs = ['libs']
        }
      }
    

image

5.在终端进入jni路径:app/src/main/jni,输入ndk-build即生成各种版本的so

ksnowlvdeMacBook-Pro:java ksnowlv$ javac com/ksnowlv/   hellojniforjava/JavaCallJNI.java 
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
ksnowlvdeMacBook-Pro:java ksnowlv$ javah -d ../jni  com.ksnowlv.hellojniforjava.JavaCallJNI
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
ksnowlvdeMacBook-Pro:java ksnowlv$ cd ..
ksnowlvdeMacBook-Pro:main ksnowlv$ cd jni
ksnowlvdeMacBook-Pro:jni ksnowlv$ ndk-build

image

”mac下android配置jni开发环境(一)“

| Comments

mac机器上,在进行jni开发之前,android studio 3.3.2,需要配置java环境与ndk环境。

一.配置java环境参数

1.通过which java查看Mac下jdk安装目录

ksnowlvdeMacBook-Pro:~ ksnowlv$ which java
/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/bin/java

image

2.在.bash_profile文件中配置java环境

JAVA_HOME=/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home
PATH=$JAVA_HOME/bin:$PATH:.
CLASSPATH=$JAVA_HOME/lib/tools.jar:$JAVA_HOME/lib/dt.jar:.

export JAVA_HOME
export PATH
export CLASSPATH

3.保存.bash_profile,并使之生效。

ksnowlvdeMacBook-Pro:~ ksnowlv$ source .bash_profile

ksnowlvdeMacBook-Pro:~ ksnowlv$ echo $JAVA_HOME
/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

ksnowlvdeMacBook-Pro:~ ksnowlv$ java -version
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
java version "1.6.0_65"
Java(TM) SE Runtime Environment (build 1.6.0_65-b14-468)
Java HotSpot(TM) 64-Bit Server VM (build 20.65-b04-468, mixed mode)

二.配置ndk。

1.在.bash_profile文件中配置ndk路径

export ANDROID_NDK_ROOT=/Users/ksnowlv/Library/Android/sdk/ndk-bundle 
export ANDROID_SDK_ROOT=/Users/ksnowlv/Library/Android/sdk

export PATH=$PATH:$ANDROID_SDK_ROOT  
export PATH=$PATH:$ANDROID_NDK_ROOT 

ndk路径,sdk路径一定要与实际目录一致,参考下图
image

2.保存.bash_profile,并使之生效。

ksnowlvdeMacBook-Pro:~ ksnowlv$ source .bash_profile
ksnowlvdeMacBook-Pro:~ ksnowlv$ echo $ANDROID_NDK_ROOT
/Users/ksnowlv/Library/Android/sdk/ndk-bundle
ksnowlvdeMacBook-Pro:~ ksnowlv$ echo $ANDROID_SDK_ROOT
/Users/ksnowlv/Library/Android/sdk
ksnowlvdeMacBook-Pro:~ ksnowlv$ 

三.其它

1.为什么不使用jdk-12.jdk?而使用了旧版jdk?

javah命令在旧版有效。新版可使用javac -h

300指数量化基金

| Comments

基金代码 简称 2016超越沪深300指数% 2017超越300指数% 2018超越300指数% 3年平均收益率% 基金规模 管理托管费%
163497 兴全沪深300指数增强 11.98 10.05 8.36 10.13 20.25亿元|0.95
100038 富国沪深300指数增强 6.27 5.3 8.37 6.65 58.83亿元|1.18
00012 华安沪深300增强A 8.33 8.95 3.95 7.08 1.75亿元|1.15
519116 浦银沪深300增强 6.6 4.36 5.79 5.59 1.11|1.15
110030 易方达沪深量化300增强 9.47 8.06 2.15 6.56 9.86|0.95
000887 华泰柏瑞量化优选 13.93 2.59 3.03 6.52 40.77 1.25

计划新增兴全沪深300指数增强,易方达沪深量化300增强长期定投

Swift Call C++(二)

| Comments

如何在swift调整c++代码呢?

swift通过工程的桥接文件,调用oc的代码,间接调用c++代码!!!

1.创建C++ Person类文件:Person.hppPerson.cpp

Person.hpp内容如下:

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
//
//  Person.hpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/28.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#ifndef Person_hpp
#define Person_hpp

#include <stdio.h>

class Person {
public:
    Person();
    ~Person();

    void setName(const char* pName);
    const char* name();

    void setAge(const int age);
    const int age() const;

private:
    char *m_pName;
    int m_age;
};


#endif /* Person_hpp */

Person.cpp内容如下

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
//
//  Person.cpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/28.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#include "Person.hpp"
#include <string.h>


Person::Person() {
    m_pName = nullptr;
    m_age = 0;
}

Person::~Person() {

    if (m_pName) {
        delete [] m_pName;
        m_pName = nullptr;
    }
}

void Person::setAge(const int age) {
    m_age = age;
}

const int Person::age()const {
    return m_age;
}

void Person::setName(const char *pName) {
    if (m_pName) {
        delete [] m_pName;
        m_pName = nullptr;
    }

    if (pName) {
        const size_t len = strlen(pName) + 1;
        m_pName = new char[len];
        memset(m_pName, 0, len);
        strcpy(m_pName, pName);
    }
}

const char* Person::name() {
    return m_pName;
}

2.创建oc类文件:PersonExt.hPersonExt.mm

PersonExt.h内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//
//  PersonExt.h
//  SwiftCallC
//
//  Created by ksnowlv on 2019/4/1.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#import <Foundation/Foundation.h>


NS_ASSUME_NONNULL_BEGIN

@interface PersonExt : NSObject


@property(nonatomic, strong) NSString *name;
@property(nonatomic, assign) NSInteger age;


@end

NS_ASSUME_NONNULL_END

PersonExt.mm内容如下

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
63
64
65
66
67
68
69
70
71
72
//
//  PersonExt.m
//  SwiftCallC
//
//  Created by ksnowlv on 2019/4/1.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#import "PersonExt.h"
#include "Person.hpp"

@interface PersonExt () {
    Person *_person;
}


@end

@implementation PersonExt

- (id)init {
    self = [super init];

    if (self) {
        _person = new Person();
    }

    return self;
}

- (void)dealloc {

    if (_person) {
        delete _person;
        _person = nil;
    }
}

- (void)setName:(NSString *)name {
    if (_person) {
        _person->setName([name UTF8String]);
    }
}

- (NSString *)name {
    if (_person) {
        const char *name = _person->name();

        if (name) {
            return  [NSString stringWithUTF8String:name];
        }
    }

    return nil;
}

- (void)setAge:(NSInteger)age {

    if (_person) {
        _person->setAge((const int)age);
    }
}

- (NSInteger)age {
    if (_person) {
        return  _person->age();
    }

    return 0;
}

@end

3.在桥接文件中,加入PersonExt.h引用:#include "PersonExt.h"

4.swift中调用

1
2
3
4
5
6
7
8
9
    let personExt = PersonExt()
    var age = personExt.age
    print("age =",age)
    personExt.age = 20
    age = personExt.age
    print("age =",age)

    personExt.name = "ksnowlv"
    print("name = ",personExt.name)

结果显而易见:

1
2
3
age = 0
age = 20
name =  ksnowlv

Swift Call C++(一)

| Comments

如何在swift调整c++代码呢?

swift通过工程的桥接文件,调用c的代码,间接调用c++代码!!!

1.创建C++ Person类文件:Person.hppPerson.cpp

Person.hpp内容如下:

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
//
//  Person.hpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/28.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#ifndef Person_hpp
#define Person_hpp

#include <stdio.h>

class Person {
public:
    Person();
    ~Person();

    void setName(const char* pName);
    const char* name();

    void setAge(const int age);
    const int age() const;

private:
    char *m_pName;
    int m_age;
};


#endif /* Person_hpp */

Person.cpp内容如下

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
//
//  Person.cpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/28.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#include "Person.hpp"
#include <string.h>


Person::Person() {
    m_pName = nullptr;
    m_age = 0;
}

Person::~Person() {

    if (m_pName) {
        delete [] m_pName;
        m_pName = nullptr;
    }
}

void Person::setAge(const int age) {
    m_age = age;
}

const int Person::age()const {
    return m_age;
}

void Person::setName(const char *pName) {
    if (m_pName) {
        delete [] m_pName;
        m_pName = nullptr;
    }

    if (pName) {
        const size_t len = strlen(pName) + 1;
        m_pName = new char[len];
        memset(m_pName, 0, len);
        strcpy(m_pName, pName);
    }
}

const char* Person::name() {
    return m_pName;
}

2.创建c类文件:PersonExtension.hppPersonExtension.cpp

PersonExtension.hpp内容如下

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
//
//  PersonExtension.hpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/29.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#ifndef PersonExtension_hpp
#define PersonExtension_hpp

#include <stdio.h>


#ifdef __cplusplus
extern "C"{
#endif
    //在这里写上c的代码

    //初始化一个Person的实例

    const void * createPerson();
    const void destroyPerson(void* p);
    const void setPersonAge(void* p, const int age);
    const int personAge(void* p);
    const void setPersonName(void* p, const char* name);
    const char* personName(void* p);


#ifdef __cplusplus
}
#endif

#endif /* PersonExtension_hpp */

PersonExtension.cpp内容如下

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
//
//  PersonExtension.cpp
//  SwiftCallC
//
//  Created by ksnowlv on 2019/3/29.
//  Copyright © 2019 ksnowlv. All rights reserved.
//

#include "PersonExtension.hpp"
#include "Person.hpp"

const void * createPerson()
{
    Person *p = new Person();

    return (void *)p;
}

const void destroyPerson(void* p) {
    if (p) {
        Person *person = (Person*)p;
        delete person;
    }
}


const void setPersonAge(void* p, const int age) {

    if (p) {
        Person *person = (Person*)p;
        person->setAge(age);
    }
}

const int personAge(void* p) {

    if (p) {
        Person *person = (Person*)p;
        return person->age();
    }

    return 0;
}

const void setPersonName(void* p, const char* name) {
    if (p) {
        Person *person = (Person*)p;
        person->setName(name);
    }
}

const char* personName(void* p) {
    if (p) {
        Person *person = (Person*)p;
        return person->name();
    }

    return nullptr;
}

3.在桥接文件中,加入PersonExtension.hpp引用:#include "PersonExtension.hpp""

4.swift中调用

1
2
3
4
5
6
7
8
9
10
11
      let person = UnsafeMutableRawPointer(mutating: createPerson())
      print("age =",personAge(person))
      setPersonAge(person, 10)
      print("age =",personAge(person))

      setPersonName(person, "ksnowlv")

      let nameBuf:UnsafePointer<Int8> = personName(person)
      print("name = ",String(cString: nameBuf))

      destroyPerson(person)

结果显而易见:

1
2
3
age = 0
age = 10
name =  ksnowlv

Swift Call C

| Comments

如何在swift调整c代码呢?

swift通过工程的桥接文件,调用oc或c的相关代码!!!

1.创建c文件:test.htest.c

test.h内容如下:

1
2
3
4
5
6
7
8
#ifndef test_h
#define test_h

#include <stdio.h>

void showValue(int *value);

#endif /* test_h */

test.c内容如下

1
2
3
4
5
6
7
#include "test.h"

void showValue(int *value) {
    printf("old value = %d\n",*value);
    *value = *value + 1;
    printf("new value = %d\n",*value);
}

2.在桥接文件中,加入test.h引用:#include "test.h"

3.swift中调用

1
2
3
   var value: Int32 = 0
   showValue(&value)

结果显而易见:

1
2
old value = 0
new value = 1

Go变量声明和使用

| Comments

go变量声明和使用

···objective-c

package main

import “fmt”

var x, y int

var (

a int
b bool

)

var c, d int = 1, 2

var e, f = 123, “hello”

func main() {

//这咱不带声明格式的用法,只能出现在函数休内
g, h := 123, "hello"

println(x, y, a, b, c, d, e, f, g, h)

var testString string = "hello world!"

fmt.Println(testString)

var a, b int

a, b = 5, 7

println("a=", a, "b=", b)

a, b = b, a

println("a和b交换后 a=", a, "b=", b)

}

···

Included file 'custom/after_footer.html' not found in _includes directory