You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
301 lines
9.9 KiB
301 lines
9.9 KiB
// C/C++/Obj-C/Obj-C++ wrapper that exports C functions
|
|
//
|
|
// As an example, distributed with .c suffix,
|
|
// but depending on extension needs, can be
|
|
// compiled as C, C++, Obj-C or Obj-C++
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include "TestClassNativeHelper.h"
|
|
|
|
#undef NDEBUG
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
#define TCH_LOGI(...) __android_log_print(ANDROID_LOG_INFO, "TestClassNativeHelper", __VA_ARGS__)
|
|
#define TCH_LOGE(...) __android_log_print(ANDROID_LOG_ERROR, "TestClassNativeHelper", __VA_ARGS__)
|
|
|
|
#ifndef NDEBUG
|
|
#define TCH_LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, "TestClassNativeHelper", __VA_ARGS__)
|
|
#else
|
|
#define TCH_LOGV(...)
|
|
#endif
|
|
|
|
#define TCH_ELOG TCH_LOGV("%s", __FUNCTION__)
|
|
|
|
void TCH_onTestClassUploadDidProgress(C_JNIEnv *env, jobject thiz, jint videoId, jdouble progress) {
|
|
TCH_ELOG;
|
|
}
|
|
|
|
#ifndef TCH_NELEM
|
|
#define TCH_NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
|
|
#endif
|
|
|
|
static const char *kTCHTestClassClass = "com/testclass/TestClass/TestClass";
|
|
static const char *kTCHTestClassLoader = "com.testclass.TestClass.TestClass";
|
|
|
|
static const char *kTCHTestClassNativeListenerClass = "com/testclass/TestClass/communication/TestClassNativeListener";
|
|
static const char *kTCHTestClassNativeListenerLoader = "com.testclass.TestClass.communication.TestClassNativeListener";
|
|
|
|
static JavaVM *TCH_vm = NULL;
|
|
|
|
static JNINativeMethod TCH_listenerMethods[] = {
|
|
{ "onTestClassUploadDidProgress", "(ID)V", (void *) TCH_onTestClassUploadDidProgress },
|
|
};
|
|
|
|
static C_JNIEnv *TCH_getEnv() {
|
|
C_JNIEnv *ret = NULL;
|
|
|
|
if (TCH_vm == NULL) {
|
|
TCH_LOGE("TCH_getEnv failed, no JVM");
|
|
return NULL;
|
|
}
|
|
|
|
#if defined(__cplusplus)
|
|
JNIEnv *env = NULL;
|
|
|
|
if (TCH_vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
|
JavaVMAttachArgs args;
|
|
args.version = JNI_VERSION_1_6;
|
|
args.name = NULL;
|
|
args.group = NULL;
|
|
|
|
int attachStatus;
|
|
if ((attachStatus = TCH_vm->AttachCurrentThread(&env, &args)) < 0) {
|
|
TCH_LOGE("TCH_getEnv failed");
|
|
}
|
|
}
|
|
ret = (C_JNIEnv *) env;
|
|
#else
|
|
JNIEnv *env = NULL;
|
|
|
|
if ((*TCH_vm)->GetEnv(TCH_vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK) {
|
|
JavaVMAttachArgs args;
|
|
args.version = JNI_VERSION_1_6;
|
|
args.name = NULL;
|
|
args.group = NULL;
|
|
|
|
int attachStatus;
|
|
if ((attachStatus = (*TCH_vm)->AttachCurrentThread(TCH_vm, &env, &args)) < 0) {
|
|
TCH_LOGE("TCH_getEnv failed");
|
|
}
|
|
}
|
|
ret = env;
|
|
#endif /* if defined(__cplusplus) */
|
|
return ret;
|
|
}
|
|
|
|
static jclass TCH_loadClass(C_JNIEnv *env, jobject activity, const char *className) {
|
|
jclass cls_Activity = (*env)->GetObjectClass((JNIEnv *) env, activity);
|
|
jmethodID mid_getClassLoader = (*env)->GetMethodID((JNIEnv *) env, cls_Activity, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
|
jobject obj_classLoader = (*env)->CallObjectMethod((JNIEnv *) env, activity, mid_getClassLoader);
|
|
|
|
jclass cls_classLoader = (*env)->GetObjectClass((JNIEnv *) env, obj_classLoader);
|
|
jmethodID mid_loadClass = (*env)->GetMethodID((JNIEnv *) env, cls_classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
|
|
|
jstring _className = (*env)->NewStringUTF((JNIEnv *) env, className);
|
|
jclass cls = (jclass) (*env)->CallObjectMethod((JNIEnv *) env, obj_classLoader, mid_loadClass, _className);
|
|
|
|
(*env)->DeleteLocalRef((JNIEnv *) env, _className);
|
|
|
|
if (!cls) {
|
|
TCH_LOGE("Couldn't find class %s", className);
|
|
}
|
|
|
|
return cls;
|
|
}
|
|
|
|
#define TCH_str2(x) #x
|
|
#define TCH_str(x) TCH_str2(x)
|
|
|
|
#define TCH_CLASS(_class) tchClass_##_class
|
|
|
|
#define TCH_LOCAL_CLASS(_class) local_tchClass_##_class
|
|
|
|
#define TCH_REGISTER_CLASS(_class) \
|
|
jclass TCH_CLASS(_class) = NULL;
|
|
|
|
#define TCH_EXTERN_CLASS(_class) \
|
|
jclass TCH_CLASS(_class);
|
|
|
|
#define TCH_METHOD(_method) tchMethod_##_method
|
|
|
|
#define TCH_REGISTER_METHOD(_method) \
|
|
jmethodID TCH_METHOD(_method) = NULL;
|
|
|
|
#define TCH_EXTERN_METHOD(_method) \
|
|
jmethodID TCH_METHOD(_method);
|
|
|
|
#define TCH_REGISTER_NATIVES(_env, _class, methods) \
|
|
if ((*_env)->RegisterNatives((JNIEnv *) _env, TCH_CLASS(_class), methods, TCH_NELEM(methods)) < 0) { \
|
|
TCH_LOGE("RegisterNatives failed for %s\n", TCH_str(_class)); \
|
|
}
|
|
|
|
#define TCH_FIND_CLASS(_env, _class, _className) \
|
|
jclass TCH_LOCAL_CLASS(_class) = (*_env)->FindClass((JNIEnv *) _env, _className); \
|
|
if (TCH_LOCAL_CLASS(_class) == NULL) { \
|
|
TCH_LOGE("Unable to find class %s\n", _className); \
|
|
} else { \
|
|
TCH_CLASS(_class) = (jclass) (*_env)->NewGlobalRef((JNIEnv *) _env, TCH_LOCAL_CLASS(_class)); \
|
|
}
|
|
|
|
#define TCH_FIND_STATIC_METHOD(_env, _class, _method, _prototype) \
|
|
TCH_METHOD(_method) = (*_env)->GetStaticMethodID((JNIEnv *) _env, TCH_CLASS(_class), TCH_str(_method), _prototype); \
|
|
if (TCH_METHOD(_method) == NULL) { \
|
|
TCH_LOGE("Unable to find method %s", TCH_str(_method)); \
|
|
}
|
|
|
|
#define TCH_FIND_STATIC_METHOD2(_env, _class, _method, _symbol, _prototype) \
|
|
TCH_METHOD(_method) = (*_env)->GetStaticMethodID((JNIEnv *) _env, TCH_CLASS(_class), TCH_str(_symbol), _prototype); \
|
|
if (TCH_METHOD(_method) == NULL) { \
|
|
TCH_LOGE("Unable to find method %s", TCH_str(_method)); \
|
|
}
|
|
|
|
#define TCH_CALL_STATIC_METHOD_ARGS(_env, _class, _method, ...) \
|
|
(*_env)->CallStaticVoidMethod((JNIEnv *) _env, TCH_CLASS(_class), TCH_METHOD(_method), __VA_ARGS__);
|
|
|
|
#define TCH_CALL_STATIC_METHOD_BOOL(_env, _class, _method) \
|
|
(*_env)->CallStaticBooleanMethod((JNIEnv *) _env, TCH_CLASS(_class), TCH_METHOD(_method));
|
|
|
|
TCH_REGISTER_CLASS(testclassClass);
|
|
TCH_REGISTER_METHOD(testclassConstructor);
|
|
static jobject TCH_testclassInstance = NULL;
|
|
|
|
TCH_REGISTER_CLASS(testclassNativeListenerClass);
|
|
TCH_REGISTER_METHOD(testclassNativeListenerConstructor);
|
|
static jobject TCH_testclassNativeListenerInstance = NULL;
|
|
|
|
TCH_REGISTER_METHOD(isSupported);
|
|
TCH_REGISTER_METHOD(initTestClass);
|
|
|
|
static void TCH_preload(C_JNIEnv *env) {
|
|
TCH_ELOG;
|
|
|
|
if (TCH_CLASS(testclassClass) == NULL) {
|
|
TCH_FIND_CLASS(env, testclassClass, kTCHTestClassClass);
|
|
}
|
|
|
|
// Class really not found or not loaded, bail
|
|
if (TCH_CLASS(testclassClass) == NULL) {
|
|
return;
|
|
}
|
|
|
|
if (TCH_CLASS(testclassClass) != NULL && TCH_METHOD(isSupported) == NULL) {
|
|
TCH_FIND_STATIC_METHOD(env, testclassClass, isSupported, "()Z");
|
|
TCH_FIND_STATIC_METHOD(env, testclassClass, initTestClass, "(Lcom/testclass/TestClass/ITestClassListener;Landroid/app/Activity;)Z");
|
|
|
|
if (TCH_CLASS(testclassClass) != NULL) {
|
|
TCH_METHOD(testclassConstructor) = (*env)->GetMethodID((JNIEnv *) env, TCH_CLASS(testclassClass), "<init>", "()V");
|
|
jobject constructor = (*env)->NewObject((JNIEnv *) env, TCH_CLASS(testclassClass), TCH_METHOD(testclassConstructor));
|
|
TCH_testclassInstance = (*env)->NewGlobalRef((JNIEnv *) env, constructor);
|
|
}
|
|
|
|
if (TCH_CLASS(testclassNativeListenerClass) == NULL) {
|
|
TCH_FIND_CLASS(env, testclassNativeListenerClass, kTCHTestClassNativeListenerClass);
|
|
}
|
|
|
|
if (TCH_CLASS(testclassNativeListenerClass) != NULL) {
|
|
TCH_METHOD(testclassNativeListenerConstructor) = (*env)->GetMethodID((JNIEnv *) env, TCH_CLASS(testclassNativeListenerClass), "<init>", "()V");
|
|
jobject listener = (*env)->NewObject((JNIEnv *) env, TCH_CLASS(testclassNativeListenerClass), TCH_METHOD(testclassNativeListenerConstructor));
|
|
TCH_testclassNativeListenerInstance = (*env)->NewGlobalRef((JNIEnv *) env, listener);
|
|
TCH_REGISTER_NATIVES(env, testclassNativeListenerClass, TCH_listenerMethods);
|
|
TCH_LOGV("Initializing built-in listener");
|
|
}
|
|
}
|
|
}
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
#ifndef NDEBUG
|
|
#define TCH_LOGV(...) NSLog(__VA_ARGS__)
|
|
#else
|
|
#define TCH_LOGV(...)
|
|
#endif
|
|
|
|
#define TCH_ELOG TCH_LOGV(@"%s", __FUNCTION__)
|
|
|
|
#if defined(__cplusplus)
|
|
#define TCH_NS(_class) ::_class
|
|
#else
|
|
#define TCH_NS(_class) _class
|
|
#endif
|
|
|
|
@interface TCH_delegateHandler : NSObject<TestClassDelegate>
|
|
@end
|
|
|
|
@implementation TCH_delegateHandler
|
|
- (void)testclassUploadDidProgress:(NSNumber *)videoId progress:(NSNumber *)progress {
|
|
TCH_ELOG;
|
|
}
|
|
|
|
@end
|
|
|
|
static TCH_delegateHandler *TCH_builtInHandler = nil;
|
|
|
|
#endif /* if defined(__ANDROID__) */
|
|
|
|
#if defined(__ANDROID__)
|
|
|
|
void TCH_initTestClass(JNIEnv *env, jobject activity, jobject listener) {
|
|
TCH_ELOG;
|
|
|
|
C_JNIEnv *cenv = NULL;
|
|
#if defined(__cplusplus)
|
|
cenv = (C_JNIEnv *) env;
|
|
#else
|
|
cenv = env;
|
|
#endif
|
|
|
|
if (TCH_vm == NULL) {
|
|
int status = (*cenv)->GetJavaVM((JNIEnv *) cenv, &TCH_vm);
|
|
if (status != 0) {
|
|
TCH_LOGE("GetJavaVM failed");
|
|
return;
|
|
}
|
|
}
|
|
|
|
TCH_CLASS(testclassClass) = TCH_loadClass(cenv, activity, kTCHTestClassLoader);
|
|
TCH_CLASS(testclassNativeListenerClass) = TCH_loadClass(cenv, activity, kTCHTestClassNativeListenerLoader);
|
|
TCH_preload(cenv);
|
|
|
|
jobject listenerRef = listener;
|
|
if (listenerRef == NULL) {
|
|
TCH_LOGV("Using built-in listener");
|
|
listenerRef = TCH_testclassNativeListenerInstance;
|
|
}
|
|
|
|
TCH_CALL_STATIC_METHOD_ARGS(cenv, testclassClass, initTestClass, listenerRef, activity);
|
|
}
|
|
|
|
#elif defined(__APPLE__)
|
|
|
|
void TCH_initTestClass(UIViewController *viewController, id<TestClassDelegate> testclassDelegate) {
|
|
TCH_ELOG;
|
|
|
|
id<TestClassDelegate> testclassDelegateRef = testclassDelegate;
|
|
if (testclassDelegateRef == nil) {
|
|
TCH_builtInHandler = [[TCH_delegateHandler alloc] init];
|
|
testclassDelegateRef = TCH_builtInHandler;
|
|
}
|
|
|
|
[TCH_NS(TestClass) initWithDelegate:testclassDelegateRef andParentViewController:viewController];
|
|
}
|
|
|
|
#endif /* if defined(__ANDROID__) */
|
|
|
|
bool TCH_isSupported(void) {
|
|
TCH_ELOG;
|
|
bool ret = false;
|
|
|
|
#if defined(__ANDROID__)
|
|
C_JNIEnv *env = TCH_getEnv();
|
|
if (env && TCH_CLASS(testclassClass)) {
|
|
ret = (bool) TCH_CALL_STATIC_METHOD_BOOL(env, testclassClass, isSupported);
|
|
}
|
|
#elif defined(__APPLE__)
|
|
ret = (bool) [TCH_NS(TestClass) isSupported];
|
|
#endif
|
|
|
|
return ret;
|
|
}
|