Skip to content

Commit f5d19b2

Browse files
committed
⚡ Performance optimization in android session recording react native
1 parent 69215ea commit f5d19b2

14 files changed

Lines changed: 793 additions & 203 deletions

app/build.gradle

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44

55
android {
66
namespace 'io.middleware.android.sample'
7-
compileSdk 34
7+
compileSdk 35
88
def secretPropertiesFile = rootProject.file("secrets.properties")
99
def secretProperties = new Properties()
1010
secretProperties.load(new FileInputStream(secretPropertiesFile))
@@ -48,7 +48,6 @@ android {
4848
}
4949

5050
dependencies {
51-
implementation 'io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom-alpha:1.32.1-alpha'
5251
implementation 'androidx.appcompat:appcompat:1.6.1'
5352
implementation 'com.google.android.material:material:1.10.0'
5453
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22
plugins {
3-
id 'com.android.application' version '8.1.2' apply false
4-
id 'com.android.library' version '8.1.2' apply false
3+
id 'com.android.application' version '8.6.1' apply false
4+
id 'com.android.library' version '8.6.1' apply false
55
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#Mon Oct 30 17:29:45 IST 2023
22
distributionBase=GRADLE_USER_HOME
33
distributionPath=wrapper/dists
4-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip
4+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
55
zipStoreBase=GRADLE_USER_HOME
66
zipStorePath=wrapper/dists

sdk/build.gradle

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,11 @@ plugins {
22
id 'com.android.library'
33
id "com.vanniktech.maven.publish" version "0.34.0"
44
}
5-
65
mavenPublishing {
76
publishToMavenCentral(true)
87
signAllPublications()
98

10-
coordinates("io.github.middleware-labs", "android-sdk", "2.0.8-rn")
9+
coordinates("io.github.middleware-labs", "android-sdk", "2.0.9-rn")
1110

1211
pom {
1312
name = "Middleware Android RUM SDK"
@@ -37,7 +36,7 @@ mavenPublishing {
3736
}
3837
android {
3938
namespace 'io.middleware.android.sdk'
40-
compileSdk 34
39+
compileSdk 35
4140

4241
defaultConfig {
4342
minSdk 21
@@ -86,6 +85,7 @@ dependencies {
8685
implementation 'org.apache.commons:commons-lang3:3.13.0'
8786
implementation 'commons-codec:commons-codec:1.16.0'
8887
implementation 'androidx.annotation:annotation-jvm:1.9.1'
88+
implementation 'androidx.compose.ui:ui-android:1.9.5'
8989
implementation 'androidx.fragment:fragment:1.8.6'
9090
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.0.4"
9191
testImplementation('org.mockito:mockito-core:5.7.0')

sdk/src/main/java/io/middleware/android/sdk/Middleware.java

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
import android.app.Activity;
1414
import android.app.Application;
15+
import android.content.Context;
1516
import android.location.Location;
1617
import android.os.Build;
1718
import android.os.Handler;
@@ -34,7 +35,7 @@
3435
import io.middleware.android.sdk.core.models.NativeRumSessionId;
3536
import io.middleware.android.sdk.core.replay.MiddlewareRecorder;
3637
import io.middleware.android.sdk.core.replay.ReplayRecording;
37-
import io.middleware.android.sdk.core.replay.v2.ActivityCallbacks;
38+
import io.middleware.android.sdk.core.replay.v2.LifecycleManager;
3839
import io.middleware.android.sdk.core.replay.v2.MiddlewareScreenshotManager;
3940
import io.middleware.android.sdk.extractors.RumResponseAttributesExtractor;
4041
import io.middleware.android.sdk.interfaces.IMiddleware;
@@ -94,28 +95,26 @@ public static MiddlewareBuilder builder() {
9495
// for testing purposes
9596
public static Middleware initialize(
9697
MiddlewareBuilder builder,
97-
Application application,
98+
Context context,
9899
Function<Application, CurrentNetworkProvider> currentNetworkProviderFactory) {
99100
if (INSTANCE != null) {
100101
Log.w(LOG_TAG, "Singleton Middleware instance has already been initialized.");
101102
return INSTANCE;
102103
}
103-
104-
rumInitializer = new RumInitializer(builder, application, startupTimer);
104+
final LifecycleManager lifecycleManager = new LifecycleManager(context.getApplicationContext(),
105+
(context instanceof Activity)
106+
? (Activity) context
107+
: null);
108+
rumInitializer = new RumInitializer(builder, context, startupTimer);
105109
INSTANCE = rumInitializer.initialize(currentNetworkProviderFactory, Looper.getMainLooper());
106110
LOGGER = INSTANCE.getOpenTelemetry().getLogsBridge()
107111
.loggerBuilder(builder.serviceName)
108112
.build();
109113
if (builder.isRecordingEnabled()) {
110114
Log.d(LOG_TAG, "Session recording enabled, waiting layout to get attached.");
111115
middlewareScreenshotManager = new MiddlewareScreenshotManager(
112-
System.currentTimeMillis(),
113-
builder.target,
114-
builder.rumAccessToken
116+
builder, lifecycleManager
115117
);
116-
application.registerActivityLifecycleCallbacks(
117-
new ActivityCallbacks(middlewareScreenshotManager))
118-
;
119118
}
120119
Log.i(LOG_TAG, "Middleware RUM monitoring initialized with session ID: " + INSTANCE.getRumSessionId());
121120
return INSTANCE;
@@ -151,23 +150,12 @@ public MiddlewareRecorder getRecorder() {
151150
return new MiddlewareRecorder(this);
152151
}
153152

154-
public void startNativeRecording(Activity activity) {
153+
public void startNativeRecording() {
155154
if (middlewareScreenshotManager != null) {
156-
middlewareScreenshotManager.setActivity(activity);
155+
middlewareScreenshotManager.start(System.currentTimeMillis());
157156
}
158157
}
159158

160-
/**
161-
* @return {@code true} if the recording started successfully.
162-
*/
163-
public boolean startRecording() {
164-
if (middlewareScreenshotManager != null) {
165-
middlewareScreenshotManager.start();
166-
return true;
167-
}
168-
return false;
169-
}
170-
171159
/**
172160
* @return @{code true} if session recording stopped successfully.
173161
*/

sdk/src/main/java/io/middleware/android/sdk/builders/MiddlewareBuilder.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static io.middleware.android.sdk.utils.Constants.LOG_TAG;
55

66
import android.app.Application;
7+
import android.content.Context;
78
import android.util.Log;
89

910
import androidx.annotation.Nullable;
@@ -12,6 +13,9 @@
1213

1314
import io.middleware.android.sdk.Middleware;
1415
import io.middleware.android.sdk.core.models.ConfigFlags;
16+
import io.middleware.android.sdk.core.replay.RecordingFrequency;
17+
import io.middleware.android.sdk.core.replay.RecordingQuality;
18+
import io.middleware.android.sdk.core.replay.v2.RecordingOptions;
1519
import io.opentelemetry.android.instrumentation.network.CurrentNetworkProvider;
1620
import io.opentelemetry.api.common.Attributes;
1721

@@ -33,6 +37,10 @@ public final class MiddlewareBuilder {
3337
public Attributes globalAttributes = Attributes.empty();
3438
@Nullable
3539
public String deploymentEnvironment;
40+
public RecordingOptions recordingOptions = new RecordingOptions.Builder()
41+
.setFrequency(RecordingFrequency.LOW)
42+
.setQuality(RecordingQuality.LOW)
43+
.build();
3644

3745
/**
3846
* Sets the application name that will be used to identify your application in the Middleware RUM
@@ -198,12 +206,12 @@ public MiddlewareBuilder setDeploymentEnvironment(String environment) {
198206
* Middleware#getInstance()}. If there was a global {@link Middleware} instance configured before,
199207
* this method does not initialize a new one and simply returns the existing instance.
200208
*/
201-
public Middleware build(Application application) {
209+
public Middleware build(Context context) {
202210
if (rumAccessToken == null || target == null || projectName == null || serviceName == null) {
203211
throw new IllegalStateException(
204212
"You must provide a rumAccessToken, target, projectName and an serviceName to create a valid Config instance.");
205213
}
206-
return Middleware.initialize(this, application, CurrentNetworkProvider::createAndStart);
214+
return Middleware.initialize(this, context, CurrentNetworkProvider::createAndStart);
207215
}
208216

209217
public boolean isAnrDetectionEnabled() {

sdk/src/main/java/io/middleware/android/sdk/core/RumInitializer.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import static io.opentelemetry.semconv.ResourceAttributes.DEPLOYMENT_ENVIRONMENT;
1010
import static io.opentelemetry.semconv.ResourceAttributes.SERVICE_NAME;
1111

12+
import android.app.Activity;
1213
import android.app.Application;
14+
import android.content.Context;
1315
import android.os.Looper;
1416
import android.util.Log;
1517

@@ -63,9 +65,15 @@ public class RumInitializer implements IRum {
6365
private final AppStartupTimer appStartupTimer;
6466
private final InitializationEvents initializerEvent;
6567

66-
public RumInitializer(MiddlewareBuilder builder, Application application, AppStartupTimer appStartupTimer) {
68+
public RumInitializer(MiddlewareBuilder builder, Context context, AppStartupTimer appStartupTimer) {
6769
this.builder = builder;
68-
this.application = application;
70+
if (context instanceof Activity) {
71+
this.application = ((Activity) context).getApplication();
72+
} else if (context instanceof Application) {
73+
this.application = (Application) context;
74+
} else {
75+
this.application = (Application) context.getApplicationContext();
76+
}
6977
this.appStartupTimer = appStartupTimer;
7078
this.initializerEvent = new InitializationEvents(appStartupTimer);
7179
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package io.middleware.android.sdk.core.replay;
2+
3+
/**
4+
* Defines how often screenshots are captured.
5+
*/
6+
public enum RecordingFrequency {
7+
LOW(1000L), // 1 FPS
8+
STANDARD(330L), // ~3 FPS
9+
HIGH(100L); // 10 FPS
10+
11+
private final long intervalMs;
12+
13+
RecordingFrequency(long intervalMs) {
14+
this.intervalMs = intervalMs;
15+
}
16+
17+
public long getIntervalMs() {
18+
return intervalMs;
19+
}
20+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package io.middleware.android.sdk.core.replay;
2+
3+
public enum RecordingQuality {
4+
LOW(25),
5+
MEDIUM(50),
6+
HIGH(75);
7+
8+
private final int value;
9+
10+
RecordingQuality(int value) {
11+
this.value = value;
12+
}
13+
14+
public int getValue() {
15+
return value;
16+
}
17+
}

sdk/src/main/java/io/middleware/android/sdk/core/replay/v2/ActivityCallbacks.java

Lines changed: 0 additions & 54 deletions
This file was deleted.

0 commit comments

Comments
 (0)