Skip to content

Commit b08bf25

Browse files
Merge pull request #5 from logicwind/dev
Added media tracking
2 parents 0c9c2de + dd34e60 commit b08bf25

File tree

9 files changed

+306
-60
lines changed

9 files changed

+306
-60
lines changed

README.md

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ trackSearch,
4848
disableTracking,
4949
enableTracking,
5050
startSession,
51+
trackMediaEvent
5152
} from '@logicwind/react-native-matomo-tracker';
5253

5354
```
@@ -193,19 +194,10 @@ setUserId("[email protected]")
193194

194195
### setVisitorId()
195196

196-
By default matomo generate the unique visitor id but if you want custom vistor id then setVisitorId function allows you to manually set a custom visitor ID for tracking purposes within a React Native application . It will take `visitor-id` parameter.
197+
By default matomo generate the unique visitor id but if you want custom vistor id then setVisitorId function allows you to manually set a custom visitor ID for tracking purposes within a React Native application . It will take `visitor-id` parameter. It must be a 16 character long hex string
197198

198199
#### Examples
199200

200-
#### ios
201-
202-
```js
203-
204-
setVisitorId("123e4567-e89b-12d3-a456-426614174000")
205-
206-
```
207-
#### Android
208-
209201
```js
210202

211203
setVisitorId("2c534f55fba6cf6e")
@@ -260,12 +252,41 @@ setLogger()
260252

