mparticle-roku-sdk 2.1.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. package/.github/workflows/build.yml +26 -0
  2. package/.gitmodules +3 -0
  3. package/LICENSE +191 -0
  4. package/README.md +24 -0
  5. package/example-legacy-sdk/images/MainMenu_Icon_Center_HD.png +0 -0
  6. package/example-legacy-sdk/images/MainMenu_Icon_Center_SD43.png +0 -0
  7. package/example-legacy-sdk/images/MainMenu_Icon_Side_HD.png +0 -0
  8. package/example-legacy-sdk/images/MainMenu_Icon_Side_SD43.png +0 -0
  9. package/example-legacy-sdk/images/splash_fhd.jpg +0 -0
  10. package/example-legacy-sdk/images/splash_hd.jpg +0 -0
  11. package/example-legacy-sdk/images/splash_sd.jpg +0 -0
  12. package/example-legacy-sdk/manifest +26 -0
  13. package/example-legacy-sdk/source/main.brs +45 -0
  14. package/example-scenegraph-sdk/LICENSE +1 -0
  15. package/example-scenegraph-sdk/README.md +2 -0
  16. package/example-scenegraph-sdk/source/Makefile +6 -0
  17. package/example-scenegraph-sdk/source/app.mk +675 -0
  18. package/example-scenegraph-sdk/source/components/helloworld.brs +300 -0
  19. package/example-scenegraph-sdk/source/components/helloworld.xml +66 -0
  20. package/example-scenegraph-sdk/source/images/channel-poster_fhd.png +0 -0
  21. package/example-scenegraph-sdk/source/images/channel-poster_hd.png +0 -0
  22. package/example-scenegraph-sdk/source/images/channel-poster_sd.png +0 -0
  23. package/example-scenegraph-sdk/source/images/splash-screen_fhd.jpg +0 -0
  24. package/example-scenegraph-sdk/source/images/splash-screen_hd.jpg +0 -0
  25. package/example-scenegraph-sdk/source/images/splash-screen_sd.jpg +0 -0
  26. package/example-scenegraph-sdk/source/manifest +12 -0
  27. package/example-scenegraph-sdk/source/source/Main.brs +46 -0
  28. package/example-scenegraph-sdk/source/testFramework/UnitTestFramework.brs +2867 -0
  29. package/example-scenegraph-sdk/source/tests/TestBasics.brs +266 -0
  30. package/mParticleBundle.crt +68 -0
  31. package/mParticleCore.brs +2301 -0
  32. package/mParticleTask.brs +78 -0
  33. package/mParticleTask.xml +12 -0
  34. package/package.json +5 -0
  35. package/testing/tests/Test__mParticle.brs +88 -0
