Skip to content

Commit

Permalink
Merge branch 'development'
Browse files Browse the repository at this point in the history
  • Loading branch information
sofakingforever committed Aug 26, 2018
2 parents 68ddeda + c3f3753 commit 9622fc6
Show file tree
Hide file tree
Showing 14 changed files with 180 additions and 56 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Initiate analytics and send events

```kotlin
// init analytics
analytics = Analytics(context = context,
analytics = Analytics(settings = AnalyticsSettings(context),
FirebaseDispatcherImpl(init = true),
MixPanelDispatcherImpl(init = true, projectToken = "TOKEN"),
AnswersDispatcherImpl(init = true))
Expand Down
4 changes: 4 additions & 0 deletions analytics/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ dependencies {
// required if you want to use Mockito for Android tests
androidTestImplementation 'org.mockito:mockito-android:2.7.22'

implementation 'com.squareup.okhttp3:okhttp:3.11.0'



// testCompile 'org.powermock:powermock:1.6.5'
// testCompile 'org.powermock:powermock-module-junit4:1.6.5'
//
Expand Down
56 changes: 37 additions & 19 deletions analytics/src/main/java/com/sofakingforever/analytics/Analytics.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
package com.sofakingforever.analytics

import android.content.Context
import android.util.Log
import com.sofakingforever.analytics.events.base.Event
import com.sofakingforever.analytics.exceptions.EventNotTrackedException
import com.sofakingforever.analytics.version.VersionChecker

/**
* The *Analytics* class is in charge of tracking any *Event* implementation.
Expand All @@ -13,55 +12,74 @@ import com.sofakingforever.analytics.exceptions.EventNotTrackedException
*
* @constructor create an instance of the *Analytics* class
*/
class Analytics(context: Context, private vararg val dispatchers: AnalyticsDispatcher) {
class Analytics(val settings: AnalyticsSettings, private vararg val dispatchers: AnalyticsDispatcher) {

var exceptionHandler: ExceptionHandler? = null

private val enabledKitMap: EnabledMap<AnalyticsKit> = EnabledMap()
private val enabledDispatcherMap: EnabledMap<String> = EnabledMap()
init {

val settings: AnalyticsSettings = AnalyticsSettings()
// check for new library version if enabled
if (settings.checkForUpdates) VersionChecker.onCheckVersion()

init {
// init all dispatchers
dispatchers.forEach { dispatcher ->
if (dispatcher.init) {
dispatcher.initDispatcher(context.applicationContext)
dispatcher.initDispatcher(settings.context.applicationContext)
}
}

}


/**
* Call this to track one or more *Events*
*/
fun track(vararg events: Event) {

if (settings.isAnalyticsEnabled.not()) return

events.forEach {

events.forEach { event ->

dispatchers.forEach { dispatcher ->

if (enabledKitMap.isDisabled(dispatcher.kit)) {
return
}
if (enabledDispatcherMap.isDisabled(dispatcher.dispatcherName)) {
return
}
if (settings.enabledKits.isDisabled(dispatcher.kit)) return

if (settings.enabledDispatchers.isDisabled(dispatcher.dispatcherName)) return

try {
dispatcher.track(it)
dispatcher.track(event)
} catch (e: Exception) {
settings.exceptionHandler?.onException(EventNotTrackedException(dispatcher, it, e))
exceptionHandler?.onException(EventNotTrackedException(dispatcher, event, e))
}
}


}
}

/**
* Set Kit as enabled or disabled for future event dispatches
*/
fun setKitEnabled(kit: AnalyticsKit, enabled: Boolean) {
enabledKitMap[kit] = enabled
settings.enabledKits[kit] = enabled
}

/**
* Set Dispatcher as enabled or disabled for future event dispatches
*/
fun setDispatcherEnabled(dispatcherName: String, enabled: Boolean) {
enabledDispatcherMap[dispatcherName] = enabled
settings.enabledDispatchers[dispatcherName] = enabled
}

/**
* Just an exception callback to log/monitor exceptions,
* thrown by the *Analytics* class or any of its dispatchers.
*/
interface ExceptionHandler {

fun onException(e: Exception)

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface AnalyticsDispatcher {
val kit: AnalyticsKit

val dispatcherName : String

/**
* Should call the analytics library's initiation methods
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
package com.sofakingforever.analytics

import android.content.Context

/**
* Holds some things for the Analytics class
* @property isAnalyticsEnabled - no events will be sent if this is set to *false*
* @property checkForUpdates - should the library check for updates
* @property exceptionHandler - implementation of @ExceptionHandler
*/
class AnalyticsSettings {
class AnalyticsSettings(val context: Context) {

@Volatile
var isAnalyticsEnabled = true
var checkForUpdates = true

var exceptionHandler: ExceptionHandler? = null
val enabledKits: ServiceEnabledMap<AnalyticsKit> = ServiceEnabledMap()
val enabledDispatchers: ServiceEnabledMap<String> = ServiceEnabledMap()

/**
* Just an exception callback to log/monitor exceptions,
* thrown by the *Analytics* class or any of its dispatchers.
*/
interface ExceptionHandler {
class ServiceEnabledMap<Key> : LinkedHashMap<Key, Boolean>() {

fun onException(e: Exception)
fun isDisabled(key: Key): Boolean = this[key] == false

}
}


}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.sofakingforever.analytics.exceptions

import java.net.MalformedURLException

class IllegalVersionFormatException(version : String) : MalformedURLException("Version '$version' is illegal") {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package com.sofakingforever.analytics.version

import com.sofakingforever.analytics.exceptions.IllegalVersionFormatException

class Version : Comparable<Version> {

private val version: String

@Throws(IllegalVersionFormatException::class) constructor(version: String) {
if (!version.contains(".")) throw IllegalVersionFormatException(version)
this.version = version
}

override fun toString(): String {
return version
}

override fun compareTo(that: Version): Int {

val levels1 = this.version.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val levels2 = that.version.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()

val length = Math.max(levels1.size, levels2.size)

for (i in 0 until length) {
val v1 = if (i < levels1.size) Integer.parseInt(levels1[i]) else 0
val v2 = if (i < levels2.size) Integer.parseInt(levels2[i]) else 0
val compare = v1.compareTo(v2)
if (compare != 0) {
return compare
}
}

return 0
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package com.sofakingforever.analytics.version

import android.util.Log
import com.sofakingforever.analytics.exceptions.IllegalVersionFormatException
import com.sofakingforever.library.BuildConfig
import okhttp3.*
import java.io.IOException

object VersionChecker {

fun onCheckVersion() {

val currentVersion = Version(BuildConfig.VERSION_NAME)

val client = OkHttpClient.Builder()
.followRedirects(true)
.build()

val request = Request.Builder()
.url("https://bintray.com/sofakingforever/analytics/kotlin-analytics/_latestVersion")
.get()
.build()

client.newCall(request).enqueue(object : Callback {

override fun onFailure(call: Call?, e: IOException?) {
// ignore failure, no need to fill logcat with bullshit
}

override fun onResponse(call: Call?, response: Response?) {
// try to finish up
response?.url().also { url ->

try {
val latestVersion = Version(extractVersion(url))

if (currentVersion < latestVersion) {
// user should update
Log.w("Analytics", "Latest kotlin-analytics version is $latestVersion > $currentVersion")
}
} catch (e: IllegalVersionFormatException) {
// ignore failure, no need to fill logcat with bullshit
}


}
}

})
}

fun extractVersion(it: HttpUrl?) : String = it?.encodedPathSegments()?.last() ?: ""

private fun Response?.url(): HttpUrl? {
return this?.networkResponse()?.request()?.url()
}

}
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package com.sofakingforever.library

import android.content.Context
import android.util.Log
import com.sofakingforever.analytics.Analytics
import com.sofakingforever.analytics.AnalyticsSettings
import com.sofakingforever.analytics.exceptions.EventNotTrackedException
import com.sofakingforever.analytics.exceptions.UnsupportedEventException
import com.sofakingforever.library.dispatcher.TestKit
Expand Down Expand Up @@ -34,7 +32,7 @@ class AnalyticsUnitTest {

analytics = Analytics(contextMock, dispatcher).apply {

this.settings.exceptionHandler = object : AnalyticsSettings.ExceptionHandler {
this.settings.exceptionHandler = object : Analytics.ExceptionHandler {
override fun onException(e: Exception) {
raisedException = e
}
Expand Down
11 changes: 9 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,16 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

implementation project(path: ':analytics')
implementation project(path: ':kit-answers')
implementation project(path: ':kit-firebase')
implementation project(':kit-flurry')
implementation project(':kit-mixpanel')
implementation project(path: ':kit-flurry')
implementation project(path: ':kit-mixpanel')

implementation('com.crashlytics.sdk.android:answers:1.4.2@aar') {
transitive = true
}


}
23 changes: 11 additions & 12 deletions app/src/main/java/com/sofakingforever/example/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import com.sofakingforever.analytics.Analytics
import com.sofakingforever.analytics.AnalyticsSettings
import com.sofakingforever.analytics.kits.answers.AnswersDispatcherImpl
import com.sofakingforever.analytics.kits.firebase.FirebaseDispatcherImpl
import com.sofakingforever.example.custom.CustomDispatcher
import com.sofakingforever.analytics.kits.logger.LoggerDispatcherImpl
import com.sofakingforever.analytics.kits.mixpanel.MixPanelDispatcherImpl
import com.sofakingforever.example.custom.CustomDispatcher

class App : Application() {

Expand All @@ -18,8 +18,14 @@ class App : Application() {
super.onCreate()


// set an analytics enabled / disabled via SharedPrefs, Database, or anything else
val settings = AnalyticsSettings(this).also {
it.isAnalyticsEnabled = true

}

// init analytics property. this is in charge of tracking all events
analytics = Analytics(this,
analytics = Analytics(settings,
CustomDispatcher(init = true),
LoggerDispatcherImpl(init = true),
FirebaseDispatcherImpl(init = true),
Expand All @@ -29,29 +35,22 @@ class App : Application() {

// if you're using crashlytics, or any other fabric kit in addition to Answers
// AnswersDispatcherImpl(init = true, Answers(), Crashlytics())
)


analytics.settings.apply {

// set analytics enabled / disabled via SharedPrefs, Database, or anything else
isAnalyticsEnabled = true
).also {

// set an exception handler
// either way, the analytics util won't crash your app
exceptionHandler = object : AnalyticsSettings.ExceptionHandler {
it.exceptionHandler = object : Analytics.ExceptionHandler {
override fun onException(e: Exception) {

// this is the exception, log it, send it or ignore it.

Log.w("Analytics", "Analytics Exception Raised")

e.printStackTrace()
}

}

}


}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.sofakingforever.example.events

import com.sofakingforever.analytics.events.CustomEvent
import com.sofakingforever.analytics.AnalyticsKit
import com.sofakingforever.analytics.events.CustomEvent
import com.sofakingforever.analytics.kits.answers.AnswersKit
import com.sofakingforever.analytics.kits.firebase.FirebaseKit

class EventPerKit(private val whatever: Boolean) : CustomEvent {
override fun getEventName(kit: AnalyticsKit): String = when (kit) {
Expand Down
Loading

0 comments on commit 9622fc6

Please sign in to comment.