|
|
|
|
@@ -0,0 +1,160 @@
|
|
|
|
|
package com.darkmatter.logrocket;
|
|
|
|
|
|
|
|
|
|
import android.app.Activity;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
|
|
|
|
|
import org.json.JSONObject;
|
|
|
|
|
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Thin Unity-facing wrapper around the LogRocket Android SDK.
|
|
|
|
|
*
|
|
|
|
|
* The LogRocket native SDK API surface is reached via reflection so the Unity
|
|
|
|
|
* project will compile even if the LogRocket Maven artifact has not been added
|
|
|
|
|
* yet. To enable, drop the LogRocket AAR into Plugins/Android (or add the
|
|
|
|
|
* Maven coordinate to mainTemplate.gradle) and the calls below resolve at
|
|
|
|
|
* runtime.
|
|
|
|
|
*
|
|
|
|
|
* Expected LogRocket SDK class: com.logrocket.core.LogRocket
|
|
|
|
|
* static void init(android.content.Context, String appId)
|
|
|
|
|
* static void identify(String userId, java.util.Map traits)
|
|
|
|
|
* static void track(String name, java.util.Map properties)
|
|
|
|
|
* static void log(String severity, String message)
|
|
|
|
|
* static String getSessionURL()
|
|
|
|
|
*/
|
|
|
|
|
public final class LogRocketUnityBridge {
|
|
|
|
|
private static final String TAG = "LogRocketBridge";
|
|
|
|
|
private static final String LR_CLASS = "com.logrocket.core.LogRocket";
|
|
|
|
|
|
|
|
|
|
private static LogRocketUnityBridge INSTANCE;
|
|
|
|
|
|
|
|
|
|
private Class<?> lrClass;
|
|
|
|
|
private boolean replayActive;
|
|
|
|
|
|
|
|
|
|
public static synchronized LogRocketUnityBridge getInstance() {
|
|
|
|
|
if (INSTANCE == null) INSTANCE = new LogRocketUnityBridge();
|
|
|
|
|
return INSTANCE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void init(Activity activity, String appId) {
|
|
|
|
|
try {
|
|
|
|
|
lrClass = Class.forName(LR_CLASS);
|
|
|
|
|
lrClass.getMethod("init", android.content.Context.class, String.class)
|
|
|
|
|
.invoke(null, activity.getApplicationContext(), appId);
|
|
|
|
|
Log.i(TAG, "LogRocket initialised: " + appId);
|
|
|
|
|
} catch (ClassNotFoundException notFound) {
|
|
|
|
|
Log.e(TAG, "LogRocket SDK class not found. Add the LogRocket Android dependency.");
|
|
|
|
|
lrClass = null;
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "LogRocket init failed", t);
|
|
|
|
|
lrClass = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void identify(String userId, String traitsJson) {
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
Map<String, Object> traits = parse(traitsJson);
|
|
|
|
|
lrClass.getMethod("identify", String.class, Map.class).invoke(null, userId, traits);
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "identify failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void track(String name, String propsJson) {
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
Map<String, Object> props = parse(propsJson);
|
|
|
|
|
lrClass.getMethod("track", String.class, Map.class).invoke(null, name, props);
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "track failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void log(String severity, String message) {
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
lrClass.getMethod("log", String.class, String.class).invoke(null, severity, message);
|
|
|
|
|
} catch (NoSuchMethodException nsme) {
|
|
|
|
|
Log.i(TAG, "[" + severity + "] " + message);
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "log failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void logException(String message, String stack) {
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
lrClass.getMethod("captureException", String.class, String.class).invoke(null, message, stack);
|
|
|
|
|
} catch (NoSuchMethodException nsme) {
|
|
|
|
|
log("error", message + "\n" + stack);
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "logException failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void captureFrame(byte[] jpeg, int width, int height) {
|
|
|
|
|
if (lrClass == null || jpeg == null) return;
|
|
|
|
|
try {
|
|
|
|
|
lrClass.getMethod("captureFrame", byte[].class, int.class, int.class)
|
|
|
|
|
.invoke(null, jpeg, width, height);
|
|
|
|
|
} catch (NoSuchMethodException nsme) {
|
|
|
|
|
// SDK does not expose frame ingest; ignore silently.
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "captureFrame failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void startReplay() {
|
|
|
|
|
replayActive = true;
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
lrClass.getMethod("startCapture").invoke(null);
|
|
|
|
|
} catch (NoSuchMethodException ignored) {
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "startReplay failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void stopReplay() {
|
|
|
|
|
replayActive = false;
|
|
|
|
|
if (lrClass == null) return;
|
|
|
|
|
try {
|
|
|
|
|
lrClass.getMethod("stopCapture").invoke(null);
|
|
|
|
|
} catch (NoSuchMethodException ignored) {
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.e(TAG, "stopReplay failed", t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getSessionUrl() {
|
|
|
|
|
if (lrClass == null) return null;
|
|
|
|
|
try {
|
|
|
|
|
Object url = lrClass.getMethod("getSessionURL").invoke(null);
|
|
|
|
|
return url == null ? null : url.toString();
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Map<String, Object> parse(String json) {
|
|
|
|
|
Map<String, Object> out = new HashMap<>();
|
|
|
|
|
if (json == null || json.isEmpty()) return out;
|
|
|
|
|
try {
|
|
|
|
|
JSONObject obj = new JSONObject(json);
|
|
|
|
|
Iterator<String> it = obj.keys();
|
|
|
|
|
while (it.hasNext()) {
|
|
|
|
|
String k = it.next();
|
|
|
|
|
out.put(k, obj.get(k));
|
|
|
|
|
}
|
|
|
|
|
} catch (Throwable t) {
|
|
|
|
|
Log.w(TAG, "json parse failed: " + json);
|
|
|
|
|
}
|
|
|
|
|
return out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
</content>
|
|
|
|
|
</invoke>
|