@@ -0,0 +1,300 @@
1
+ sub init()
2
+
3
+
4
+ 'Create the mParticle Task Node
5
+ m.mParticleTask = createObject("roSGNode", "mParticleTask")
6
+ m.mParticleTask.ObserveField(mParticleConstants().SCENEGRAPH_NODES.IDENTITY_RESULT_NODE, "onIdentityResult")
7
+ m.mParticleTask.ObserveField(mParticleConstants().SCENEGRAPH_NODES.CURRENT_USER_NODE, "onCurrentUserChanged")
8
+ m.mparticle = mParticleSGBridge(m.mParticleTask)
9
+ mpConstants = mparticleconstants()
10
+ m.mpidLabel = m.top.findNode("mpidLabel")
11
+ m.userAttributesLabel = m.top.findNode("userAttributesLabel")
12
+ m.userIdentitiesLabel = m.top.findNode("userIdentitiesLabel")
13
+ m.emailTextEdit = m.top.findNode("emailTextEdit")
14
+ m.emailTextEdit.setFocus(true)
15
+ identityApiRequest = {}
16
+ identityApiRequest.userIdentities = {}
17
+ identityApiRequest.userIdentities[mpConstants.IDENTITY_TYPE.OTHER] = "foo"
18
+ m.mparticle.identity.modify(identityApiRequest)
19
+ identityApiRequest = {}
20
+ identityApiRequest.userIdentities = {}
21
+ identityApiRequest.userIdentities[mpConstants.IDENTITY_TYPE.OTHER] = "bar"
22
+ m.mparticle.identity.modify(identityApiRequest)
23
+ m.mparticle.logEvent("hello world!")
24
+ m.mparticle.identity.setUserAttribute("example attribute key", "example attribute value 1")
25
+ m.mparticle.identity.setUserAttribute("example attribute array", ["foo", "bar"])
26
+ m.mparticle.identity.setUserAttribute("example attribute key", "example attribute value 2")
27
+ m.mparticle.identity.setUserAttribute("example attribute array", ["noo", "mar"])
28
+
29
+ m.mparticle.logScreenEvent("hello screen!")
30
+
31
+ time = CreateObject("roDateTime")
32
+
33
+ consentStateAPI = mpConstants.ConsentState
34
+ consentState = consentStateAPI.build()
35
+
36
+ ' GDPR
37
+ ' This portion is commented out because a workspace has to be configured for specific GDPR purposes (in this case, 'functional' and 'performance').
38
+ ' If the purpose is not configured, events will not be accepted and not show up in the Live Stream.
39
+ ' To test your own implementation, make sure you have a GDPR consent purpose activated on your workspace and update the purpose below.
40
+ ' Similarly, CCPA (which does not require a purpose) must be configured on your workspace for events with a CCPA attached to work.
41
+ 'gdprConsentStateApi = mpConstants.GDPRConsentState
42
+ 'gdprConsentState = gdprConsentStateApi.build(False, time.asSeconds())
43
+
44
+ 'gdprConsentStateApi.setDocument(gdprConsentState, "document_agreement.v2")
45
+ 'gdprConsentStateApi.setLocation(gdprConsentState, "dtmgbank.com/signup")
46
+ 'gdprConsentStateApi.setHardwareId(gdprConsentState, "IDFA:a5d934n0-232f-4afc-2e9a-3832d95zc702")
47
+
48
+ 'consentStateAPI.addGDPRConsentState(consentState, "functional", gdprConsentState)
49
+
50
+ ' For testing delete
51
+ 'gdprToDelete = gdprConsentStateApi.build(False, time.asSeconds())
52
+ 'gdprConsentStateApi.setDocument(gdprToDelete, "deletion_agreement")
53
+ 'gdprConsentStateApi.setLocation(gdprToDelete, "mparticle.test")
54
+ 'gdprConsentStateApi.setHardwareId(gdprToDelete, "TEST_HARDWARE_ID")
55
+
56
+ 'consentStateAPI.addGDPRConsentState(consentState, "performance", gdprToDelete)
57
+
58
+ 'print " --- Consent State with GDPR --- "
59
+ 'print formatjson(consentState)
60
+
61
+ 'print " --- Test Removing a GDPR Consent State --- "
62
+ consentStateAPI.removeGDPRConsentState(consentState, "performance")
63
+ consentStateAPI.removeGDPRConsentState(consentState, "functional")
64
+ 'print formatjson(consentState)
65
+
66
+ ' CCPA
67
+ 'ccpaConsentStateApi = mpConstants.CCPAConsentState
68
+ 'ccpaToDelete = ccpaConsentStateApi.build(False, time.asSeconds())
69
+ 'ccpaConsentStateApi.setDocument(ccpaToDelete, "deletion_agreement")
70
+ 'ccpaConsentStateApi.setLocation(ccpaToDelete, "mparticle.test")
71
+ 'ccpaConsentStateApi.setHardwareId(ccpaToDelete, "TEST_HARDWARE_ID")
72
+
73
+ 'print ccpaToDelete
74
+
75
+ 'consentStateAPI.setCCPAConsentState(consentState, ccpaToDelete)
76
+
77
+ 'print " --- Consent State with CCPA --- "
78
+ 'print formatjson(consentState)
79
+
80
+ 'print " --- Test Removing CCPA Consent State --- "
81
+ consentStateAPI.removeCCPAConsentState(consentState)
82
+ 'print formatjson(consentState)
83
+
84
+ 'ccpaConsentState = ccpaConsentStateApi.build(True, time.asSeconds())
85
+ 'print formatjson(ccpaConsentState)
86
+
87
+ 'ccpaConsentStateApi.setDocument(ccpaConsentState, "document_agreement.v4")
88
+ 'ccpaConsentStateApi.setLocation(ccpaConsentState, "mpbank.com/signup")
89
+ 'ccpaConsentStateApi.setHardwareId(ccpaConsentState, "IDFA:a5d934n0-232f-4afc-2e9a-3832d95zc702")
90
+
91
+ 'consentStateAPI.setCCPAConsentState(consentState, ccpaConsentState)
92
+
93
+ 'print " --- Add new CCPA Consent State --- "
94
+ 'print formatjson(consentState)
95
+
96
+ 'm.mparticle.identity.setConsentState(consentState)
97
+ 'print "--- Consent Test End ---"
98
+
99
+ ' Commerce
100
+
101
+ product = mpConstants.Product.build("foo-sku", "foo-name", 123.45)
102
+ actionApi = mpConstants.ProductAction
103
+ productAction = actionApi.build(actionApi.ACTION_TYPE.PURCHASE, 123.45, [product])
104
+ actionApi.setCheckoutStep(productAction, 5)
105
+ actionApi.setCouponCode(productAction, "foo-coupon-code")
106
+ actionApi.setShippingAmount(productAction, 33.42)
107
+
108
+ promotionList = [mpConstants.Promotion.build("foo-id", "foo-name", "foo-creative", "foo-position")]
109
+ promotionAction = mpConstants.PromotionAction.build(mpConstants.PromotionAction.ACTION_TYPE.VIEW, promotionList)
110
+
111
+ impressions = [mpConstants.Impression.build("foo-list", [product])]
112
+ m.mparticle.setSessionAttribute("foo attribute key", "bar attribute value")
113
+ m.mparticle.logCommerceEvent(productAction, promotionAction, impressions, { "foo-attribute": "bar-attribute-value" })
114
+
115
+ ' Custom Media Event
116
+
117
+ customAttributes = { "example custom attribute": "example custom attribute value" }
118
+ m.mparticle.logEvent("Custom Media Event", mparticleConstants().CUSTOM_EVENT_TYPE.MEDIA, customAttributes)
119
+
120
+ ' Media API
121
+ customAttributes = { "example custom attribute": "example custom attribute value" }
122
+ mediaSession = mpConstants.MediaSession.build("ABC123", "Space Pilot 3000", mparticleConstants().MEDIA_CONTENT_TYPE.VIDEO, mparticleConstants().MEDIA_STREAM_TYPE.LIVE_STREAM, 1800000)
123
+ m.mparticle.media.logMediaSessionStart(mediaSession, customAttributes)
124
+
125
+ print ("Logging session after start: " + formatjson(mediaSession))
126
+
127
+ segment = mpConstants.Segment.build("Chapter 1", 0, 183400)
128
+ mediaSession.segment = segment
129
+ mediaSession.mediaSessionSegmentTotal = 1
130
+ mediaSession.currentPlayheadPosition = 0
131
+ mediaSession.mediaContentTimeSpent = 0
132
+ m.mparticle.media.logSegmentStart(mediaSession, customAttributes)
133
+
134
+ print ("Logging session after segment start: " + formatjson(mediaSession))
135
+
136
+ customAttributes = { "Source": "Auto Playback" }
137
+ m.mparticle.media.logPlay(mediaSession, customAttributes)
138
+
139
+ print ("Logging session after play: " + formatjson(mediaSession))
140
+
141
+ mediaSession.currentPlayheadPosition = 1000
142
+ mediaSession.mediaContentTimeSpent = 1000
143
+ m.mparticle.media.logPlayheadPosition(mediaSession)
144
+
145
+ print ("Logging session after playhead: " + formatjson(mediaSession))
146
+
147
+ mediaSession.currentPlayheadPosition = 1900
148
+ mediaSession.mediaContentTimeSpent = 1900
149
+ customAttributes = { "Source": "Player Controls" }
150
+ m.mparticle.media.logPause(mediaSession, customAttributes)
151
+
152
+ print ("Logging session after pause: " + formatjson(mediaSession))
153
+
154
+ adBreak = mpConstants.adBreak.build("XYZ123", "Gamer Ad Collection")
155
+ adBreak.duration = 32000
156
+ mediaSession.adBreak = adBreak
157
+ m.mparticle.media.logAdBreakStart(mediaSession, {})
158
+
159
+ print ("Logging session after adBreak start: " + formatjson(mediaSession))
160
+
161
+ adContent = mpConstants.adContent.build("ABC890", "CP 2077 - Be Cool, Be Anything")
162
+ adContent.duration = 16000
163
+ adContent.position = 0
164
+ adContent.campaign = "CP 2077 Preorder Push"
165
+ mediaSession.adContent = adContent
166
+ mediaSession.mediaSessionAdTotal = 1
167
+ mediaSession.mediaSessionAdObjects.push(adContent.id)
168
+ mediaSession.mediaContentTimeSpent = 1950
169
+ m.mparticle.media.logAdStart(mediaSession, {})
170
+
171
+ print ("Logging session after ad start: " + formatjson(mediaSession))
172
+
173
+ customAttributes = { "click_timestamp_ms": 1593007533602 }
174
+ mediaSession.adContent.position = 800
175
+ mediaSession.mediaContentTimeSpent = 2750
176
+ m.mparticle.media.logAdClick(mediaSession, customAttributes)
177
+
178
+ print ("Logging session after ad click: " + formatjson(mediaSession))
179
+
180
+ m.mparticle.media.logAdEnd(mediaSession, {})
181
+ m.mparticle.media.logAdSummary(mediaSession, {})
182
+ mediaSession.adContent = invalid
183
+
184
+ print ("Logging session after ad end: " + formatjson(mediaSession))
185
+
186
+ adContent2 = mpConstants.adContent.build("ABC543", "VtM: B2 - Own the night")
187
+ adContent2.duration = 16000
188
+ adContent2.position = 0
189
+ adContent2.campaign = "VtM: Revival"
190
+ mediaSession.adContent = adContent2
191
+ mediaSession.mediaSessionAdTotal = 2
192
+ mediaSession.mediaSessionAdObjects.push(adContent2.id)
193
+ mediaSession.mediaContentTimeSpent = 3000
194
+ m.mparticle.media.logAdStart(mediaSession, {})
195
+
196
+ print ("Logging session after ad start 2: " + formatjson(mediaSession))
197
+
198
+ mediaSession.adContent.position = 3000
199
+ mediaSession.mediaContentTimeSpent = 6000
200
+ m.mparticle.media.logAdSkip(mediaSession, {})
201
+ m.mparticle.media.logAdSummary(mediaSession, {})
202
+ mediaSession.adContent = invalid
203
+
204
+ print ("Logging session after ad skip: " + formatjson(mediaSession))
205
+
206
+ m.mparticle.media.logAdBreakEnd(mediaSession, {})
207
+ mediaSession.adBreak = invalid
208
+
209
+ print ("Logging session after adBreak end: " + formatjson(mediaSession))
210
+
211
+ m.mparticle.media.logQoS(mediaSession, 120, 3, 1232133, 46, {})
212
+
213
+ print ("Logging session after QOS: " + formatjson(mediaSession))
214
+
215
+ m.mparticle.media.logSegmentEnd(mediaSession, customAttributes)
216
+ m.mparticle.media.logSegmentSummary(mediaSession, customAttributes)
217
+ mediaSession.segment = invalid
218
+
219
+ print ("Logging session after segment end: " + formatjson(mediaSession))
220
+
221
+ segment2 = mpConstants.Segment.build("Chapter 2", 1, 17500)
222
+ mediaSession.segment = segment2
223
+ mediaSession.mediaSessionSegmentTotal = 2
224
+ m.mparticle.media.logSegmentStart(mediaSession, customAttributes)
225
+
226
+ print ("Logging session after segment start 2: " + formatjson(mediaSession))
227
+
228
+ m.mparticle.media.logSeekStart(mediaSession, 1900, customAttributes)
229
+
230
+ print ("Logging session after seek start: " + formatjson(mediaSession))
231
+
232
+ m.mparticle.media.logSeekEnd(mediaSession, 45600, {})
233
+
234
+ print ("Logging session after seek end: " + formatjson(mediaSession))
235
+
236
+ m.mparticle.media.logSegmentSkip(mediaSession, customAttributes)
237
+ m.mparticle.media.logSegmentSummary(mediaSession, customAttributes)
238
+ mediaSession.segment = invalid
239
+
240
+ print ("Logging session after segment skip: " + formatjson(mediaSession))
241
+
242
+ m.mparticle.media.logBufferStart(mediaSession, 1200, 0.12, 45600, customAttributes)
243
+
244
+ print ("Logging session after buffer start: " + formatjson(mediaSession))
245
+
246
+ m.mparticle.media.logBufferEnd(mediaSession, 563300, 1.0, 45600, {})
247
+
248
+ print ("Logging session after buffer end: " + formatjson(mediaSession))
249
+
250
+ mediaSession.mediaContentComplete = true
251
+ m.mparticle.media.logMediaContentEnd(mediaSession, customAttributes)
252
+
253
+ print ("Logging session after media content End: " + formatjson(mediaSession))
254
+
255
+ m.mparticle.media.logMediaSessionEnd(mediaSession, customAttributes)
256
+ m.mparticle.media.logMediaSessionSummary(mediaSession, customAttributes)
257
+
258
+
259
+ print ("Logging session after End: " + formatjson(mediaSession))
260
+
261
+ appInfo = CreateObject("roAppInfo")
262
+ if appInfo.IsDev() and Type(TestRunner) <> "<uninitialized>" and TestRunner <> invalid and GetInterface(TestRunner, "ifFunction") <> invalid then
263
+ Runner = TestRunner()
264
+ Runner.SetFunctions([
265
+ TestCase__ProductAction
266
+ Test_SimpleCustom
267
+ Test_Consent
268
+ Test_Media
269
+ ])
270
+
271
+ if args.IncludeFilter <> invalid
272
+ Runner.SetIncludeFilter(args.IncludeFilter)
273
+ end if
274
+
275
+ if args.ExcludeFilter <> invalid
276
+ Runner.SetExcludeFilter(args.ExcludeFilter)
277
+ end if
278
+
279
+ Runner.Logger.SetVerbosity(3)
280
+ Runner.Logger.SetEcho(false)
281
+ Runner.Logger.SetJUnit(false)
282
+ Runner.SetFailFast(true)
283
+
284
+ Runner.Run()
285
+ end if
286
+ end sub
287
+
288
+ function onIdentityResult() as void
289
+ print "IdentityResult: " + formatjson(m.mParticleTask[mParticleConstants().SCENEGRAPH_NODES.IDENTITY_RESULT_NODE])
290
+ end function
291
+
292
+ function onCurrentUserChanged() as void
293
+ currentUser = m.mParticleTask[mParticleConstants().SCENEGRAPH_NODES.CURRENT_USER_NODE]
294
+ print "Current user: " + formatjson(currentUser)
295
+ m.mpidLabel.text = "MPID: " + currentUser.mpid
296
+ m.userAttributesLabel.text = "User attributes: " + formatjson(currentUser.userAttributes)
297
+ m.userIdentitiesLabel.text = "User identities: " + formatjson(currentUser.userIdentities)
298
+
299
+ m.mparticle.logEvent("User Changed", mparticleconstants().CUSTOM_EVENT_TYPE.USER_CONTENT, currentUser)
300
+ end function
@@ -0,0 +1,66 @@
1
+ <?xml version="1.0" encoding="utf-8" ?>
2
+ <component name="HelloWorld" extends="Scene">
3
+ <children>
4
+ <Group id = "exampleLayoutGroup" >
5
+ <LayoutGroup
6
+ translation = "[ 0, 0 ]"
7
+ itemSpacings = "[50]"
8
+ layoutDirection = "vert" >
9
+ <LayoutGroup
10
+
11
+ translation = "[ 0, 0 ]"
12
+ itemSpacings = "[20]"
13
+ layoutDirection = "horiz" >
14
+
15
+ <TextEditBox id="emailTextEdit"
16
+ hintText = "Email"
17
+ active="true"
18
+ font = "font:SmallestSystemFont"
19
+ horizAlign="center"
20
+ />
21
+
22
+ <TextEditBox id="customerIdTextEdit"
23
+ hintText = "Customer Id"
24
+ font = "font:SmallestSystemFont"
25
+ horizAlign="center"
26
+ />
27
+
28
+ <TextEditBox id="otherIdTextEdit"
29
+ hintText = "Other ID"
30
+ font = "font:SmallestSystemFont"
31
+ horizAlign="center"
32
+ />
33
+
34
+ </LayoutGroup>
35
+ <LayoutGroup
36
+
37
+ translation = "[ 0, 0 ]"
38
+ itemSpacings = "[20]"
39
+ layoutDirection = "vert" >
40
+
41
+ <Label id="mpidLabel"
42
+ text = "MPID"
43
+ font = "font:SmallestSystemFont"
44
+ horizAlign="center"
45
+ />
46
+
47
+ <Label id="userAttributesLabel"
48
+ text = "User Attributes"
49
+ font = "font:SmallestSystemFont"
50
+ horizAlign="center"
51
+ />
52
+
53
+ <Label id="userIdentitiesLabel"
54
+ text = "User Identities"
55
+ font = "font:SmallestSystemFont"
56
+ horizAlign="center"
57
+ />
58
+
59
+ </LayoutGroup>
60
+ </LayoutGroup>
61
+ </Group>
62
+ </children>
63
+ <script type="text/brightscript" uri="pkg:/components/helloworld.brs"/>
64
+ <!-- Replace with correct path if necessary -->
65
+ <script type="text/brightscript" uri="pkg:/source/mparticle/mParticleCore.brs"/>
66
+ </component>
@@ -0,0 +1,12 @@
1
+ title=Hello World
2
+ major_version=1
3
+ minor_version=1
4
+ build_version=00001
5
+ mm_icon_focus_hd=pkg:/images/channel-poster_hd.png
6
+ mm_icon_focus_sd=pkg:/images/channel-poster_sd.png
7
+ splash_screen_fhd=pkg:/images/splash-screen_fhd.jpg
8
+ splash_screen_hd=pkg:/images/splash-screen_hd.jpg
9
+ splash_screen_sd=pkg:/images/splash-screen_sd.jpg
10
+ splash_color=#000000
11
+ splash_min_time=1
12
+ mm_icon_focus_fhd=pkg:/images/channel-poster_fhd.png
@@ -0,0 +1,46 @@
1
+ '*************************************************************
2
+ '** Hello World example
3
+ '** Copyright (c) 2015 Roku, Inc. All rights reserved.
4
+ '** Use of the Roku Platform is subject to the Roku SDK License Agreement:
5
+ '** https://docs.roku.com/doc/developersdk/en-us
6
+ '*************************************************************
7
+
8
+ sub Main(args as dynamic)
9
+ print "in showChannelSGScreen"
10
+ 'Indicate this is a Roku SceneGraph application'
11
+ screen = CreateObject("roSGScreen")
12
+ m.port = CreateObject("roMessagePort")
13
+ screen.setMessagePort(m.port)
14
+
15
+ 'Create a scene and load /components/helloworld.xml'
16
+ scene = screen.CreateScene("HelloWorld")
17
+
18
+ options = {}
19
+ options.logLevel = mparticleConstants().LOG_LEVEL.DEBUG
20
+ options.apiKey = "REPLACE WITH API KEY"
21
+ options.apiSecret = "REPLACE WITH API SECRET"
22
+ 'OPTIONAL: For use with our data master feature
23
+ options.dataPlanId = "REPLACE WITH DATA PLAN ID"
24
+ options.dataPlanVersion = 1 'REPLACE WITH DATA PLAN VERSION
25
+
26
+ 'If you know the users credentials, supply them here
27
+ 'otherwise the SDK will use the last known identities
28
+ identityApiRequest = { userIdentities: {} }
29
+ identityApiRequest.userIdentities[mparticleConstants().IDENTITY_TYPE.EMAIL] = "user@example.com"
30
+ options.identifyRequest = identityApiRequest
31
+
32
+ options.environment = mparticleConstants().ENVIRONMENT.FORCE_DEVELOPMENT
33
+ options.startupArgs = args
34
+
35
+ 'REQUIRED: mParticle will look for mParticleOptions in the global node
36
+ screen.getGlobalNode().addFields({ mparticleOptions: options })
37
+ screen.show()
38
+
39
+ while(true)
40
+ msg = wait(0, m.port)
41
+ msgType = type(msg)
42
+ if msgType = "roSGScreenEvent"
43
+ if msg.isScreenClosed() then return
44
+ end if
45
+ end while
46
+ end sub