135 lines
4.6 KiB
Java
135 lines
4.6 KiB
Java
package com.darkmatter.logrocket;
|
|
|
|
import android.app.Activity;
|
|
import android.app.Application;
|
|
import android.util.Log;
|
|
|
|
import com.logrocket.core.CustomEventBuilder;
|
|
import com.logrocket.core.LogRocket;
|
|
|
|
import org.json.JSONException;
|
|
import org.json.JSONObject;
|
|
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
import java.util.Map;
|
|
|
|
/**
|
|
* Unity to LogRocket Android bridge.
|
|
*
|
|
* This is a loose .java source file: Unity compiles it into the unityLibrary
|
|
* Gradle module, which carries the LogRocket Maven dependency added by the
|
|
* External Dependency Manager (see LogRocketDependencies.xml). That lets us call
|
|
* the SDK directly - including the init/getSessionURL lambdas - instead of
|
|
* reflecting, so there is no functional-interface name to guess.
|
|
*
|
|
* Because the calls are direct, Android builds REQUIRE the LogRocket AAR: keep
|
|
* the androidPackage entry in LogRocketDependencies.xml enabled, or this file
|
|
* will fail to compile.
|
|
*
|
|
* API verified against the LogRocket Android SDK 3.x
|
|
* (docs.logrocket.com/reference/android): com.logrocket.core.LogRocket,
|
|
* com.logrocket.core.CustomEventBuilder.
|
|
*/
|
|
public final class LogRocketUnityBridge {
|
|
private static final String TAG = "LogRocketBridge";
|
|
private static volatile String sessionUrl;
|
|
|
|
private LogRocketUnityBridge() {
|
|
}
|
|
|
|
public static void init(Activity activity, String appId) {
|
|
try {
|
|
Application app = activity.getApplication();
|
|
// Docs recommend init from a custom Application.attachBaseContext for
|
|
// earliest-startup capture. Runtime init from the current activity
|
|
// (as the React Native SDK does) works but misses the launch window.
|
|
LogRocket.init(app, app.getBaseContext(), options -> options.setAppID(appId));
|
|
LogRocket.getSessionURL(url -> sessionUrl = url);
|
|
Log.i(TAG, "LogRocket initialized: " + appId);
|
|
} catch (Throwable t) {
|
|
Log.e(TAG, "init failed", t);
|
|
}
|
|
}
|
|
|
|
public static void identify(String userId, String traitsJson) {
|
|
try {
|
|
Map<String, String> traits = parse(traitsJson);
|
|
if (traits.isEmpty()) {
|
|
LogRocket.identify(userId);
|
|
} else {
|
|
LogRocket.identify(userId, traits);
|
|
}
|
|
} catch (Throwable t) {
|
|
Log.e(TAG, "identify failed", t);
|
|
}
|
|
}
|
|
|
|
public static void track(String name, String propsJson) {
|
|
try {
|
|
CustomEventBuilder builder = new CustomEventBuilder(name);
|
|
for (Map.Entry<String, String> e : parse(propsJson).entrySet()) {
|
|
builder.put(e.getKey(), e.getValue());
|
|
}
|
|
LogRocket.track(builder);
|
|
} catch (Throwable t) {
|
|
Log.e(TAG, "track failed", t);
|
|
}
|
|
}
|
|
|
|
public static void log(String severity, String message) {
|
|
// LogRocket auto-captures logcat, so emitting here is enough to record it.
|
|
Log.println(level(severity), TAG, message == null ? "" : message);
|
|
}
|
|
|
|
public static void logException(String message, String stack) {
|
|
Log.e(TAG, (message == null ? "" : message) + "\n" + (stack == null ? "" : stack));
|
|
}
|
|
|
|
public static String getSessionUrl() {
|
|
return sessionUrl;
|
|
}
|
|
|
|
// Recording starts automatically at init. These provide manual control,
|
|
// verified against the 3.1.0 AAR: endSession() halts the current recording
|
|
// (SDK stays alive), startNewSession() begins a fresh one.
|
|
public static void startReplay() {
|
|
try {
|
|
LogRocket.startNewSession();
|
|
} catch (Throwable t) {
|
|
Log.e(TAG, "startReplay failed", t);
|
|
}
|
|
}
|
|
|
|
public static void stopReplay() {
|
|
try {
|
|
LogRocket.endSession();
|
|
} catch (Throwable t) {
|
|
Log.e(TAG, "stopReplay failed", t);
|
|
}
|
|
}
|
|
|
|
private static int level(String severity) {
|
|
if ("error".equals(severity)) return Log.ERROR;
|
|
if ("warn".equals(severity)) return Log.WARN;
|
|
if ("debug".equals(severity)) return Log.DEBUG;
|
|
return Log.INFO;
|
|
}
|
|
|
|
private static Map<String, String> parse(String json) {
|
|
Map<String, String> 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 key = it.next();
|
|
out.put(key, String.valueOf(obj.get(key)));
|
|
}
|
|
} catch (JSONException e) {
|
|
Log.w(TAG, "bad json: " + json);
|
|
}
|
|
return out;
|
|
}
|
|
}
|