261253
```
262254

255+
### trackMediaEvent()
256+
257+
trackMediaEvent function use to monitor user interactions with media content, such as audio or video files. It allows you to track various events related to media playback, such as play, pause, stop, seek, and complete, providing insights into user engagement with your media assets.
258+
259+
| Parameter | Description |
260+
|----------------|-----------------------------------------------------------|
261+
| mediaId | (required) A unique id that is always the same while playing a media. As soon as the played media changes. |
262+
| mediaResource | (required) The URL of the media resource. |
263+
| mediaType | (required) video or audio depending on the type of the media. You can used MediaType.VIDEO or MediaType.AUDIO |
264+
| mediaTitle | The name / title of the media. |
265+
| playerName | The name of the media player, for example html5. |
266+
| mediaStatus | The time in seconds for how long a user has been playing this media. This number should typically increase when you send a media tracking request. It should be 0 if the media was only visible/impressed but not played. Do not increase this number when a media is paused. |
267+
| mediaLength | The duration (the length) of the media in seconds. For example if a video is 90 seconds long, the value should be 90. |
268+
| mediaProgress | The progress / current position within the media. Defines basically at which position within the total length the user is currently playing. |
269+
| mediaTTP | Defines after how many seconds the user has started playing this media. For example a user might have seen the poster of the video for 30 seconds before a user actually pressed the play button. |
270+
| mediaWidth | The resolution width of the media in pixels. Only recommended being set for videos. |
271+
| mediaHeight | The resolution height of the media in pixels. Only recommended being set for videos. |
272+
| mediaFullScreen| Should be 0 or 1 and defines whether the media is currently viewed in full screen. Only recommended being set for videos. |
273+
| mediaSE | An optional comma separated list of which positions within a media a user has played. For example if the user has viewed position 5s, 10s, 15s and 35s, then you would need to send 5,10,15,35. We recommend to round to the next 5 seconds and not send a value for each second. Internally, Matomo may round to the next 15 or 30 seconds. For performance optimisation we recommend not sending the same position twice. Meaning if you have sent ma_se=10 there is no need to send later ma_se=10,20 but instead only ma_se=20. |
274+
275+
276+
277+
#### Examples
278+
279+
```js
280+
281+
trackMediaEvent({siteId:"siteid",mediaId:"unique id",mediaTitle:"video media play track",playerName:"test 08",mediaType:MediaType.VIDEO,mediaResource:"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4",mediaStatus:"100",mediaLength:"100",mediaFullScreen:"1",mediaHeight:"720",mediaWidth:"1080",mediaProgress:"100"});
282+
283+
```
263284

264285

265286
## Methods
266287

267288

268-
| Method | Require Paramter | Android | ios | Android TV | Apple TV |
289+
| Method | Required Parameter | Android | ios | Android TV | Apple TV |
269290
|--------------------------------------|-----------------------------------------------------------|:-------:|:---:|:----------:|:--------:|
270291
| [createTracker](#createtracker) | uri: String, siteId: Number |||||
271292
| [startSession](#startsession) | - |||||
@@ -282,6 +303,7 @@ setLogger()
282303
| [disableTracking](#disabletracking) | - |||||
283304
| [enableTracking](#enabletracking) | - |||||
284305
| [setLogger](#setlogger) | - |||||
306+
| [trackMediaEvent](#trackmediaevent) | siteId: String, mediaId: String, mediaTitle: String, playerName: String, mediaType: String, mediaResource: String, mediaStatus: String,mediaLength?:String, mediaProgress?:String, mediaTTP?: String, mediaWidth?: String, mediaHeight?: String, mediaSE?: String, mediaFullScreen?:String |||||
285307

286308

287309
<!-- ## Contributing

android/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,5 +92,6 @@ dependencies {
9292
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
9393
implementation 'com.jakewharton.timber:timber:5.0.1'
9494
implementation 'com.github.matomo-org:matomo-sdk-android:4.2'
95+
implementation 'com.squareup.okhttp3:okhttp:4.9.3'
9596
}
9697

android/src/main/java/com/logicwind/reactnativematomotracker/ReactNativeMatomoTrackerModule.kt

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,21 @@
11
package com.logicwind.reactnativematomotracker
22

3+
import android.app.Application
4+
import android.content.ContentValues.TAG
5+
import android.util.Log
36
import com.facebook.react.bridge.ReactApplicationContext
47
import com.facebook.react.bridge.ReactContextBaseJavaModule
58
import com.facebook.react.bridge.ReactMethod
6-
import com.facebook.react.bridge.Promise
7-
import com.facebook.react.bridge.ReadableArray
8-
import com.facebook.react.bridge.ReadableMap
9-
import com.facebook.react.bridge.ReadableMapKeySetIterator
10-
import timber.log.Timber
9+
import okhttp3.OkHttpClient
10+
import okhttp3.Request
1111
import org.matomo.sdk.Matomo
12+
import org.matomo.sdk.TrackMe
1213
import org.matomo.sdk.Tracker
1314
import org.matomo.sdk.TrackerBuilder
1415
import org.matomo.sdk.extra.TrackHelper
16+
import timber.log.Timber
1517
import java.net.URL
16-
import android.content.ContentValues.TAG
17-
import android.util.Log
18-
import android.app.Application
19-
import org.matomo.sdk.extra.DownloadTracker
18+
import java.net.URLEncoder
2019

2120

2221
class ReactNativeMatomoTrackerModule(reactContext: ReactApplicationContext) :
@@ -25,6 +24,7 @@ class ReactNativeMatomoTrackerModule(reactContext: ReactApplicationContext) :
2524
private val mMatomoTracker: Matomo? = Matomo.getInstance(reactContext)
2625

2726
private var tracker: Tracker? = null
27+
private val client = OkHttpClient()
2828

2929
override fun getName(): String {
3030
return NAME
@@ -37,7 +37,7 @@ class ReactNativeMatomoTrackerModule(reactContext: ReactApplicationContext) :
3737

3838
tracker = TrackerBuilder.createDefault(uri, siteId)
3939
.build(mMatomoTracker)
40-
Log.e(TAG, "initialized successfully! ${tracker}")
40+
Log.e(TAG, "initialized successfully! ${tracker}")
4141

4242
} catch (e: Exception) {
4343
Log.e(TAG, "An error occurred: ${e.message}")
@@ -46,12 +46,6 @@ class ReactNativeMatomoTrackerModule(reactContext: ReactApplicationContext) :
4646
}
4747
}
4848

49-
50-
51-
52-
// Example method
53-
// See https://reactnative.dev/docs/native-modules-android
54-
5549
@ReactMethod
5650
fun startSession() {
5751
tracker?.startNewSession()
@@ -181,8 +175,94 @@ class ReactNativeMatomoTrackerModule(reactContext: ReactApplicationContext) :
181175
}
182176
}
183177

178+
@ReactMethod
179+
fun trackMedia(
180+
siteId: String,
181+
mediaId: String,
182+
mediaTitle: String,
183+
playerName: String,
184+
mediaType: String,
185+
mediaResource: String,
186+
mediaStatus: String,
187+
mediaLength:String,
188+
mediaProgress:String,
189+
mediaTTP: String,
190+
mediaWidth: String,
191+
mediaHeight: String,
192+
mediaSE: String,
193+
mediaFullScreen:String
194+
195+
) {
196+
197+
if(mediaStatus=="0") {
198+
TrackHelper.track().event(mediaType, "play").name(mediaTitle).with(tracker)
199+
trackDispatch()
200+
}
201+
if(mediaStatus==mediaLength && mediaStatus==mediaProgress) {
202+
TrackHelper.track().event(mediaType, "stop").name(mediaTitle).with(tracker)
203+
trackDispatch()
204+
}
205+
206+
val baseUrl = tracker?.apiUrl
207+
var query = "idsite=${encode(siteId)}" +
208+
"&rec=1" +
209+
"&r=${generateRandomNumber()}" +
210+
"&ma_id=${encode(mediaId)}" +
211+
"&ma_ti=${encode(mediaTitle)}" +
212+
"&ma_pn=${encode(playerName)}" +
213+
"&ma_mt=${encode(mediaType)}" +
214+
"&ma_re=${encode(mediaResource)}"+
215+
"&ma_st=${encode(mediaStatus)}"+
216+
"&_id=${encode(tracker?.visitorId.toString())}"
217+
218+
if(mediaLength.isNotEmpty()){
219+
query=query+ "&ma_le=${encode(mediaLength)}";
220+
}
221+
222+
if(mediaProgress.isNotEmpty()){
223+
query=query+ "&ma_ps=${encode(mediaProgress)}";
224+
}
184225

226+
if(mediaWidth.isNotEmpty()){
227+
query=query+ "&ma_w=${encode(mediaWidth)}";
228+
}
229+
230+
if(mediaHeight.isNotEmpty()){
231+
query=query+ "&ma_h=${encode(mediaHeight)}";
232+
}
233+
234+
if(mediaFullScreen.isNotEmpty()){
235+
query=query+ "&ma_fs=${encode(mediaFullScreen)}";
236+
}
237+
238+
if(mediaSE.isNotEmpty()){
239+
query=query+ "&ma_se=${encode(mediaSE)}";
240+
}
185241

242+
if(mediaTTP.isNotEmpty()){
243+
query=query+ "&ma_ttp=${encode(mediaTTP)}";
244+
}
245+
try {
246+
val urlString = "$baseUrl?$query"
247+
val request = Request.Builder()
248+
.url(urlString)
249+
.build()
250+
251+
client.newCall(request).execute().use { response ->
252+
val responseCode = response.code
253+
}
254+
}catch (e:Exception){
255+
Log.e(TAG, "error : ${e.message}")
256+
}
257+
}
258+
259+
private fun generateRandomNumber(): Long {
260+
return (Math.random() * Long.MAX_VALUE).toLong()
261+
}
262+
263+
private fun encode(value: String): String {
264+
return URLEncoder.encode(value, "UTF-8")
265+
}
186266

187267

188268
companion object {

example/ios/Podfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ PODS:
77
- hermes-engine (0.74.1):
88
- hermes-engine/Pre-built (= 0.74.1)
99
- hermes-engine/Pre-built (0.74.1)
10-
- logicwind-react-native-matomo-tracker (0.2.1):
10+
- logicwind-react-native-matomo-tracker (0.3.0):
1111
- DoubleConversion
1212
- glog
1313
- hermes-engine
@@ -1376,7 +1376,7 @@ SPEC CHECKSUMS:
13761376
fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120
13771377
glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2
13781378
hermes-engine: 16b8530de1b383cdada1476cf52d1b52f0692cbc
1379-
logicwind-react-native-matomo-tracker: cb7577a2f7dca6f646620a44c45f2aca91c3e65b
1379+
logicwind-react-native-matomo-tracker: a370c4497348c4d31730b3d09d474be3d813ef81
13801380
MatomoTracker: 1f3772a41c27393067d0126071afe6ae1c7f739e
13811381
RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47
13821382
RCTDeprecation: efb313d8126259e9294dc4ee0002f44a6f676aba

example/src/App.tsx

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ import {
77
Pressable,
88
ScrollView,
99
SafeAreaView,
10-
Platform,
1110
} from 'react-native';
1211

1312
import {
13+
MediaType,
1414
createTracker,
1515
disableTracking,
1616
enableTracking,
@@ -23,6 +23,7 @@ import {
2323
trackEvent,
2424
trackImpression,
2525
trackInteraction,
26+
trackMediaEvent,
2627
trackOutlink,
2728
trackScreen,
2829
trackSearch,
@@ -32,29 +33,30 @@ import {
3233
export default function App() {
3334
const [result] = React.useState<number | undefined>();
3435

35-
3636
React.useEffect(() => {
37-
createTracker("your-matomo-url",1) //Replace 1 with your matomo site id
37+
createTracker("https://your-matomo-url/matomo.php", 1) //Replace 1 with your matomo site id
38+
3839
}, []);
3940

4041
return (
4142
<SafeAreaView style={styles.main}>
4243
<ScrollView showsHorizontalScrollIndicator={false}>
4344
<View style={styles.container}>
4445
<Text>Matomo Tracking {result}</Text>
45-
<Pressable
46-
style={styles.button}
47-
onPress={() => {
48-
startSession()
49-
}}
50-
>
51-
<Text style={styles.buttonText}>Start Session</Text>
52-
</Pressable>
46+
47+
<Pressable
48+
style={styles.button}
49+
onPress={() => {
50+
startSession()
51+
}}
52+
>
53+
<Text style={styles.buttonText}>Start Session</Text>
54+
</Pressable>
5355
<Pressable
5456
style={styles.button}
5557
onPress={() => {
5658
trackScreen('HomeScreen', 'This is test home screen');
57-
59+
5860
}}
5961
>
6062
<Text style={styles.buttonText}>Track Screen</Text>
@@ -138,11 +140,7 @@ export default function App() {
138140
<Pressable
139141
style={styles.button}
140142
onPress={() => {
141-
if (Platform.OS === 'ios') {
142-
setVisitorId('123e4567-e89b-12d3-a456-426614174000');
143-
} else {
144-
setVisitorId('2c534f55fba6cf6e');
145-
}
143+
setVisitorId('0123456789abcdef');
146144
}}
147145
>
148146
<Text style={styles.buttonText}>Set Visistor Id</Text>
@@ -169,17 +167,26 @@ export default function App() {
169167
<Pressable
170168
style={styles.button}
171169
onPress={() => {
172-
setLogger()
170+
setLogger()
173171
}}
174172
>
175173
<Text style={styles.buttonText}>Set Logger</Text>
176174
</Pressable>
177175

176+
<Pressable
177+
style={styles.button}
178+
onPress={() => {
179+
trackMediaEvent({ siteId: "siteId", mediaId: Date.now.toString(), mediaTitle: "video media play track", playerName: "test 08", mediaType: MediaType.VIDEO, mediaResource: "http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4", mediaStatus: "100", mediaLength: "100", mediaFullScreen: "1", mediaHeight: "720", mediaWidth: "1080", mediaProgress: "100" });
180+
}}
181+
>
182+
<Text style={styles.buttonText}>Video Play Stop</Text>
183+
</Pressable>
178184

179185
<Pressable
180186
style={styles.button}
181187
onPress={() => {
182-
trackDispatch();
188+
trackDispatch()
189+
183190
}}
184191
>
185192
<Text style={styles.buttonText}>Track Dispatch</Text>

ios/ReactNativeMatomoTracker.mm

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ @interface RCT_EXTERN_MODULE(ReactNativeMatomoTracker, NSObject)
3939

4040
RCT_EXTERN_METHOD(enableTracking)
4141

42+
RCT_EXTERN_METHOD(trackMedia:(NSString *)siteId withMediaId:(NSString *)mediaId withMediaTitle:(NSString *)mediaTitle withPlayerName:(NSString *)playerName withMediaType:(NSString *)mediaType withMediaResource:(NSString *)mediaResource withMediaStatus:(NSString *)mediaStatus withMediaLength:(NSString *)mediaLength withMediaProgress:(NSString *)mediaProgress withMediaTTP:(NSString *)mediaTTP withMediaWidth:(NSString *)mediaWidth withMediaHeight:(NSString *)mediaHeight withMediaSE:(NSString *)mediaSE withMediaFullScreen:(NSString *)mediaFullScreen)
43+
44+
45+
46+
4247

4348

4449

0 commit comments

Comments
 (0)