@24i/smartapps-bigscreen-rnv-build-engine 0.17.26 → 0.17.27-alpha.2774
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.
- package/dist/src/sdks/sdk-androidtv/sdkAndroidtv.js +4 -0
- package/dist/templates/platforms/androidtv/project/app/build.gradle +9 -4
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/bridge/BridgeToJavaScript.kt +16 -0
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/global/utils/PlayerFactoryExoPlayerNpaw.kt +63 -16
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/model/MediaEventType.kt +5 -2
- package/dist/templates/platforms/androidtv/project/app/src/main/java/com/twentyfouri/tvbridge/webview/viewmodel/WebViewModel.kt +13 -4
- package/package.json +1 -1
|
@@ -200,6 +200,7 @@ const configureEntryUrl = (c) => {
|
|
|
200
200
|
|| rnv_1.Common.getConfigProp(c, c.platform, 'theoLicense', '');
|
|
201
201
|
const npawAccountCode = process.env.NPAW_ACCOUNT_CODE
|
|
202
202
|
|| rnv_1.Common.getConfigProp(c, c.platform, 'npawAccountCode', '');
|
|
203
|
+
const enableImaSdk = !!rnv_1.Common.getConfigProp(c, c.platform, 'enableImaSdk', false);
|
|
203
204
|
const injects = [{
|
|
204
205
|
pattern: '{{APP_URL}}',
|
|
205
206
|
override: entryUrl,
|
|
@@ -209,6 +210,9 @@ const configureEntryUrl = (c) => {
|
|
|
209
210
|
}, {
|
|
210
211
|
pattern: '{{NPAW_ACCOUNT_CODE}}',
|
|
211
212
|
override: npawAccountCode,
|
|
213
|
+
}, {
|
|
214
|
+
pattern: '{{ENABLE_IMA_SDK}}',
|
|
215
|
+
override: enableImaSdk,
|
|
212
216
|
}];
|
|
213
217
|
rnv_1.Common.addSystemInjects(c, injects);
|
|
214
218
|
rnv_1.FileUtils.writeCleanFile(buildGradleFilePath, buildGradleFilePath, injects, null, c);
|
|
@@ -6,6 +6,7 @@ def theoLicense = '{{THEO_LICENSE}}'
|
|
|
6
6
|
def useTheoPlayer = theoLicense != ''
|
|
7
7
|
def npawAccountCode = '{{NPAW_ACCOUNT_CODE}}'
|
|
8
8
|
def useNpawPlugin = npawAccountCode != ''
|
|
9
|
+
def useImaSdk = {{ENABLE_IMA_SDK}}
|
|
9
10
|
|
|
10
11
|
android {
|
|
11
12
|
namespace = 'com.twentyfouri.tvbridge'
|
|
@@ -104,12 +105,12 @@ dependencies {
|
|
|
104
105
|
implementation "com.squareup.okhttp3:logging-interceptor:4.9.2"
|
|
105
106
|
implementation "com.squareup.okhttp3:okhttp:4.9.2"
|
|
106
107
|
if (useTheoPlayer) {
|
|
107
|
-
compileOnly "com.twentyfouri.player:exoplayer:0.8.0-alpha.
|
|
108
|
-
implementation "com.twentyfouri.player:theoplayer:0.8.0-alpha.
|
|
108
|
+
compileOnly "com.twentyfouri.player:exoplayer:0.8.0-alpha.15"
|
|
109
|
+
implementation "com.twentyfouri.player:theoplayer:0.8.0-alpha.15"
|
|
109
110
|
implementation "com.theoplayer.theoplayer-sdk-android:core:8.2.0"
|
|
110
111
|
} else {
|
|
111
|
-
implementation "com.twentyfouri.player:exoplayer:0.8.0-alpha.
|
|
112
|
-
compileOnly "com.twentyfouri.player:theoplayer:0.8.0-alpha.
|
|
112
|
+
implementation "com.twentyfouri.player:exoplayer:0.8.0-alpha.15"
|
|
113
|
+
compileOnly "com.twentyfouri.player:theoplayer:0.8.0-alpha.15"
|
|
113
114
|
compileOnly "com.theoplayer.theoplayer-sdk-android:core:8.2.0"
|
|
114
115
|
}
|
|
115
116
|
|
|
@@ -123,6 +124,10 @@ dependencies {
|
|
|
123
124
|
compileOnly 'com.google.android.exoplayer:extension-okhttp:2.19.1'
|
|
124
125
|
}
|
|
125
126
|
|
|
127
|
+
if (useImaSdk) {
|
|
128
|
+
implementation 'com.google.ads.interactivemedia.v3:interactivemedia:3.36.0'
|
|
129
|
+
}
|
|
130
|
+
|
|
126
131
|
implementation project(':common')
|
|
127
132
|
}
|
|
128
133
|
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package com.twentyfouri.tvbridge.bridge
|
|
2
2
|
|
|
3
3
|
import android.util.Log
|
|
4
|
+
import com.twentyfouri.player.base.Ad
|
|
5
|
+
import com.twentyfouri.player.base.AdBreak
|
|
4
6
|
import com.twentyfouri.player.base.AudioTrack
|
|
5
7
|
import com.twentyfouri.player.base.DefaultSourceSerializer
|
|
6
8
|
import com.twentyfouri.player.base.TextTrack
|
|
@@ -63,6 +65,20 @@ class BridgeToJavaScript(
|
|
|
63
65
|
executeJavaScript(mediaEventString)
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
fun bridgeAndroidToJavaScript_MediaAdEvent(
|
|
69
|
+
mediaEvent: String,
|
|
70
|
+
adBreak: AdBreak?,
|
|
71
|
+
ad: Ad?
|
|
72
|
+
) {
|
|
73
|
+
val serializer = DefaultSourceSerializer()
|
|
74
|
+
val adBreakJson = adBreak?.let { serializer.toPersistentMap(it).toString() } ?: ""
|
|
75
|
+
val adJson = ad?.let { serializer.toPersistentMap(it).toString() } ?: ""
|
|
76
|
+
|
|
77
|
+
val mediaEventString = "javascript:((function dispatchEvent(){var evt = document.createEvent('Events');evt.initEvent('$mediaEventPrefix$mediaEvent',true,true);evt.adbreak='$adBreakJson';evt.adbreak='$adJson';document.dispatchEvent(evt);})())"
|
|
78
|
+
Log.v(LOG_TAG, mediaEventString)
|
|
79
|
+
executeJavaScript(mediaEventString)
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
fun bridgeAndroidToJavaScript_MediaAdBreaksEvent(
|
|
67
83
|
mediaEvent: String,
|
|
68
84
|
timeline: List<TimelineEvent>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
package com.twentyfouri.tvbridge.global.utils
|
|
2
2
|
|
|
3
3
|
import android.annotation.SuppressLint
|
|
4
|
-
import android.app.Application
|
|
5
4
|
import android.content.Context
|
|
6
5
|
import android.content.ContextWrapper
|
|
7
6
|
import android.os.Bundle
|
|
@@ -45,13 +44,16 @@ import com.npaw.analytics.video.VideoOptions
|
|
|
45
44
|
import com.npaw.core.options.AnalyticsOptions
|
|
46
45
|
import com.npaw.exoplayer.ExoPlayerAdapter
|
|
47
46
|
import com.npaw.exoplayer.ExoPlayerBalancer
|
|
47
|
+
import com.twentyfouri.player.base.BackgroundMode
|
|
48
48
|
import com.twentyfouri.player.base.CastingEnded
|
|
49
49
|
import com.twentyfouri.player.base.CastingStarted
|
|
50
|
+
import com.twentyfouri.player.base.CastingType
|
|
50
51
|
import com.twentyfouri.player.base.DrmPlayready
|
|
51
52
|
import com.twentyfouri.player.base.DrmWidevine
|
|
52
53
|
import com.twentyfouri.player.base.EventListenerDispose
|
|
53
54
|
import com.twentyfouri.player.base.PlayerBase
|
|
54
55
|
import com.twentyfouri.player.base.PlayerGesturesTarget
|
|
56
|
+
import com.twentyfouri.player.base.PlayerProxy
|
|
55
57
|
import com.twentyfouri.player.base.PlayerSurface
|
|
56
58
|
import com.twentyfouri.player.base.ResizeEvent
|
|
57
59
|
import com.twentyfouri.player.base.ScaleType
|
|
@@ -71,11 +73,11 @@ import com.twentyfouri.player.exoplayer.DrmSessionManagerProvider
|
|
|
71
73
|
import com.twentyfouri.player.exoplayer.PlayerComponents
|
|
72
74
|
import com.twentyfouri.player.exoplayer.PlayerExoPlayer
|
|
73
75
|
import com.twentyfouri.player.exoplayer.PlayerFactoryExoPlayer
|
|
74
|
-
import com.twentyfouri.player.exoplayer.PlayerProxy
|
|
75
76
|
import com.twentyfouri.player.exoplayer.PlayerViewAdvertisement
|
|
76
77
|
import com.twentyfouri.player.exoplayer.SharedComponents
|
|
77
78
|
import com.twentyfouri.tvbridge.BuildConfig
|
|
78
79
|
import com.twentyfouri.tvbridge.configuration.BridgeConfig
|
|
80
|
+
import java.util.WeakHashMap
|
|
79
81
|
import com.npaw.core.util.extensions.Log as NpawLog
|
|
80
82
|
|
|
81
83
|
class PlayerFactoryExoPlayerNpaw(
|
|
@@ -86,9 +88,11 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
86
88
|
|
|
87
89
|
override val engineVersion: String = ExoPlayerLibraryInfo.VERSION
|
|
88
90
|
|
|
91
|
+
private val activePlayers = WeakHashMap<PlayerBase, Boolean>()
|
|
92
|
+
|
|
89
93
|
override fun createSharedComponents(context: Context): SharedComponents =
|
|
90
94
|
CustomizedSharedComponents(context)
|
|
91
|
-
|
|
95
|
+
|
|
92
96
|
override fun createView(parent: ViewGroup): View {
|
|
93
97
|
return NpawPlayerView(parent.context).also {
|
|
94
98
|
val basePlayer = createPlayer(parent.context)
|
|
@@ -97,7 +101,7 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
97
101
|
.sharedComponents as CustomizedSharedComponents
|
|
98
102
|
).npawPlugin
|
|
99
103
|
val npawPlayer = NpawPlayer(basePlayer, npawPlugin)
|
|
100
|
-
|
|
104
|
+
activePlayers[npawPlayer] = true
|
|
101
105
|
it.player = npawPlayer
|
|
102
106
|
}
|
|
103
107
|
}
|
|
@@ -111,10 +115,15 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
111
115
|
?: throw IllegalStateException("Player was not initialized by PlayerFactory")
|
|
112
116
|
}
|
|
113
117
|
|
|
114
|
-
|
|
118
|
+
override fun release() {
|
|
119
|
+
activePlayers.keys.forEach {
|
|
120
|
+
it.destroy()
|
|
121
|
+
}
|
|
122
|
+
activePlayers.clear()
|
|
123
|
+
super.release()
|
|
124
|
+
}
|
|
115
125
|
|
|
116
|
-
|
|
117
|
-
?: throw IllegalStateException("Missing application")
|
|
126
|
+
private inner class CustomizedSharedComponents(context: Context) : DefaultSharedComponents(context) {
|
|
118
127
|
|
|
119
128
|
val npawPlugin: NpawPlugin = NpawPlugin
|
|
120
129
|
.Builder(application, config.npawAccount)
|
|
@@ -335,6 +344,10 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
335
344
|
adOverlay.gesturesTarget = value
|
|
336
345
|
}
|
|
337
346
|
|
|
347
|
+
override var supportsPictureInPicture: Boolean
|
|
348
|
+
get() = false
|
|
349
|
+
set(value) {}
|
|
350
|
+
|
|
338
351
|
var player: PlayerBase? = null
|
|
339
352
|
set(value) {
|
|
340
353
|
if (field == value) return
|
|
@@ -474,6 +487,23 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
474
487
|
}
|
|
475
488
|
}
|
|
476
489
|
|
|
490
|
+
override fun onUserLeaveHint() {
|
|
491
|
+
(player as? PlayerProxy)?.onUserLeaveHint()
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
override fun onPictureInPictureModeChanged(inPictureInPictureMode: Boolean) {
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
fun autoPauseByBackground() {
|
|
498
|
+
val player = this.player ?: return
|
|
499
|
+
if (player.live) {
|
|
500
|
+
player.stop()
|
|
501
|
+
} else {
|
|
502
|
+
player.pause()
|
|
503
|
+
}
|
|
504
|
+
pausedByBackground = true
|
|
505
|
+
}
|
|
506
|
+
|
|
477
507
|
private inner class ComponentListener : TextOutput, Player.Listener,
|
|
478
508
|
DefaultLifecycleObserver {
|
|
479
509
|
override fun onCues(cueGroup: CueGroup) {
|
|
@@ -499,29 +529,46 @@ class PlayerFactoryExoPlayerNpaw(
|
|
|
499
529
|
this@NpawPlayerView.keepScreenOn = isPlaying
|
|
500
530
|
}
|
|
501
531
|
|
|
502
|
-
override fun
|
|
532
|
+
override fun onStop(owner: LifecycleOwner) {
|
|
503
533
|
val player = this@NpawPlayerView.player ?: return
|
|
504
534
|
player.asPlayerExoPlayer()?.also {
|
|
505
535
|
detachSurface(it)
|
|
506
536
|
}
|
|
507
|
-
if (
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
537
|
+
if (
|
|
538
|
+
!player.paused && player.state.source != null &&
|
|
539
|
+
player.castingType == CastingType.NONE
|
|
540
|
+
) {
|
|
541
|
+
val shouldPause = when (player.continueInBackgroundMode) {
|
|
542
|
+
BackgroundMode.PAUSE -> true
|
|
543
|
+
BackgroundMode.PICTURE_IN_PICTURE -> when {
|
|
544
|
+
player.isCastingHost -> false
|
|
545
|
+
player.pictureInPicture -> false
|
|
546
|
+
else -> true // PiP disabled in system settings?
|
|
547
|
+
}
|
|
548
|
+
else -> false
|
|
549
|
+
}
|
|
550
|
+
if (shouldPause) {
|
|
551
|
+
autoPauseByBackground()
|
|
512
552
|
}
|
|
513
|
-
|
|
553
|
+
}
|
|
554
|
+
if (player is PlayerProxy) {
|
|
555
|
+
player.onLifecycleStop()
|
|
514
556
|
}
|
|
515
557
|
}
|
|
516
558
|
|
|
517
|
-
override fun
|
|
559
|
+
override fun onStart(owner: LifecycleOwner) {
|
|
518
560
|
val player = this@NpawPlayerView.player ?: return
|
|
519
561
|
if (pausedByBackground) {
|
|
520
562
|
pausedByBackground = false
|
|
521
563
|
player.play()
|
|
522
564
|
}
|
|
565
|
+
if (player is PlayerProxy) {
|
|
566
|
+
player.onLifecycleStart()
|
|
567
|
+
}
|
|
523
568
|
player.asPlayerExoPlayer()?.also {
|
|
524
|
-
|
|
569
|
+
if (player.castingType == CastingType.NONE) {
|
|
570
|
+
attachSurface(it)
|
|
571
|
+
}
|
|
525
572
|
}
|
|
526
573
|
}
|
|
527
574
|
|
|
@@ -20,7 +20,10 @@ object MediaEventType {
|
|
|
20
20
|
const val KEY_UP = "keyup"
|
|
21
21
|
const val KEY_DOWN = "keydown"
|
|
22
22
|
const val TRACKS_CHANGED = "trackschanged"
|
|
23
|
-
const val AD_BREAK_START = "
|
|
23
|
+
const val AD_BREAK_START = "adbreakbegin"
|
|
24
24
|
const val AD_BREAK_END = "adbreakend"
|
|
25
|
-
const val AD_BREAKS_RESCHEDULED = "
|
|
25
|
+
const val AD_BREAKS_RESCHEDULED = "admetadata"
|
|
26
|
+
const val AD_STARTED = "adbegin"
|
|
27
|
+
const val AD_ERROR = "aderror"
|
|
28
|
+
const val AD_SKIPPED = "adskip"
|
|
26
29
|
}
|
|
@@ -328,14 +328,23 @@ class WebViewModel @Inject constructor(
|
|
|
328
328
|
Log.d("WebViewModel", "onTrackschanged: audio=$audioTrack subtitle=$subtitleTrack")
|
|
329
329
|
jsBridge.bridgeAndroidToJavaScript_MediaTrackEvent(MediaEventType.TRACKS_CHANGED, player.audioTracks, player.textTracks)
|
|
330
330
|
}
|
|
331
|
+
is AdBreaksRescheduledEvent -> {
|
|
332
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdBreaksEvent(MediaEventType.AD_BREAKS_RESCHEDULED, player.timeline)
|
|
333
|
+
}
|
|
331
334
|
is AdBreakStartedEvent -> {
|
|
332
|
-
jsBridge.
|
|
335
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_BREAK_START, player.currentAdBreak, player.currentAd)
|
|
333
336
|
}
|
|
334
337
|
is AdBreakEndedEvent -> {
|
|
335
|
-
jsBridge.
|
|
338
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_BREAK_END, player.currentAdBreak, player.currentAd)
|
|
336
339
|
}
|
|
337
|
-
is
|
|
338
|
-
jsBridge.
|
|
340
|
+
is AdStartedEvent -> {
|
|
341
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_STARTED, player.currentAdBreak, player.currentAd)
|
|
342
|
+
}
|
|
343
|
+
is AdErrorEvent -> {
|
|
344
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_ERROR, player.currentAdBreak, player.currentAd)
|
|
345
|
+
}
|
|
346
|
+
is AdSkippedEvent -> {
|
|
347
|
+
jsBridge.bridgeAndroidToJavaScript_MediaAdEvent(MediaEventType.AD_SKIPPED, player.currentAdBreak, player.currentAd)
|
|
339
348
|
}
|
|
340
349
|
}
|
|
341
350
|
}
|
package/package.json
CHANGED