Как создать обратные вызовы между кодом android и собственным кодом?

у меня есть требование для создания обратных вызовов между родным кодом ( код языка c) и кодом Android . Я написал функции JNI для вызова C code от андроида, как это

код JNI здесь

#include <android/log.h>

void initSocket(); 

#ifdef __cplusplus
extern "C" {
#endif

  JNIEXPORT void JNICALL Java_org_pjsip_pjsua_pjsua_1appJNI_initSocket(JNIEnv *jenv, jclass jcls) {

    __android_log_write(ANDROID_LOG_INFO, " JNI CODE ", " APP INIT SOCKET");        
    initSocket();        
  }
}

код C выглядит так

void initSocket()
{
    /// some more stuff
    printf("  initSocket function ");           
}

static int worker_thread(void *unused)
{       
    /// some more stuff
    return 0;
}

pj_bool_t on_rx_data1(pj_stun_sock *stun_sock, void *pkt, unsigned pkt_len, const pj_sockaddr_t *src_addr, unsigned addr_len)
{      
    /// some more stuff    
    return PJ_TRUE;
}

pj_bool_t on_data_sent1 (pj_stun_sock *stun_sock, pj_ioqueue_op_key_t *send_key, pj_ssize_t sent)
{        
    /// some more stuff
    return PJ_TRUE;  
}
pj_bool_t on_status1(pj_stun_sock *stun_sock, pj_stun_sock_op op, pj_status_t status)
{        
    /// some more stuff
    returnsockaddress();            
    return PJ_TRUE;
}

char* returnsockaddress()
{     
    /// some more stuff   
    return ipinttostring(sock_address);
}

char* ipinttostring(unsigned int addr )
{       
    /// some more stuff
    return fullIP;
}

это код, который я использую на языке C, вызывая initSocket() функция от JNI. Теперь я хочу создать callback отсюда C code, когда on_status1 функция вызывается в этом коде. это on_status1 будет повторите через несколько секунд, когда это называется, Я хочу вызвать функцию в коде android.

редактировать

Я пробовал так, но не получилось

JNIEXPORT void JNICALL Java_org_pjsip_pjsua_pjsua_1appJNI_initSocket(JNIEnv *jenv, jobject obj) {

      __android_log_write(ANDROID_LOG_INFO, " JNI CODE ", " APP INIT SOCKET");            
      initSocket();             
      jclass cls = jenv->GetObjectClass(obj);
      jmethodID methodid = env->GetMethodID(cls, "callback", "()V");            
      if(!methodid) {
          return;
      }            
      jenv->CallVoidMethod(obj , methodid);            
  }

Я был объявлен функцией, как это в коде android.

public static void callback(String value) {
    Log.e(TAG, "value:" + value);
}

2 ответов


попробуйте это :

JNIEXPORT void JNICALL Java_org_pjsip_pjsua_pjsua_1appJNI_initSocket(JNIEnv *jenv, jobject obj) {
  __android_log_write(ANDROID_LOG_INFO, " JNI CODE ", " APP INIT SOCKET");            
  initSocket();             
  // jclass cls = (*jenv)->GetObjectClass(jenv, obj);
  // or something like this :
  jclass cls = (*jenv)->FindClass(jenv, "org/pjsip/pjsua/pjsua_appJNI"); 
  jmethodID methodid = (*jenv)->GetStaticMethodID(jenv, cls, "callback", "(Ljava/lang/String;)V");            
  if(!methodid) {
      return;
  }       
  jstring jstr = (*jenv)->NewStringUTF(jenv, "Hello from C"); 
  (*jenv)->CallStaticVoidMethod(jenv, cls, methodid, jstr); 
  }

из кода java:

public static void callback(String value){
    Log.e(TAG, "value:"+value);
 }

и вызовите C:

typedef struct JniSMSMethodInfo
{
    JNIEnv *    env;
    jclass      classID;
    jmethodID   methodID;
} JniMethodInfo;

extern "C"
{
static JNIEnv* getJNIEnv(void)
{

    JavaVM* jvm = cocos2d::JniHelper::getJavaVM();
    if (NULL == jvm) {
        LOGD("Failed to get JNIEnv. JniHelper::getJavaVM() is NULL");
        return NULL;
    }

    JNIEnv *env = NULL;
    // get jni environment
    jint ret = jvm->GetEnv((void**)&env, JNI_VERSION_1_4);

    switch (ret) {
        case JNI_OK :
            // Success!
            return env;

        case JNI_EDETACHED :
            // Thread not attached

            // TODO : If calling AttachCurrentThread() on a native thread
            // must call DetachCurrentThread() in future.
            // see: http://developer.android.com/guide/practices/design/jni.html

            if (jvm->AttachCurrentThread(&env, NULL) < 0)
            {
                LOGD("Failed to get the environment using AttachCurrentThread()");
                return NULL;
            } else {
                // Success : Attached and obtained JNIEnv!
                return env;
            }

        case JNI_EVERSION :
            // Cannot recover from this error
            LOGD("JNI interface version 1.4 not supported");
        default :
            LOGD("Failed to get the environment using GetEnv()");
            return NULL;
    }
}
// get class and make it a global reference, release it at endJni().
static jclass getClassID(JNIEnv *pEnv)
{
    jclass ret = pEnv->FindClass(CLASS_NAME);
    if (! ret)
    {
        LOGD("Failed to find class of %s", CLASS_NAME);
    }

    return ret;
}
static bool getStaticMethodInfo(JniMethodInfo &methodinfo, const char *methodName, const char *paramCode)
{
    jmethodID methodID = 0;
    JNIEnv *pEnv = 0;
    bool bRet = false;

    do 
    {
        pEnv = getJNIEnv();
        if (! pEnv)
        {
            break;
        }

        jclass classID = getClassID(pEnv);

        methodID = pEnv->GetStaticMethodID(classID, methodName, paramCode);
        if (! methodID)
        {
            LOGD("Failed to find static method id of %s", methodName);
            break;
        }

        methodinfo.classID = classID;
        methodinfo.env = pEnv;
        methodinfo.methodID = methodID;

        bRet = true;
    } while (0);

    return bRet;
}
void callback(char* value){
    JniMethodInfo methodInfo;
    if (! getStaticMethodInfo(methodInfo, "callback", METHOD_SIGNATURE))
    {            
        return;
    }

    jstring stringArg = methodInfo.env->NewStringUTF(value);
    methodInfo.env->CallStaticVoidMethod(methodInfo.classID, methodInfo.methodID, stringArg1);
    methodInfo.env->DeleteLocalRef(stringArg);
    methodInfo.env->DeleteLocalRef(methodInfo.classID);
}

}

ИМЯ_КЛАССА: / METHOD_SIGNATURE: см. Его из файла *.класс!--3-->