Skip to content
This repository was archived by the owner on Aug 8, 2025. It is now read-only.

Commit 2891a63

Browse files
authored
Merge pull request #75 from taplytics/TAP-4426-kotlin-docs
kotlin documentation
2 parents 207ab65 + c773f51 commit 2891a63

File tree

4 files changed

+1059
-0
lines changed

4 files changed

+1059
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,4 @@ proguard/
2424

2525
# Mac
2626
.DS_Store
27+
.history/*

Kotlin/EXPERIMENTS.md

Lines changed: 326 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,326 @@
1+
Creating experiments is easy using Taplytics. You can either use our visual editor or create code-based experiments. You can find documentation on how to do this below.
2+
3+
| Table of Contents |
4+
| ----------------- |
5+
| [Feature Flags](#feature-flags)|
6+
| [Dynamic Variables](#dynamic-variables) |
7+
| [Code Blocks](#code-blocks) |
8+
| [Testing Specific Experiments](#testing-specific-experiments) |
9+
| [Visual Editing](#visual-editing) |
10+
| [First-view Experiments](#delay-load) |
11+
| [List Running Experiments](#running-experiments) |
12+
13+
## Feature Flags
14+
15+
Taplytics feature flags operate in synchronous mode.
16+
17+
#### Synchronous
18+
19+
Synchronous feature flags are guaranteed to have the same value for the entire session and will have that value immediately after construction.
20+
21+
Due to the synchronous nature of feature flags, if it is used before the feature flags have been loaded from Taplytics servers (for example on the first launch of your app), it will default to as if the feature flag is not present. In order to prevent this you can ensure that the feature flag is loaded before using the feature flag. This can be done with either the `delayLoad` functionality, the `TaplyticsExperimentsLoadedListener` parameter in your `startTaplytics` call, or the `getRunningExperimentsAndVariations` call:
22+
23+
```kotlin
24+
if (Taplytics.featureFlagEnabled("featureFlagKey")) {
25+
//Put feature code here, or launch feature from here
26+
}
27+
```
28+
29+
#### Setting a Default value
30+
31+
In the event that Taplytics was unable to load, Taplytics will by default return FALSE when using ```featureFlagEnabled```. To prevent this behavour and instead default a feature to being ON in cases of no network, pass in the desired default behavior.
32+
33+
```kotlin
34+
if (Taplytics.featureFlagEnabled("featureFlagKey", true)) {
35+
//Put feature code here, or launch feature from here
36+
}
37+
```
38+
39+
40+
## Running Feature Flags
41+
42+
If you would like to see which feature flags are running on a given device, there exists a `getRunningFeatureFlags(TaplyticsRunningFeatureFlagsListener listener)` function which provides a callback with a map of the current feature flags. An example:
43+
44+
```kotlin
45+
Taplytics.getRunningFeatureFlags {
46+
// TODO: Do something with the map.
47+
}
48+
```
49+
50+
## Dynamic Variables
51+
52+
Taplytics variables are values in your app that are controlled by experiments. Changing the values can update the content or functionality of your app. If logging is enabled, logs will show when a variable has been set, updated or when `get()` is called. Variables are reusable between experiments and operate in one of two modes: synchronous or asynchronous.
53+
54+
#### Synchronous
55+
56+
Synchronous variables are guaranteed to have the same value for the entire session and will have that value immediately after construction.
57+
58+
Due to the synchronous nature of the variable, if it is used before the experiments have been loaded, its value will be the default value rather than the value set for that experiment. This could taint the results of the experiment. In order to prevent this you can ensure that the experiments are loaded before using the variable. This can be done with either the `delayLoad` functionality, the `TaplyticsExperimentsLoadedListener` parameter in your `startTaplytics` call, or the `getRunningExperimentsAndVariations` call.
59+
60+
Synchronous variables take two parameters in its constructor:
61+
62+
1. Variable name (String)
63+
2. Default Value
64+
65+
The type of the variable is defined in the first diamond brackets, and can be a `String`, `Number`, `Boolean` or `JSON`.
66+
67+
For example, using a variable of type `String`:
68+
```kotlin
69+
val stringVar = TaplyticsVar("some name", "default value")
70+
```
71+
72+
Then when you wish to get the value for the variable, simply call `get()` on the Taplytics variable:
73+
```kotlin
74+
val value = stringVar.get()
75+
```
76+
77+
#### Asynchronous
78+
79+
Asynchronous variables take care of insuring that the experiments have been loaded before returning a value. This removes any danger of tainting the results of your experiment with bad data. What comes with the insurance of using the correct value is the possibility that the value will not be set immediately. If the variable is constructed *before* the experiments are loaded, you won't have the correct value until the experiments have finished loading. If the experiments fail to load, then you will be given the default value, as specified in the variables constructor. For the best results with asynchronous varaibles make sure that they are constructed after the StartTaplytics call in your app's lifecycle.
80+
81+
Asynchronous variables take three parameters in its constructor:
82+
83+
1. Variable name (String)
84+
2. Default Value
85+
3. TaplyticsVarListener
86+
87+
Just as for synchronous variables the type of the variable is defined in the first diamond brackets, and can be a `String`, `Int`, `Boolean` or `JSON`.
88+
89+
For example, using a variable of type `Int`:
90+
91+
```kotlin
92+
val `var`: TaplyticsVar<Int> =
93+
TaplyticsVar<Int>("name", 5, TaplyticsVarListener {
94+
// Do something with the value
95+
})
96+
```
97+
98+
When the variable's value has been updated, the listener will be called with that updated value. You can specify what you want to do with the variable inside the `variableUpdated` method.
99+
100+
**Note: Default values for dynamic variables cannot be NULL. NULL values may cause default to trigger in all scenarios**
101+
102+
----------
103+
104+
#### Testing Dynamic Variables
105+
106+
When testing dynamic variables in live update mode you can change the values on the fly via the Taplytics interface and you can switch variations with the shake menu on the device.
107+
108+
**Important Note:** When testing synchronous dynamic variables you *must* call the constructor again to see the new value, as there are no callbacks which occur when the variable is updated with a new value.
109+
110+
This can be achieved by using a experiments updated listener. Here is an example for updating a TextView:
111+
112+
113+
``` kotlin
114+
115+
Taplytics.setTaplyticsExperimentsUpdatedListener {
116+
val stringVar = TaplyticsVar("stringVar", "defaultValue")
117+
updateText(stringVar.get())
118+
}
119+
```
120+
## Code Blocks
121+
122+
Similar to Dynamic Variables, Taplytics has an option for 'Code Blocks'. Code blocks are linked to Experiments through the Taplytics website very much the same way that Dynamic Variables are, and will be executed based on the configuration of the experiment through the Taplytics website. A Code Block is a callback that can be enabled or disabled depending on the variation. If enabled, the code within the callback will be executed. If disabled, the variation will not get the callback.
123+
124+
A Code Block can be used alongside as many other Code Blocks as you would like to determine a combination that yields the best results. Perhaps there are three different Code Blocks on one activity. This means there could be 8 different combinations of Code Blocks being enabled / disabled on that activity if you'd like.
125+
126+
For example:
127+
128+
```kotlin
129+
Taplytics.runCodeBlock("name") {
130+
// Put your code here!
131+
}
132+
```
133+
134+
By default, a code block will _not_ run unless enabled on the Taplytics Dashboard. It must be enabled for a Variation before it will run.
135+
136+
## Testing Specific Experiments
137+
138+
To test/QA specific experiment and variation combinations, add a map to the Taplytics start options containing the experiments and variations you wish to test. The keys should be the experiment names, and values of variation names (or baseline).
139+
140+
For example:
141+
142+
143+
```kotlin
144+
val startOptions: HashMap<String, Any> = HashMap()
145+
val testExperiments = HashMap<Any, Any>()
146+
testExperiments["Big Experiment"] = "Variation 2"
147+
startOptions["testExperiments"] = testExperiments
148+
149+
Taplytics.startTaplytics(this, APIKEY, startOptions)
150+
```
151+
## Visual Editing
152+
153+
**NOTE: Not currently fully supported for Android TV / Fire TV**
154+
155+
You don't have to do anything else! You can use the Taplytics dashboard to make all your visual changes. See the docs on visual editing [here](https://taplytics.com/docs/guides/visual-experiments).
156+
157+
#### Dialogs
158+
159+
Taplytics supports editing elements on **dialogFragments** (not dialogs). To do this properly, you must use a fragmentTransaction to add the fragment to the backstack. The tag used here should be the same as the tag used to show the fragment, like so:
160+
161+
```kotlin
162+
val fragmentTransaction: FragmentTransaction = fragmentManager.beginTransaction()
163+
fragmentTransaction.show(someDialog)
164+
fragmentTransaction.addToBackStack("fragment_some_dialog")
165+
someDialog.show(fragmentTransaction, "fragment_some_dialog")
166+
```
167+
168+
Taplytics tracks the appearance/disappearance of the dialog via the backstack manager, which is why it needs to be sent there. The tag is necessary to confirm that the visual edits are being applied to the correct fragment.
169+
170+
This only works with dialogFragments as normal Dialogs do not have any unique identifying tags.
171+
172+
**NOTE:**
173+
174+
dialogFragments exist on an entirely different view hierarchy than traditional view elements. They exist within their own `window` and have an entirely different viewRoot than the rest of your application. This makes changes on dialogs very difficult, and this feature is not 100% guaranteed to work for all dialogs.
175+
176+
---
177+
178+
## Delay Load
179+
180+
Taplytics has the option to delay the loading of your main activity while Taplytics gets initial ***view*** changes ready. Keep in mind that this initial load will only take some time the very first time, after that, these changes will be saved to disk and will likely not need a delay.
181+
182+
There are two methods to do this, **use both at the start of your ```kotlin onCreate()``` after ```kotlin setContentView()```**:
183+
184+
#### Delay Load With Image
185+
In this instance, Taplytics takes care of the loading for you. Taplytics creates a splash screen with the provided image. The image will fade automatically after the given time, or when Taplytics has successfully loaded visual changes on the provided activity.
186+
187+
Method: ```Taplytics.delayLoad(Activity activity, Drawable image, int maxTime) ```
188+
189+
and ```Taplytics.delayLoad(Activity activity, Drawable image, int maxTime)```
190+
191+
192+
**Activity**: the activity (typically main activity) that will be covered in a splash image.
193+
194+
**Image**: A Drawable image that will be the splash screen.
195+
196+
**maxTime**: Regardless of the results of Taplytics, the image will fade after this time. Milliseconds.
197+
198+
**minTime**: Sometimes Taplytics loads things really fast, and this might make the image show only for a short amount of time. To keep this from happening, there is an optional minimum time option. Regardless of Taplytics loading experiments, the ```delayLoad``` won't finish until after this minimum time. Milliseconds.
199+
200+
**Examples**:
201+
202+
```kotlin
203+
override fun onCreate(Bundle savedInstanceState) {
204+
super.onCreate(savedInstanceState)
205+
setContentView(R.layout.main_layout);
206+
207+
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000);
208+
...
209+
```
210+
211+
**With a 1 second minimum time**
212+
213+
```kotlin
214+
Taplytics.delayLoad(this, getResources().getDrawable(R.drawable.image5), 2000, 1000);
215+
...
216+
```
217+
218+
#### Delay Load with Callbacks
219+
In this instance, Taplytics provides callbacks when the delay load should begin, and when the delay load ends. The callback will also return after the provided timeout time has been reached. This provides you the ability to show a splashscreen that is more than just a simple image.
220+
221+
Method: ```Taplytics.delayLoad(int maxTime, TaplyticsDelayLoadListener listener) ```
222+
223+
and ```Taplytics.delayLoad(int maxTime, int minTime, TaplyticsDelayLoadListener listener) ```
224+
225+
226+
227+
**maxTime**: Regardless of the results of Taplytics, this callback will be triggered if this time is reached.
228+
229+
**minTime**: Sometimes Taplytics loads things really fast, and this might make the behavior of the callback undesirable. To keep this from happening, there is an optional minimum time option. Regardless of Taplytics loading experiments, the ```delayLoad``` won't finish until after this minimum time.
230+
231+
**Listener**: This listener will provide the necessary callbacks.
232+
233+
**Examples**:
234+
235+
```kotlin
236+
protected fun onCreate(savedInstanceState: Bundle?) {
237+
super.onCreate(savedInstanceState)
238+
setContentView(R.layout.main_layout)
239+
Taplytics.delayLoad(2000, object : TaplyticsDelayLoadListener {
240+
override fun startDelay() {
241+
//Start delaying!
242+
}
243+
244+
override fun delayComplete() {
245+
//Loading completed, or the given time has been reached. Insert your code here.
246+
}
247+
})
248+
...
249+
}
250+
```
251+
252+
**With a 1 second minimum time:**
253+
254+
```kotlin
255+
Taplytics.delayLoad(2000, 1000, ...
256+
```
257+
258+
---
259+
260+
## Running Experiments
261+
262+
If you would like to see which variations and experiments are running on a given device, there exists a `getRunningExperimentsAndVariations(TaplyticsRunningExperimentsListener listener)` function which provides a callback with a map of the current experiments and their running variation. If logging is enabled, logs will also show this map.
263+
264+
An example:
265+
266+
```kotlin
267+
Taplytics.getRunningExperimentsAndVariations {
268+
// TODO: Do something with the map.
269+
}
270+
```
271+
272+
NOTE: This function runs asynchronously, as it waits for the updated properties to load from Taplytics' servers before returning the running experiments.
273+
274+
If you want to see when the experiments have been loaded by Taplytics, you can add a `TaplyticsExperimentLoadedListener` to your `startTaplytics` call. For example
275+
276+
```kotlin
277+
Taplytics.startTaplytics(
278+
this,
279+
"YOUR API KEY",
280+
null
281+
) {
282+
//TODO: Do something now that experiments are loaded
283+
}
284+
```
285+
286+
## Sessions
287+
288+
By default, Taplytics defines a session as when a user is using the app with less than 10 minutes of inactivity. If the app has been backgrounded for 10 minutes, the next time the user opens the app it will be considered a new session. Similarly, if the app is entirely force closed, the next time the app is opened, it will be considered a new session.
289+
290+
### StartNewSession
291+
292+
To manually force a new user session (ex: A user has logged in / out), there exists ```Taplytics.startNewSession```
293+
294+
If there is an internet connection, a new session will be created, and new experiments/variations will be fetched from Taplytics if they exist. If logging is enabled, logs will show when a new session has been started or if an error has occurred.
295+
296+
It can be used as follows:
297+
298+
```kotlin
299+
Taplytics.startNewSession(object : TaplyticsNewSessionListener {
300+
override fun onNewSession() {
301+
// New session here! Only returns if successful.
302+
}
303+
304+
override fun onError() {
305+
// No new session here! Only returns if unsuccessful.
306+
}
307+
})
308+
```
309+
310+
### Session Listener
311+
312+
To keep track of when Taplytics defines a new session, use a `TaplyticsNewSessionListener` as follows.
313+
314+
```kotlin
315+
Taplytics.setTaplyticsNewSessionListener(object : TaplyticsNewSessionListener {
316+
override fun onNewSession() {
317+
//We are in a new session
318+
}
319+
320+
override fun onError() {
321+
//We are not in a new session
322+
}
323+
})
324+
```
325+
326+
**Note that this is NOT called the first time Taplytics loads, only on subsequent sessions**

0 commit comments

Comments
 (0)