I am trying to integrate flurry into a NativeActivity (no-java based code) Android application, and am not having any success. I have set up a sister Java-based flurry test activity that works well, but the native calls seem to be the ones not getting through
In the manifest file, I have the permissions:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
package com.myTest.flurry;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import com.flurry.android.FlurryAgent;
public class FlurryActivity extends Activity {
//code has correct api key here
private static final String appKey = "xxxxxxxxxxxxxxxxxxxx";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_flurry);
FlurryAgent.onStartSession(this, appKey);
FlurryAgent.setLogEnabled(true);
FlurryAgent.setLogLevel(Log.VERBOSE);
FlurryAgent.setLogEvents(true);
FlurryAgent.logEvent("Starting up!");
}
@Override
protected void onDestroy() {
super.onDestroy();
FlurryAgent.onEndSession(this);
}
}
Which simply enough makes the events show up on the flurry website. However, when calling the same functions through my native code, the events do not show up
#include "flurry.h"
#include <jni.h>
#include <android/native_activity.h>
#include <android_native_app_glue.h>
#include "log.h"
JNIEnv *GetEnv(JavaVM *jvm);
void DetachEnv(JavaVM *jvm);
Flurry::Flurry()
: state_(0) {
}
jclass Flurry::GetFlurryAgentClass(JNIEnv *env) {
// Extract the FlurryAgent class
jobject nativeActivity = state_->activity->clazz;
jclass acl = env->GetObjectClass(nativeActivity);
// Get the classloader
jmethodID getClassLoader = env->GetMethodID(acl, "getClassLoader", "()Ljava/lang/ClassLoader;");
jobject cls = env->CallObjectMethod(nativeActivity, getClassLoader);
jclass classLoader = env->FindClass("java/lang/ClassLoader");
// find the loadclass function
jmethodID findClass = env->GetMethodID(classLoader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
// Run the loadClass function for the flurry agent
jstring strClassName = env->NewStringUTF("com/flurry/android/FlurryAgent");
const char *path = env->GetStringUTFChars(strClassName, 0);
// The following line will crash the app because it can't find the class files
jclass flurry_agent_class = (jclass)(env->CallObjectMethod(cls, findClass, strClassName));
env->DeleteLocalRef(strClassName);
if (env->ExceptionCheck() || flurry_agent_class == 0) {
Log("Failed to load flurry class!");
env->ExceptionDescribe();
env->ExceptionClear();
return 0;
}
return flurry_agent_class;
}
void Flurry::SetStateAndStartSession(android_app *state) {
state_ = state;
JNIEnv *env = GetEnv(state->activity->vm);
jclass flurry_agent_class = GetFlurryAgentClass(env);
if (flurry_agent_class == 0) {
return;
}
// Start session
jmethodID onStartSession_method = env->GetStaticMethodID(flurry_agent_class, "onStartSession", "(Landroid/content/Context;Ljava/lang/String;)V");
if (onStartSession_method) {
jstring api_key_string = env->NewStringUTF("xxxxxxxxxxxxxxxxxxxx");
Log("Starting native flurry");
env->CallStaticVoidMethod(flurry_agent_class, onStartSession_method, state->activity->clazz, api_key_string);
env->DeleteLocalRef(api_key_string);
}
// Set logging
jmethodID setLogEnabled_method = env->GetStaticMethodID(flurry_agent_class, "setLogEnabled", "(Z)V");
if (setLogEnabled_method) {
env->CallStaticVoidMethod(flurry_agent_class, setLogEnabled_method, JNI_TRUE);
}
// Set logging
jmethodID setLogLevel_method = env->GetStaticMethodID(flurry_agent_class, "setLogLevel", "(I)V");
if (setLogLevel_method) {
env->CallStaticVoidMethod(flurry_agent_class, setLogLevel_method, 2);
}
// Set events logging
jmethodID setLogEvents_method = env->GetStaticMethodID(flurry_agent_class, "setLogEvents", "(Z)V");
if (setLogEvents_method) {
env->CallStaticVoidMethod(flurry_agent_class, setLogEvents_method, JNI_TRUE);
}
// Set https
jmethodID setUseHttps_method = env->GetStaticMethodID(flurry_agent_class, "setUseHttps", "(Z)V");
if (setUseHttps_method) {
env->CallStaticVoidMethod(flurry_agent_class, setUseHttps_method, JNI_TRUE);
}
// Send the event
const char *eventname = "Native interface start";
jmethodID logEvent_method = env->GetStaticMethodID(flurry_agent_class, "logEvent", "(Ljava/lang/String;)V");
if (logEvent_method) {
Log("Sending Flurry Event: %s", eventname);
jstring event_name = env->NewStringUTF(eventname);
env->CallStaticVoidMethod(flurry_agent_class, logEvent_method, state_->activity->clazz, event_name);
env->DeleteLocalRef(event_name);
}
//LogEvent("Starting up native interface");
}
void Flurry::EndSession() {
// End session
JNIEnv *env = GetEnv(state_->activity->vm);
jclass flurry_agent_class = GetFlurryAgentClass(env);
if (flurry_agent_class == 0) {
return;
}
jmethodID onEndSession_method = env->GetStaticMethodID(flurry_agent_class, "onEndSession", "(Landroid/content/Context;)V");
if (onEndSession_method) {
Log("Ending flurry");
env->CallStaticVoidMethod(flurry_agent_class, onEndSession_method, state_->activity->clazz);
}
}
The output log for the flurry calls seems consistent with the java based calls:
Sample Log output:
I/FlurryAgent(25878): Agent cache file doesn't exist.
I/MyApp(25878): Starting native flurry
I/MyApp(25878): Sending Flurry Event: Native interface start
D/FlurryAgent(25878): generating report
D/FlurryAgent(25878): Sending report to: https://data.flurry.com/aap.do
D/FlurryAgent(25878): Report successful
D/FlurryAgent(25878): Done sending initial agent report
D/FlurryAgent(25878): Ending session
I am at a complete loss why the events from Java are showing up while the Native calls and events are not. Please help? Thanks
It appears that you are calling the logEvent method with the wrong parameters:
env->CallStaticVoidMethod(flurry_agent_class, logEvent_method, state_->activity->clazz, event_name);
should be
env->CallStaticVoidMethod(flurry_agent_class, logEvent_method, event_name);
because the FlurryAgent.logEvent method only takes in a string, not a context.