Skip to content

Commit bb6a0c8

Browse files
authored
Merge pull request #18 from optimizely/load-from-resources
Implements API for compiling in data file with an app
2 parents 0798078 + eb13cbb commit bb6a0c8

File tree

3 files changed

+71
-9
lines changed

3 files changed

+71
-9
lines changed

android-sdk/src/main/java/com/optimizely/ab/android/sdk/OptimizelyManager.java

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,27 @@
2222
import android.content.Context;
2323
import android.content.Intent;
2424
import android.content.ServiceConnection;
25+
import android.content.res.Resources;
2526
import android.os.AsyncTask;
2627
import android.os.Bundle;
2728
import android.os.IBinder;
2829
import android.support.annotation.NonNull;
2930
import android.support.annotation.Nullable;
31+
import android.support.annotation.RawRes;
3032

3133
import com.optimizely.ab.Optimizely;
3234
import com.optimizely.ab.android.event_handler.OptlyEventHandler;
3335
import com.optimizely.ab.android.shared.ServiceScheduler;
3436
import com.optimizely.ab.bucketing.UserExperimentRecord;
37+
import com.optimizely.ab.config.parser.ConfigParseException;
3538
import com.optimizely.ab.event.internal.payload.Event;
3639
import com.optimizely.user_experiment_record.AndroidUserExperimentRecord;
3740

3841
import org.slf4j.Logger;
3942
import org.slf4j.LoggerFactory;
4043

44+
import java.io.IOException;
45+
import java.io.InputStream;
4146
import java.util.concurrent.Executor;
4247
import java.util.concurrent.Executors;
4348
import java.util.concurrent.TimeUnit;
@@ -128,6 +133,38 @@ public AndroidOptimizely getOptimizely() {
128133
return androidOptimizely;
129134
}
130135

136+
@NonNull
137+
public AndroidOptimizely getOptimizely(@NonNull Context context, @RawRes int dataFileRes) {
138+
AndroidUserExperimentRecord userExperimentRecord =
139+
(AndroidUserExperimentRecord) AndroidUserExperimentRecord.newInstance(getProjectId(), context);
140+
// Blocking File I/O is necessary here in order to provide a synchronous API
141+
// The User Experiment Record is started off the of the main thread when starting
142+
// asynchronously. Starting simply creates the file if it doesn't exist so it's not
143+
// terribly expensive. Blocking the UI the thread prevents touch input...
144+
userExperimentRecord.start();
145+
try {
146+
androidOptimizely = buildOptimizely(context, loadRawResource(context, dataFileRes), userExperimentRecord);
147+
} catch (ConfigParseException e) {
148+
logger.error("Unable to parse compiled data file", e);
149+
} catch (IOException e) {
150+
logger.error("Unable to load compiled data file", e);
151+
}
152+
153+
return androidOptimizely;
154+
}
155+
156+
private String loadRawResource(Context context, @RawRes int rawRes) throws IOException {
157+
Resources res = context.getResources();
158+
InputStream in = res.openRawResource(rawRes);
159+
byte[] b = new byte[in.available()];
160+
int read = in.read(b);
161+
if (read > -1) {
162+
return new String(b);
163+
} else {
164+
throw new IOException("Couldn't parse raw res fixture, no bytes");
165+
}
166+
}
167+
131168
@NonNull
132169
public String getProjectId() {
133170
return projectId;
@@ -148,16 +185,8 @@ protected void onPostExecute(UserExperimentRecord userExperimentRecord) {
148185
serviceScheduler.schedule(intent, dataFileDownloadIntervalTimeUnit.toMillis(dataFileDownloadInterval));
149186

150187
try {
151-
OptlyEventHandler eventHandler = OptlyEventHandler.getInstance(context);
152-
eventHandler.setDispatchInterval(eventHandlerDispatchInterval, eventHandlerDispatchIntervalTimeUnit);
153-
Optimizely optimizely = Optimizely.builder(dataFile, eventHandler)
154-
.withUserExperimentRecord(userExperimentRecord)
155-
.withClientEngine(Event.ClientEngine.ANDROID_SDK)
156-
.withClientVersion(BuildConfig.CLIENT_VERSION)
157-
.build();
188+
OptimizelyManager.androidOptimizely = buildOptimizely(context, dataFile, userExperimentRecord);
158189
logger.info("Sending Optimizely instance to listener");
159-
AndroidOptimizely androidOptimizely = new AndroidOptimizely(optimizely);
160-
OptimizelyManager.androidOptimizely = androidOptimizely;
161190

162191
if (optimizelyStartListener != null) {
163192
optimizelyStartListener.onStart(androidOptimizely);
@@ -176,6 +205,17 @@ protected void onPostExecute(UserExperimentRecord userExperimentRecord) {
176205
initUserExperimentRecordTask.executeOnExecutor(executor);
177206
}
178207

208+
private AndroidOptimizely buildOptimizely(@NonNull Context context, @NonNull String dataFile, @NonNull UserExperimentRecord userExperimentRecord) throws ConfigParseException {
209+
OptlyEventHandler eventHandler = OptlyEventHandler.getInstance(context);
210+
eventHandler.setDispatchInterval(eventHandlerDispatchInterval, eventHandlerDispatchIntervalTimeUnit);
211+
Optimizely optimizely = Optimizely.builder(dataFile, eventHandler)
212+
.withUserExperimentRecord(userExperimentRecord)
213+
.withClientEngine(Event.ClientEngine.ANDROID_SDK)
214+
.withClientVersion(BuildConfig.CLIENT_VERSION)
215+
.build();
216+
return new AndroidOptimizely(optimizely);
217+
}
218+
179219
public static class OptlyActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
180220

181221
@NonNull private OptimizelyManager optimizelyManager;

test-app/src/main/java/com/optimizely/ab/android/test_app/MainActivity.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,17 @@ protected void onCreate(Bundle savedInstanceState) {
3838
// This could also be done via DI framework such as Dagger
3939
optimizelyManager = ((MyApplication) getApplication()).getOptimizelyManager();
4040

41+
// Load Optimizely from a compiled in data file
42+
AndroidOptimizely optimizely = optimizelyManager.getOptimizely(this, R.raw.data_file);
43+
Variation variation = optimizely.activate("experiment_0", "user_1");
44+
if (variation != null) {
45+
if (variation.is("variation_1")) {
46+
Toast.makeText(MainActivity.this, "Variation 1", Toast.LENGTH_LONG).show();
47+
} else {
48+
Toast.makeText(MainActivity.this, "Default", Toast.LENGTH_LONG).show();
49+
}
50+
}
51+
4152
findViewById(R.id.button1).setOnClickListener(new View.OnClickListener() {
4253
@Override
4354
public void onClick(View v) {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"experiments": [ ],
3+
"version": "2",
4+
"audiences": [ ],
5+
"groups": [ ],
6+
"attributes": [ ],
7+
"projectId": "7595190003",
8+
"accountId": "6365361536",
9+
"events": [ ],
10+
"revision": "1"
11+
}

0 commit comments

Comments
 (0)