Skip to content

Commit 5b536f7

Browse files
committed
raven sdk
1 parent 98a4f47 commit 5b536f7

22 files changed

+946
-0
lines changed

raven-android-sdk/build.gradle

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
plugins {
2+
id 'com.android.library'
3+
id 'kotlin-android'
4+
id 'kotlin-android-extensions'
5+
id 'maven-publish'
6+
}
7+
8+
repositories {
9+
mavenCentral()
10+
google()
11+
jcenter()
12+
maven { url "https://jitpack.io" }
13+
}
14+
15+
android {
16+
compileSdkVersion 30
17+
buildToolsVersion '30.0.3'
18+
19+
defaultConfig {
20+
minSdkVersion 21
21+
targetSdkVersion 30
22+
versionCode 1
23+
versionName "1.0"
24+
25+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
26+
consumerProguardFiles 'consumer-rules.pro'
27+
}
28+
29+
buildTypes {
30+
release {
31+
minifyEnabled false
32+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
33+
}
34+
}
35+
36+
}
37+
38+
dependencies {
39+
implementation fileTree(dir: 'libs', include: ['*.jar'])
40+
41+
//kotlin
42+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.4.10"
43+
44+
//android
45+
implementation 'androidx.appcompat:appcompat:1.2.0'
46+
implementation 'androidx.core:core-ktx:1.3.2'
47+
48+
// retrofit
49+
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
50+
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
51+
implementation 'com.squareup.okhttp3:logging-interceptor:4.2.1'
52+
53+
debugCompile 'com.readystatesoftware.chuck:library:1.1.0'
54+
releaseCompile 'com.readystatesoftware.chuck:library-no-op:1.1.0'
55+
}
56+
57+
// Because the components are created only during the afterEvaluate phase, you must
58+
// configure your publications using the afterEvaluate() lifecycle method.
59+
afterEvaluate {
60+
publishing {
61+
publications {
62+
// Creates a Maven publication called "release".
63+
release(MavenPublication) {
64+
// Applies the component for the release build variant.
65+
from components.release
66+
67+
// You can then customize attributes of the publication as shown below.
68+
groupId = 'com.raven'
69+
artifactId = 'raven-android-sdk'
70+
version = '1.0.0'
71+
}
72+
// Creates a Maven publication called “debug”.
73+
debug(MavenPublication) {
74+
// Applies the component for the debug build variant.
75+
from components.debug
76+
77+
groupId = 'com.raven'
78+
artifactId = 'raven-android-sdk-debug'
79+
version = '1.0.0'
80+
}
81+
}
82+
}
83+
}

raven-android-sdk/consumer-rules.pro

