mparticle-roku-sdk 2.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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