Whitespace-only changes.
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
2+
package="com.raven.ravenandroidsdk" />
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.raven.ravenandroidsdk
2+
3+
internal const val PREF_APP_ID = "PREF_RAVEN_APP_ID"
4+
internal const val PREF_USER_ID = "PREF_RAVEN_USER_ID"
5+
internal const val PREF_USER_DEVICE_ID = "PREF_USER_DEVICE_ID"
6+
internal const val PREF_SECRET_KEY = "PREF_SECRET_KEY"
7+
internal const val PREF_RAVEN_USER = "PREF_RAVEN_USER"
8+
9+
internal const val PLATFORM = "android"
Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
package com.raven.ravenandroidsdk
2+
3+
import android.app.Application
4+
import android.content.Context
5+
import android.content.ContextWrapper
6+
import com.raven.ravenandroidsdk.api.ApiProvider
7+
import com.raven.ravenandroidsdk.api.controllers.CommunicationController
8+
import com.raven.ravenandroidsdk.api.controllers.GetUserController
9+
import com.raven.ravenandroidsdk.api.controllers.RemoveTokenController
10+
import com.raven.ravenandroidsdk.api.controllers.UpdateDeliveryStatus
11+
import com.raven.ravenandroidsdk.api.controllers.UpdateTokenController
12+
import com.raven.ravenandroidsdk.api.controllers.UpdateUserController
13+
import com.raven.ravenandroidsdk.api.dto.DeliveryStatus
14+
import com.raven.ravenandroidsdk.models.*
15+
import com.raven.ravenandroidsdk.api.dto.RavenMessage
16+
import com.raven.ravenandroidsdk.api.dto.Recipient
17+
import com.raven.ravenandroidsdk.models.User
18+
import com.raven.ravenandroidsdk.utils.Prefs
19+
20+
object RavenSdk {
21+
22+
const val RAVEN_NOTIFICATION_ID = "raven_notification_id"
23+
24+
/*
25+
Method to initialize Raven SDK when you want to trigger raven events via SDK.
26+
Invoke on app launch
27+
*/
28+
@Throws(IllegalArgumentException::class)
29+
fun initialize(context: Application, appId: String, secretKey: String) {
30+
initPrefs(context, appId)
31+
ApiProvider(context, secretKey)
32+
fetchCurrentUser()
33+
}
34+
35+
36+
/*
37+
Method to initialize Raven SDK when you do not want to trigger raven events via SDK.
38+
Invoke on app launch
39+
*/
40+
@Throws(IllegalArgumentException::class)
41+
fun initialize(context: Application, appId: String) {
42+
initPrefs(context, appId)
43+
ApiProvider(context)
44+
fetchCurrentUser()
45+
}
46+
47+
48+
/*
49+
Set user identifier.
50+
Invoke once on login to set the user identifier
51+
*/
52+
private fun setUserId(userId: String) {
53+
54+
if (userId.isEmpty()) {
55+
return
56+
}
57+
58+
//check if user id is set, or its the first time
59+
val currentUserId = Prefs.getString(PREF_USER_ID, null)
60+
if (currentUserId == userId) {
61+
return
62+
}
63+
64+
//user switch without logout
65+
if (currentUserId != null && currentUserId != userId) {
66+
logout()
67+
}
68+
69+
Prefs.putString(PREF_USER_ID, userId)
70+
}
71+
72+
73+
/*
74+
Set user mobile
75+
*/
76+
fun setUserMobile(userId: String, mobile: String) {
77+
78+
//throws exception if uninitialized
79+
checkIfSDKInitialized()
80+
81+
//set user id
82+
setUserId(userId)
83+
84+
if (mobile.isEmpty() || userId.isEmpty()) {
85+
return
86+
}
87+
88+
//check if cached mobile is same as the argument
89+
val currentUser = getCurrentUser()
90+
if (currentUser?.mobile == mobile) {
91+
return
92+
}
93+
94+
//Check for currently set user id
95+
val user = User(userId = userId, mobile = mobile)
96+
UpdateUserController().start(Prefs.getString(PREF_APP_ID, null) ?: return, user)
97+
}
98+
99+
100+
/*
101+
Set user
102+
*/
103+
fun setUser(userId: String, mobile: String? = null, email: String? = null) {
104+
105+
//throws exception if uninitialized
106+
checkIfSDKInitialized()
107+
108+
//set user id
109+
setUserId(userId)
110+
111+
if (userId.isEmpty() || ((mobile == null || mobile.isEmpty()) && (email == null || email.isEmpty()))) {
112+
return
113+
}
114+
115+
//check if cached mobile/email is same as the argument
116+
val currentUser = getCurrentUser()
117+
if (currentUser?.mobile == mobile && currentUser?.email == email) {
118+
return
119+
}
120+
121+
val user = User(userId = userId, mobile = mobile, email = email)
122+
UpdateUserController().start(Prefs.getString(PREF_APP_ID, null) ?: return, user)
123+
}
124+
125+
126+
/*
127+
Set user email
128+
*/
129+
fun setUserEmail(userId: String, email: String) {
130+
131+
//throws exception if uninitialized
132+
checkIfSDKInitialized()
133+
134+
//set user id
135+
setUserId(userId)
136+
137+
if (email.isEmpty() || userId.isEmpty()) {
138+
return
139+
}
140+
141+
//check if cached mobile is same as the argument
142+
val currentUser = getCurrentUser()
143+
if (currentUser?.email == email) {
144+
return
145+
}
146+
147+
val user = User(userId = userId, email = email)
148+
UpdateUserController().start(Prefs.getString(PREF_APP_ID, null) ?: return, user)
149+
}
150+
151+
152+
/*
153+
Set user email
154+
*/
155+
fun setDeviceToken(token: String) {
156+
157+
//throws exception if uninitialized
158+
checkIfSDKInitialized()
159+
160+
if (token.isEmpty()) {
161+
return
162+
}
163+
164+
//check if cached token is same as the argument
165+
val currentUser = getCurrentUser()
166+
var isUpdate = false
167+
for (item in currentUser?.devices ?: arrayListOf()) {
168+
if (item.fcmToken == token && item.platform == PLATFORM) {
169+
return
170+
}
171+
172+
if (item.deviceSid == Prefs.getString(PREF_USER_DEVICE_ID, null)) {
173+
if (item.fcmToken != token && item.platform == PLATFORM) {
174+
isUpdate = true
175+
}
176+
}
177+
}
178+
179+
val userId = Prefs.getString(PREF_USER_ID, null)
180+
if (userId != null) {
181+
UpdateTokenController().start(Prefs.getString(PREF_APP_ID, null) ?: return, userId, token, isUpdate)
182+
}
183+
}
184+
185+
186+
/*
187+
Logout user
188+
*/
189+
fun logout() {
190+
191+
//de register the device
192+
val userId = Prefs.getString(PREF_USER_ID, null)
193+
if (userId != null) {
194+
RemoveTokenController().start(Prefs.getString(PREF_APP_ID, null) ?: return, userId)
195+
}
196+
197+
//reset the preferences
198+
Prefs.putString(PREF_USER_ID, null)
199+
Prefs.putString(PREF_RAVEN_USER, null)
200+
}
201+
202+
203+
/*
204+
Update message delivery status
205+
*/
206+
fun updateStatus(notificationId: String, status: Status) {
207+
val deliveryStatus = DeliveryStatus(notificationId = notificationId, type = status)
208+
UpdateDeliveryStatus().start(Prefs.getString(PREF_APP_ID, null) ?: return, deliveryStatus)
209+
}
210+
211+
212+
/*
213+
Method to get the currently active user from raven backend
214+
*/
215+
private fun fetchCurrentUser() {
216+
217+
//throws exception if uninitialized
218+
checkIfSDKInitialized()
219+
220+
//Check for currently set user id
221+
val userId = Prefs.getString(PREF_USER_ID, null)
222+
223+
//if present, get the user from raven backend
224+
if (userId != null && userId.isNotEmpty()) {
225+
GetUserController().start(Prefs.getString(PREF_APP_ID, null) ?: return, userId)
226+
}
227+
}
228+
229+
230+
private fun initPrefs(context: Context?, appId: String) {
231+
232+
if (appId.isEmpty()) {
233+
throw IllegalArgumentException("App ID cannot be empty")
234+
}
235+
236+
//Initialize Prefs lib
237+
Prefs.init(context, context?.packageName + "_" + "raven", ContextWrapper.MODE_PRIVATE)
238+
239+
Prefs.putString(PREF_APP_ID, appId)
240+
}
241+
242+
243+
private fun checkIfSDKInitialized() {
244+
if (Prefs.getString(PREF_APP_ID, null) == null) {
245+
throw IllegalStateException("Raven Client SDK not initialized")
246+
}
247+
}
248+
249+
250+
@Throws(IllegalStateException::class)
251+
fun sendMessage(template: String, id: String, callback: RavenResponseCallback?) {
252+
253+
checkIfSDKInitialized()
254+
255+
val message = RavenMessage()
256+
message.event = template
257+
258+
val recipient = Recipient()
259+
recipient.userId = id
260+
message.user = recipient
261+
262+
//api call
263+
Prefs.getString(PREF_APP_ID, null)?.let { CommunicationController(callback).start(it, message) }
264+
}
265+
266+
267+
interface RavenResponseCallback {
268+
fun onSuccess()
269+
fun onFailure(error: String?)
270+
}
271+
}

0 commit comments

Comments
 (0)