Compare commits

...

70 Commits

Author SHA1 Message Date
ff0f288636 Merge remote-tracking branch 'origin/master' into ivan/merging-shaka-hls 2024-12-02 22:57:41 -07:00
YangJH
64c222df44
chore(android): bump default androidx.activity version from v1.8.2 to v1.9.3 (#4314) 2024-12-01 13:46:56 +01:00
Kamil Moskała
621a80299c
fix: hiding poster (#4308)
* fix: hiding poster

* fix: hiding poster

* remove zIndex: 1

* fix: remove showPoster from dependency array
2024-12-01 13:41:03 +01:00
Olivier Bouillet
63c592f7cd
fix(android): disable caching on local asset files (#4304) 2024-12-01 13:29:24 +01:00
Olivier Bouillet
569a79c510 chore: release v6.8.2 2024-11-25 21:36:30 +01:00
Olivier Bouillet
f37dc9e33e
fix: playback restart without bufferingConfig (#4305) 2024-11-25 21:33:56 +01:00
Olivier Bouillet
dd78241b0d chore: release v6.8.1 2024-11-24 21:25:46 +01:00
Olivier Bouillet
2b7c215e66
Fix(android): restart issue react76 (#4302)
* fix: upgrade to expo 54
* fix: more bufferConfig inside source
- restart issue on react 0.76
- fix constness
- deprecate bufferConfig in root props
- update documentation
2024-11-24 21:19:46 +01:00
Tarık
daaac9740a
fix(ios): handle async player access in text track selection (#4293)
* fix(ios): add null check to setSelectedTextTrack for player instance

* Revert "fix(ios): add null check to setSelectedTextTrack for player instance"

This reverts commit 447c83423cdd77b0cfa9cc171b231327a2cf1586.

* fix(ios): ensure strong reference to player during async operation

* fix: linter

* fix: linter formatting

* fix: revert typo
2024-11-22 14:19:09 +01:00
Krzysztof Moch
d934f214f5
chore: release v6.8.0 2024-11-17 15:42:49 +01:00
d7977241c9 Account for crop in progress 2024-10-18 03:25:50 -06:00
921ead0f05 Timeout actions 2024-10-17 19:21:06 -06:00
20397d32e6 More logging 2024-10-17 19:11:22 -06:00
e3900e794d What is going on 2024-10-17 19:07:39 -06:00
4dc7bf465f Typescript 2024-10-17 18:59:42 -06:00
e5f182cda9 Use an async queue 2024-10-17 18:56:38 -06:00
9138c3249d Try to fix double load 2024-10-17 18:34:34 -06:00
7a1d0e8b10 Try to fix source quality issue 2024-10-17 18:28:16 -06:00
9cbba8f95e Typescript again 2024-10-17 18:22:26 -06:00
2cfb26d51f Typescript 2024-10-17 18:20:28 -06:00
4f18e9b238 Fix never ending loading, try to respect crops 2024-10-17 18:19:05 -06:00
bd64379837 Merge pull request 'Fix android build' (#7) from volodymyr/fix-android-build into feat/shaka
Reviewed-on: #7
Reviewed-by: Ivan Malison <ivanmalison@gmail.com>
2024-10-14 07:01:12 -06:00
47151c7119 Fix android build
Some checks failed
Build Android / Build Android Example App (pull_request) Has been cancelled
Build Android / Build Android Example App Without Ads (pull_request) Has been cancelled
Check Android / Kotlin-Lint (pull_request) Has been cancelled
2024-10-14 11:02:21 +02:00
a16275b003 ts-ignores 2024-10-13 22:48:51 -06:00
56c129aa4f Don't patch package anymore 2024-10-13 22:45:06 -06:00
68cbe3c4b1 Don't require rate to be defined 2024-10-13 20:45:25 -06:00
81e864c0e1 Update shaka when nativeRef changes 2024-10-13 19:17:01 -06:00
0e9ac4d125 Shaka loggin 2024-10-13 15:14:48 -06:00
9191a06600 Simple shaka 2024-10-13 15:04:44 -06:00
dc61c3efea Fix tsc 2024-10-13 14:18:49 -06:00
11f480f206 Start muted 2024-10-13 14:15:28 -06:00
9619e7517b Try again 2024-10-13 02:06:12 -06:00
3ddc6e931a More hacks 2024-10-13 01:09:57 -06:00
6b5831dc1c Hacks 2024-10-13 01:07:48 -06:00
3fc002f3fd Fix ts issues 2024-10-13 00:44:54 -06:00
edb5c6bcfa Merge remote-tracking branch 'railbird/master' into feat/shaka 2024-10-12 23:52:26 -06:00
5bc975b2c9 Shaka? 2024-10-12 23:48:55 -06:00
d79b5c9a83 Merge remote-tracking branch 'origin/master' into feat/web 2024-10-12 23:40:00 -06:00
f72b44d4df Merge pull request 'Implement onSeekComplete for Android' (#5) from kat/temp-4 into master
Some checks failed
Build Android / Build Android Example App (push) Has been cancelled
Build Android / Build Android Example App Without Ads (push) Has been cancelled
Check Android / Kotlin-Lint (push) Has been cancelled
Reviewed-on: #5
2024-08-26 17:23:32 -06:00
d2ab22b99f wip
Some checks failed
Build Android / Build Android Example App (pull_request) Has been cancelled
Build Android / Build Android Example App Without Ads (pull_request) Has been cancelled
Check Android / Kotlin-Lint (pull_request) Has been cancelled
2024-08-26 17:22:38 -06:00
2dcde42fd6 Add logs 2024-08-26 17:22:38 -06:00
c7a45d421b Only complete seek if seek was in progress 2024-08-26 17:22:38 -06:00
f0db0a6868 kat wip 2024-08-26 17:22:38 -06:00
01b3322e03 Log in seek 2024-08-26 17:22:38 -06:00
13beae1401 Merge pull request 'Implement ios onSeekComplete' (#3) from kat/seek-complete-ios into master
Some checks failed
Build iOS / Build iOS Example App (push) Has been cancelled
Build iOS / Build iOS Example App With Ads (push) Has been cancelled
Build iOS / Build iOS Example App With Caching (push) Has been cancelled
Check CLang / CLang-Format (push) Has been cancelled
Check iOS / Swift-Lint (push) Has been cancelled
Check iOS / Swift-Format (push) Has been cancelled
Reviewed-on: #3
2024-08-20 22:37:10 -06:00
f3deabd75e Implement ios onSeekComplete
Some checks failed
Build iOS / Build iOS Example App (pull_request) Has been cancelled
Build iOS / Build iOS Example App With Ads (pull_request) Has been cancelled
Build iOS / Build iOS Example App With Caching (pull_request) Has been cancelled
Check CLang / CLang-Format (pull_request) Has been cancelled
Check iOS / Swift-Lint (pull_request) Has been cancelled
Check iOS / Swift-Format (pull_request) Has been cancelled
2024-08-20 22:24:00 -06:00
d69729dc04 expose-on-seek-complete (#1)
Some checks failed
Build iOS / Build iOS Example App (push) Has been cancelled
Build iOS / Build iOS Example App With Ads (push) Has been cancelled
Build iOS / Build iOS Example App With Caching (push) Has been cancelled
Check CLang / CLang-Format (push) Has been cancelled
Check iOS / Swift-Lint (push) Has been cancelled
Check iOS / Swift-Format (push) Has been cancelled
Check JS / Check TS (tsc) (push) Has been cancelled
Check JS / Lint JS (eslint, prettier) (push) Has been cancelled
Reviewed-on: #1
2024-08-06 00:11:17 -06:00
Zoe Roux
6768c22139
Add nativeHtmlVideoRef doc 2024-07-16 12:31:32 +07:00
Zoe Roux
2b369df57d
Fix native import on web 2024-07-16 12:31:32 +07:00
Zoe Roux
8542c8f7d1
Add isSeeking on web 2024-07-16 12:31:32 +07:00
Zoe Roux
fc5b2d4563
Add web support for fullscreen 2024-07-16 11:33:50 +07:00
Zoe Roux
ffb4631854
Remove unused errorHandler ref 2024-07-16 11:33:50 +07:00
Zoe Roux
29cf7c97c3
Update doc for web 2024-07-16 11:33:50 +07:00
Zoe Roux
491ed77a32
Renamve nativeHtmlRef to nativeHtmlVideoRef 2024-07-16 11:33:50 +07:00
Zoe Roux
5b199b52b4
Move video style to const var 2024-07-16 11:33:50 +07:00
Zoe Roux
9d19157654
Add web command in basic example 2024-07-16 11:33:50 +07:00
Zoe Roux
3dabf5f16f
Fix and improve VideoNativeComponent (canPlay/isWidewine supportd) for web 2024-07-16 11:33:50 +07:00
Zoe Roux
e610a274d5
Prevent playback state change loop on web 2024-07-16 11:33:50 +07:00
Zoe Roux
27880f5212
Update the doc for web things 2024-07-16 11:33:50 +07:00
Zoe Roux
39dd30b762
Cleanup media session handling on the web 2024-07-16 11:33:50 +07:00
Zoe Roux
edf5d0c613
Test notifications on web 2024-07-16 11:33:50 +07:00
Zoe Roux
975fc2f303
Fix web bugs 2024-07-16 11:33:49 +07:00
Zoe Roux
aa85d71b87
Make the basic example app work on web 2024-07-16 11:33:18 +07:00
Zoe Roux
cce24cd829
Add media session support 2024-07-16 11:33:18 +07:00
Zoe Roux
cad63d465d
Add most properties 2024-07-16 11:33:18 +07:00
Zoe Roux
f5fa063bc0
Add most events 2024-07-16 11:33:18 +07:00
Zoe Roux
c6abcdeb2f
Create ref handling and basics stollen from Kyoo 2024-07-16 11:33:18 +07:00
Zoe Roux
a72ab331dc
Move video ref type to its own file 2024-07-16 11:33:15 +07:00
Zoe Roux
fa126de97f
Add VideoDecoderProperties for the web 2024-07-16 11:24:52 +07:00
Zoe Roux
ca2452edb6
Add shell.nix for nix users 2024-07-16 11:20:12 +07:00
31 changed files with 11839 additions and 1409 deletions

View File

@ -1,5 +1,26 @@
## [6.8.2](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.8.1...v6.8.2) (2024-11-25)
### Bug Fixes
* playback restart without bufferingConfig ([#4305](https://github.com/TheWidlarzGroup/react-native-video/issues/4305)) ([f37dc9e](https://github.com/TheWidlarzGroup/react-native-video/commit/f37dc9e33ebefd922605c5ae91360379fe91bed6))
## [6.8.1](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.8.0...v6.8.1) (2024-11-24)
### Bug Fixes
* **ios:** handle async player access in text track selection ([#4293](https://github.com/TheWidlarzGroup/react-native-video/issues/4293)) ([daaac97](https://github.com/TheWidlarzGroup/react-native-video/commit/daaac9740aed1858b7ababae0ec8b08274130a27))
# [6.8.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.7.0...v6.8.0) (2024-11-17)
### Bug Fixes
* **android:** add helper to avoid type error ([#4257](https://github.com/TheWidlarzGroup/react-native-video/issues/4257)) ([3b4bfd3](https://github.com/TheWidlarzGroup/react-native-video/commit/3b4bfd3936a8cb846c0e61ffd396940987a7ba43))
# [6.7.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.6.4...v6.7.0) (2024-10-17) # [6.7.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.6.4...v6.7.0) (2024-10-17)

View File

@ -91,9 +91,10 @@ def configStringPath = ExoplayerDependencies
.concat("buildFromSource:$media3_buildFromSource") .concat("buildFromSource:$media3_buildFromSource")
.md5() .md5()
if (isNewArchitectureEnabled()) { // commented as new architecture not yet fully supported
apply plugin: "com.facebook.react" // if (isNewArchitectureEnabled()) {
} // apply plugin: "com.facebook.react"
// }
android { android {
if (supportsNamespace()) { if (supportsNamespace()) {

View File

@ -11,5 +11,5 @@ RNVideo_useExoplayerSmoothStreaming=true
RNVideo_useExoplayerDash=true RNVideo_useExoplayerDash=true
RNVideo_useExoplayerHls=true RNVideo_useExoplayerHls=true
RNVideo_androidxCoreVersion=1.13.1 RNVideo_androidxCoreVersion=1.13.1
RNVideo_androidxActivityVersion=1.8.2 RNVideo_androidxActivityVersion=1.9.3
RNVideo_buildFromMedia3Source=false RNVideo_buildFromMedia3Source=false

View File

@ -23,6 +23,23 @@ class BufferConfig {
var live: Live = Live() var live: Live = Live()
/** return true if this and src are equals */
override fun equals(other: Any?): Boolean {
if (other == null || other !is BufferConfig) return false
return (
cacheSize == other.cacheSize &&
minBufferMs == other.minBufferMs &&
maxBufferMs == other.maxBufferMs &&
bufferForPlaybackMs == other.bufferForPlaybackMs &&
bufferForPlaybackAfterRebufferMs == other.bufferForPlaybackAfterRebufferMs &&
backBufferDurationMs == other.backBufferDurationMs &&
maxHeapAllocationPercent == other.maxHeapAllocationPercent &&
minBackBufferMemoryReservePercent == other.minBackBufferMemoryReservePercent &&
minBufferMemoryReservePercent == other.minBufferMemoryReservePercent &&
live == other.live
)
}
class Live { class Live {
var maxPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat() var maxPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat()
var minPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat() var minPlaybackSpeed: Float = BufferConfigPropUnsetDouble.toFloat()
@ -30,12 +47,23 @@ class BufferConfig {
var minOffsetMs: Long = BufferConfigPropUnsetInt.toLong() var minOffsetMs: Long = BufferConfigPropUnsetInt.toLong()
var targetOffsetMs: Long = BufferConfigPropUnsetInt.toLong() var targetOffsetMs: Long = BufferConfigPropUnsetInt.toLong()
override fun equals(other: Any?): Boolean {
if (other == null || other !is Live) return false
return (
maxPlaybackSpeed == other.maxPlaybackSpeed &&
minPlaybackSpeed == other.minPlaybackSpeed &&
maxOffsetMs == other.maxOffsetMs &&
minOffsetMs == other.minOffsetMs &&
targetOffsetMs == other.targetOffsetMs
)
}
companion object { companion object {
private val PROP_BUFFER_CONFIG_LIVE_MAX_PLAYBACK_SPEED = "maxPlaybackSpeed" private const val PROP_BUFFER_CONFIG_LIVE_MAX_PLAYBACK_SPEED = "maxPlaybackSpeed"
private val PROP_BUFFER_CONFIG_LIVE_MIN_PLAYBACK_SPEED = "minPlaybackSpeed" private const val PROP_BUFFER_CONFIG_LIVE_MIN_PLAYBACK_SPEED = "minPlaybackSpeed"
private val PROP_BUFFER_CONFIG_LIVE_MAX_OFFSET_MS = "maxOffsetMs" private const val PROP_BUFFER_CONFIG_LIVE_MAX_OFFSET_MS = "maxOffsetMs"
private val PROP_BUFFER_CONFIG_LIVE_MIN_OFFSET_MS = "minOffsetMs" private const val PROP_BUFFER_CONFIG_LIVE_MIN_OFFSET_MS = "minOffsetMs"
private val PROP_BUFFER_CONFIG_LIVE_TARGET_OFFSET_MS = "targetOffsetMs" private const val PROP_BUFFER_CONFIG_LIVE_TARGET_OFFSET_MS = "targetOffsetMs"
@JvmStatic @JvmStatic
fun parse(src: ReadableMap?): Live { fun parse(src: ReadableMap?): Live {
@ -54,16 +82,16 @@ class BufferConfig {
val BufferConfigPropUnsetInt = -1 val BufferConfigPropUnsetInt = -1
val BufferConfigPropUnsetDouble = -1.0 val BufferConfigPropUnsetDouble = -1.0
private val PROP_BUFFER_CONFIG_CACHE_SIZE = "cacheSizeMB" private const val PROP_BUFFER_CONFIG_CACHE_SIZE = "cacheSizeMB"
private val PROP_BUFFER_CONFIG_MIN_BUFFER_MS = "minBufferMs" private const val PROP_BUFFER_CONFIG_MIN_BUFFER_MS = "minBufferMs"
private val PROP_BUFFER_CONFIG_MAX_BUFFER_MS = "maxBufferMs" private const val PROP_BUFFER_CONFIG_MAX_BUFFER_MS = "maxBufferMs"
private val PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS = "bufferForPlaybackMs" private const val PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_MS = "bufferForPlaybackMs"
private val PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = "bufferForPlaybackAfterRebufferMs" private const val PROP_BUFFER_CONFIG_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS = "bufferForPlaybackAfterRebufferMs"
private val PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT = "maxHeapAllocationPercent" private const val PROP_BUFFER_CONFIG_MAX_HEAP_ALLOCATION_PERCENT = "maxHeapAllocationPercent"
private val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent" private const val PROP_BUFFER_CONFIG_MIN_BACK_BUFFER_MEMORY_RESERVE_PERCENT = "minBackBufferMemoryReservePercent"
private val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent" private const val PROP_BUFFER_CONFIG_MIN_BUFFER_MEMORY_RESERVE_PERCENT = "minBufferMemoryReservePercent"
private val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs" private const val PROP_BUFFER_CONFIG_BACK_BUFFER_DURATION_MS = "backBufferDurationMs"
private val PROP_BUFFER_CONFIG_LIVE = "live" private const val PROP_BUFFER_CONFIG_LIVE = "live"
@JvmStatic @JvmStatic
fun parse(src: ReadableMap?): BufferConfig { fun parse(src: ReadableMap?): BufferConfig {

View File

@ -30,6 +30,12 @@ class Source {
/** Parsed value of source to playback */ /** Parsed value of source to playback */
var uri: Uri? = null var uri: Uri? = null
/** True if source is a local JS asset */
var isLocalAssetFile: Boolean = false
/** True if source is a local file asset://, ... */
var isAsset: Boolean = false
/** Start position of playback used to resume playback */ /** Start position of playback used to resume playback */
var startPositionMs: Int = -1 var startPositionMs: Int = -1
@ -74,6 +80,11 @@ class Source {
*/ */
var adsProps: AdsProps? = null var adsProps: AdsProps? = null
/*
* buffering configuration
*/
var bufferConfig = BufferConfig()
/** /**
* The list of sideLoaded text tracks * The list of sideLoaded text tracks
*/ */
@ -95,7 +106,10 @@ class Source {
cmcdProps == other.cmcdProps && cmcdProps == other.cmcdProps &&
sideLoadedTextTracks == other.sideLoadedTextTracks && sideLoadedTextTracks == other.sideLoadedTextTracks &&
adsProps == other.adsProps && adsProps == other.adsProps &&
minLoadRetryCount == other.minLoadRetryCount minLoadRetryCount == other.minLoadRetryCount &&
isLocalAssetFile == other.isLocalAssetFile &&
isAsset == other.isAsset &&
bufferConfig == other.bufferConfig
) )
} }
@ -151,6 +165,8 @@ class Source {
companion object { companion object {
private const val TAG = "Source" private const val TAG = "Source"
private const val PROP_SRC_URI = "uri" private const val PROP_SRC_URI = "uri"
private const val PROP_SRC_IS_LOCAL_ASSET_FILE = "isLocalAssetFile"
private const val PROP_SRC_IS_ASSET = "isAsset"
private const val PROP_SRC_START_POSITION = "startPosition" private const val PROP_SRC_START_POSITION = "startPosition"
private const val PROP_SRC_CROP_START = "cropStart" private const val PROP_SRC_CROP_START = "cropStart"
private const val PROP_SRC_CROP_END = "cropEnd" private const val PROP_SRC_CROP_END = "cropEnd"
@ -164,6 +180,7 @@ class Source {
private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation" private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation"
private const val PROP_SRC_TEXT_TRACKS = "textTracks" private const val PROP_SRC_TEXT_TRACKS = "textTracks"
private const val PROP_SRC_MIN_LOAD_RETRY_COUNT = "minLoadRetryCount" private const val PROP_SRC_MIN_LOAD_RETRY_COUNT = "minLoadRetryCount"
private const val PROP_SRC_BUFFER_CONFIG = "bufferConfig"
@SuppressLint("DiscouragedApi") @SuppressLint("DiscouragedApi")
private fun getUriFromAssetId(context: Context, uriString: String): Uri? { private fun getUriFromAssetId(context: Context, uriString: String): Uri? {
@ -216,6 +233,8 @@ class Source {
} }
source.uriString = uriString source.uriString = uriString
source.uri = uri source.uri = uri
source.isLocalAssetFile = safeGetBool(src, PROP_SRC_IS_LOCAL_ASSET_FILE, false)
source.isAsset = safeGetBool(src, PROP_SRC_IS_ASSET, false)
source.startPositionMs = safeGetInt(src, PROP_SRC_START_POSITION, -1) source.startPositionMs = safeGetInt(src, PROP_SRC_START_POSITION, -1)
source.cropStartMs = safeGetInt(src, PROP_SRC_CROP_START, -1) source.cropStartMs = safeGetInt(src, PROP_SRC_CROP_START, -1)
source.cropEndMs = safeGetInt(src, PROP_SRC_CROP_END, -1) source.cropEndMs = safeGetInt(src, PROP_SRC_CROP_END, -1)
@ -229,6 +248,8 @@ class Source {
source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true) source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true)
source.sideLoadedTextTracks = SideLoadedTextTrackList.parse(safeGetArray(src, PROP_SRC_TEXT_TRACKS)) source.sideLoadedTextTracks = SideLoadedTextTrackList.parse(safeGetArray(src, PROP_SRC_TEXT_TRACKS))
source.minLoadRetryCount = safeGetInt(src, PROP_SRC_MIN_LOAD_RETRY_COUNT, 3) source.minLoadRetryCount = safeGetInt(src, PROP_SRC_MIN_LOAD_RETRY_COUNT, 3)
source.bufferConfig = BufferConfig.parse(safeGetMap(src, PROP_SRC_BUFFER_CONFIG))
val propSrcHeadersArray = safeGetArray(src, PROP_SRC_HEADERS) val propSrcHeadersArray = safeGetArray(src, PROP_SRC_HEADERS)
if (propSrcHeadersArray != null) { if (propSrcHeadersArray != null) {
if (propSrcHeadersArray.size() > 0) { if (propSrcHeadersArray.size() > 0) {

View File

@ -22,6 +22,7 @@ enum class EventTypes(val eventName: String) {
EVENT_BANDWIDTH("onVideoBandwidthUpdate"), EVENT_BANDWIDTH("onVideoBandwidthUpdate"),
EVENT_CONTROLS_VISIBILITY_CHANGE("onControlsVisibilityChange"), EVENT_CONTROLS_VISIBILITY_CHANGE("onControlsVisibilityChange"),
EVENT_SEEK("onVideoSeek"), EVENT_SEEK("onVideoSeek"),
EVENT_SEEK_COMPLETE("onVideoSeekComplete"),
EVENT_END("onVideoEnd"), EVENT_END("onVideoEnd"),
EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"), EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"),
EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"), EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"),
@ -71,6 +72,7 @@ class VideoEventEmitter {
lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String?) -> Unit lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String?) -> Unit
lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit
lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit
lateinit var onVideoSeekComplete: (currentPosition: Long) -> Unit
lateinit var onVideoEnd: () -> Unit lateinit var onVideoEnd: () -> Unit
lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit
lateinit var onVideoFullscreenPlayerDidPresent: () -> Unit lateinit var onVideoFullscreenPlayerDidPresent: () -> Unit
@ -174,6 +176,11 @@ class VideoEventEmitter {
putDouble("seekTime", seekTime / 1000.0) putDouble("seekTime", seekTime / 1000.0)
} }
} }
onVideoSeekComplete = { currentPosition ->
event.dispatch(EventTypes.EVENT_SEEK_COMPLETE) {
putDouble("currentTime", currentPosition / 1000.0)
}
}
onVideoEnd = { onVideoEnd = {
event.dispatch(EventTypes.EVENT_END) event.dispatch(EventTypes.EVENT_END)
} }

View File

@ -23,6 +23,7 @@ import android.os.IBinder;
import android.os.Looper; import android.os.Looper;
import android.os.Message; import android.os.Message;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.accessibility.CaptioningManager; import android.view.accessibility.CaptioningManager;
import android.widget.FrameLayout; import android.widget.FrameLayout;
@ -206,7 +207,6 @@ public class ReactExoplayerView extends FrameLayout implements
private float rate = 1f; private float rate = 1f;
private AudioOutput audioOutput = AudioOutput.SPEAKER; private AudioOutput audioOutput = AudioOutput.SPEAKER;
private float audioVolume = 1f; private float audioVolume = 1f;
private BufferConfig bufferConfig = new BufferConfig();
private int maxBitRate = 0; private int maxBitRate = 0;
private boolean hasDrmFailed = false; private boolean hasDrmFailed = false;
private boolean isUsingContentResolution = false; private boolean isUsingContentResolution = false;
@ -222,6 +222,7 @@ public class ReactExoplayerView extends FrameLayout implements
*/ */
private boolean isSeeking = false; private boolean isSeeking = false;
private long seekPosition = -1; private long seekPosition = -1;
private boolean isSeekInProgress = false;
// Props from React // Props from React
private Source source = new Source(); private Source source = new Source();
@ -301,6 +302,16 @@ public class ReactExoplayerView extends FrameLayout implements
} }
}; };
private void handleSeekCompletion() {
if (player != null && player.getPlaybackState() == Player.STATE_READY && isSeekInProgress) {
Log.d("ReactExoplayerView", "handleSeekCompletion: currentPosition=" + player.getCurrentPosition());
eventEmitter.onVideoSeekComplete.invoke(player.getCurrentPosition());
isSeeking = false;
seekPosition = -1;
isSeekInProgress = false;
}
}
public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) { public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) {
Timeline.Window window = new Timeline.Window(); Timeline.Window window = new Timeline.Window();
if(!player.getCurrentTimeline().isEmpty()) { if(!player.getCurrentTimeline().isEmpty()) {
@ -519,12 +530,21 @@ public class ReactExoplayerView extends FrameLayout implements
builder.setSingleChoiceItems(speedOptions, selectedSpeedIndex, (dialog, which) -> { builder.setSingleChoiceItems(speedOptions, selectedSpeedIndex, (dialog, which) -> {
selectedSpeedIndex = which; selectedSpeedIndex = which;
float speed = switch (which) { float speed;
case 0 -> 0.5f; switch (which) {
case 2 -> 1.5f; case 0:
case 3 -> 2.0f; speed = 0.5f;
default -> 1.0f; break;
}; case 1:
speed = 1.0f;
break;
case 2:
speed = 1.5f;
break;
default:
speed = 1.0f;
break;
}
setRateModifier(speed); setRateModifier(speed);
}); });
builder.show(); builder.show();
@ -691,7 +711,7 @@ public class ReactExoplayerView extends FrameLayout implements
runtime = Runtime.getRuntime(); runtime = Runtime.getRuntime();
ActivityManager activityManager = (ActivityManager) themedReactContext.getSystemService(ThemedReactContext.ACTIVITY_SERVICE); ActivityManager activityManager = (ActivityManager) themedReactContext.getSystemService(ThemedReactContext.ACTIVITY_SERVICE);
double maxHeap = config.getMaxHeapAllocationPercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble() double maxHeap = config.getMaxHeapAllocationPercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble()
? bufferConfig.getMaxHeapAllocationPercent() ? config.getMaxHeapAllocationPercent()
: DEFAULT_MAX_HEAP_ALLOCATION_PERCENT; : DEFAULT_MAX_HEAP_ALLOCATION_PERCENT;
availableHeapInBytes = (int) Math.floor(activityManager.getMemoryClass() * maxHeap * 1024 * 1024); availableHeapInBytes = (int) Math.floor(activityManager.getMemoryClass() * maxHeap * 1024 * 1024);
} }
@ -710,8 +730,8 @@ public class ReactExoplayerView extends FrameLayout implements
} }
long usedMemory = runtime.totalMemory() - runtime.freeMemory(); long usedMemory = runtime.totalMemory() - runtime.freeMemory();
long freeMemory = runtime.maxMemory() - usedMemory; long freeMemory = runtime.maxMemory() - usedMemory;
double minBufferMemoryReservePercent = bufferConfig.getMinBufferMemoryReservePercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble() double minBufferMemoryReservePercent = source.getBufferConfig().getMinBufferMemoryReservePercent() != BufferConfig.Companion.getBufferConfigPropUnsetDouble()
? bufferConfig.getMinBufferMemoryReservePercent() ? source.getBufferConfig().getMinBufferMemoryReservePercent()
: ReactExoplayerView.DEFAULT_MIN_BUFFER_MEMORY_RESERVE; : ReactExoplayerView.DEFAULT_MIN_BUFFER_MEMORY_RESERVE;
long reserveMemory = (long) minBufferMemoryReservePercent * runtime.maxMemory(); long reserveMemory = (long) minBufferMemoryReservePercent * runtime.maxMemory();
long bufferedMs = bufferedDurationUs / (long) 1000; long bufferedMs = bufferedDurationUs / (long) 1000;
@ -743,10 +763,20 @@ public class ReactExoplayerView extends FrameLayout implements
if (runningSource.getUri() == null) { if (runningSource.getUri() == null) {
return; return;
} }
if (player == null) { if (player == null) {
// Initialize core configuration and listeners // Initialize core configuration and listeners
initializePlayerCore(self); initializePlayerCore(self);
} }
if (!source.isLocalAssetFile() && !source.isAsset() && source.getBufferConfig().getCacheSize() > 0) {
RNVSimpleCache.INSTANCE.setSimpleCache(
this.getContext(),
source.getBufferConfig().getCacheSize()
);
useCache = true;
} else {
useCache = false;
}
if (playerNeedsSource) { if (playerNeedsSource) {
// Will force display of shutter view if needed // Will force display of shutter view if needed
exoPlayerView.updateShutterViewVisibility(); exoPlayerView.updateShutterViewVisibility();
@ -813,7 +843,7 @@ public class ReactExoplayerView extends FrameLayout implements
DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE); DefaultAllocator allocator = new DefaultAllocator(true, C.DEFAULT_BUFFER_SEGMENT_SIZE);
RNVLoadControl loadControl = new RNVLoadControl( RNVLoadControl loadControl = new RNVLoadControl(
allocator, allocator,
bufferConfig source.getBufferConfig()
); );
DefaultRenderersFactory renderersFactory = DefaultRenderersFactory renderersFactory =
new DefaultRenderersFactory(getContext()) new DefaultRenderersFactory(getContext())
@ -834,6 +864,7 @@ public class ReactExoplayerView extends FrameLayout implements
.setLoadControl(loadControl) .setLoadControl(loadControl)
.setMediaSourceFactory(mediaSourceFactory) .setMediaSourceFactory(mediaSourceFactory)
.build(); .build();
player.addListener(self);
ReactNativeVideoManager.Companion.getInstance().onInstanceCreated(instanceId, player); ReactNativeVideoManager.Companion.getInstance().onInstanceCreated(instanceId, player);
refreshDebugState(); refreshDebugState();
player.addListener(self); player.addListener(self);
@ -1119,7 +1150,7 @@ public class ReactExoplayerView extends FrameLayout implements
} }
} }
MediaItem.LiveConfiguration.Builder liveConfiguration = ConfigurationUtils.getLiveConfiguration(bufferConfig); MediaItem.LiveConfiguration.Builder liveConfiguration = ConfigurationUtils.getLiveConfiguration(source.getBufferConfig());
mediaItemBuilder.setLiveConfiguration(liveConfiguration.build()); mediaItemBuilder.setLiveConfiguration(liveConfiguration.build());
MediaSource.Factory mediaSourceFactory; MediaSource.Factory mediaSourceFactory;
@ -1177,7 +1208,7 @@ public class ReactExoplayerView extends FrameLayout implements
DataSource.Factory assetDataSourceFactory = DataSourceUtil.buildAssetDataSourceFactory(themedReactContext, uri); DataSource.Factory assetDataSourceFactory = DataSourceUtil.buildAssetDataSourceFactory(themedReactContext, uri);
mediaSourceFactory = new ProgressiveMediaSource.Factory(assetDataSourceFactory); mediaSourceFactory = new ProgressiveMediaSource.Factory(assetDataSourceFactory);
} catch (Exception e) { } catch (Exception e) {
throw new IllegalStateException("cannot open input file" + uri); throw new IllegalStateException("cannot open input file:" + uri);
} }
} else if ("file".equals(uri.getScheme()) || } else if ("file".equals(uri.getScheme()) ||
!useCache) { !useCache) {
@ -1442,6 +1473,7 @@ public class ReactExoplayerView extends FrameLayout implements
if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) { if (events.contains(Player.EVENT_PLAYBACK_STATE_CHANGED) || events.contains(Player.EVENT_PLAY_WHEN_READY_CHANGED)) {
int playbackState = player.getPlaybackState(); int playbackState = player.getPlaybackState();
boolean playWhenReady = player.getPlayWhenReady(); boolean playWhenReady = player.getPlayWhenReady();
Log.d("ReactExoplayerView", "onEvents: playbackState=" + playbackState + ", playWhenReady=" + playWhenReady);
String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState="; String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState=";
eventEmitter.onPlaybackRateChange.invoke(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f); eventEmitter.onPlaybackRateChange.invoke(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f);
switch (playbackState) { switch (playbackState) {
@ -1475,6 +1507,10 @@ public class ReactExoplayerView extends FrameLayout implements
playerControlView.show(); playerControlView.show();
} }
setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback); setKeepScreenOn(preventsDisplaySleepDuringVideoPlayback);
Log.d("ReactExoplayerView", "Player STATE_READY: currentPosition=" + player.getCurrentPosition());
if (isSeekInProgress) {
handleSeekCompletion();
}
break; break;
case Player.STATE_ENDED: case Player.STATE_ENDED:
text += "ended"; text += "ended";
@ -1739,6 +1775,7 @@ public class ReactExoplayerView extends FrameLayout implements
@Override @Override
public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) { public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) {
Log.d("ReactExoplayerView", "onPositionDiscontinuity: reason=" + reason + ", oldPosition=" + oldPosition.positionMs + ", newPosition=" + newPosition.positionMs);
if (reason == Player.DISCONTINUITY_REASON_SEEK) { if (reason == Player.DISCONTINUITY_REASON_SEEK) {
isSeeking = true; isSeeking = true;
seekPosition = newPosition.positionMs; seekPosition = newPosition.positionMs;
@ -2250,6 +2287,10 @@ public class ReactExoplayerView extends FrameLayout implements
public void seekTo(long positionMs) { public void seekTo(long positionMs) {
if (player != null) { if (player != null) {
Log.d("ReactExoplayerView", "seekTo: positionMs=" + positionMs);
isSeekInProgress = true;
isSeeking = true;
seekPosition = positionMs;
player.seekTo(positionMs); player.seekTo(positionMs);
} }
} }
@ -2368,21 +2409,6 @@ public class ReactExoplayerView extends FrameLayout implements
exoPlayerView.setHideShutterView(hideShutterView); exoPlayerView.setHideShutterView(hideShutterView);
} }
public void setBufferConfig(BufferConfig config) {
bufferConfig = config;
if (bufferConfig.getCacheSize() > 0) {
RNVSimpleCache.INSTANCE.setSimpleCache(
this.getContext(),
bufferConfig.getCacheSize()
);
useCache = true;
} else {
useCache = false;
}
releasePlayer();
initializePlayer();
}
@Override @Override
public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) { public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
DebugLog.d("DRM Info", "onDrmKeysLoaded"); DebugLog.d("DRM Info", "onDrmKeysLoaded");

View File

@ -2,7 +2,6 @@ package com.brentvatne.exoplayer
import android.graphics.Color import android.graphics.Color
import android.util.Log import android.util.Log
import com.brentvatne.common.api.BufferConfig
import com.brentvatne.common.api.BufferingStrategy import com.brentvatne.common.api.BufferingStrategy
import com.brentvatne.common.api.ControlsConfig import com.brentvatne.common.api.ControlsConfig
import com.brentvatne.common.api.ResizeMode import com.brentvatne.common.api.ResizeMode
@ -36,7 +35,6 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View
private const val PROP_MUTED = "muted" private const val PROP_MUTED = "muted"
private const val PROP_AUDIO_OUTPUT = "audioOutput" private const val PROP_AUDIO_OUTPUT = "audioOutput"
private const val PROP_VOLUME = "volume" private const val PROP_VOLUME = "volume"
private const val PROP_BUFFER_CONFIG = "bufferConfig"
private const val PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK = private const val PROP_PREVENTS_DISPLAY_SLEEP_DURING_VIDEO_PLAYBACK =
"preventsDisplaySleepDuringVideoPlayback" "preventsDisplaySleepDuringVideoPlayback"
private const val PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval" private const val PROP_PROGRESS_UPDATE_INTERVAL = "progressUpdateInterval"
@ -242,12 +240,6 @@ class ReactExoplayerViewManager(private val config: ReactExoplayerConfig) : View
videoView.setShutterColor(color) videoView.setShutterColor(color)
} }
@ReactProp(name = PROP_BUFFER_CONFIG)
fun setBufferConfig(videoView: ReactExoplayerView, bufferConfig: ReadableMap?) {
val config = BufferConfig.parse(bufferConfig)
videoView.setBufferConfig(config)
}
@ReactProp(name = PROP_SHOW_NOTIFICATION_CONTROLS) @ReactProp(name = PROP_SHOW_NOTIFICATION_CONTROLS)
fun setShowNotificationControls(videoView: ReactExoplayerView, showNotificationControls: Boolean) { fun setShowNotificationControls(videoView: ReactExoplayerView, showNotificationControls: Boolean) {
videoView.setShowNotificationControls(showNotificationControls) videoView.setShowNotificationControls(showNotificationControls)

View File

@ -52,6 +52,9 @@ A Boolean value that indicates whether the player should automatically delay pla
### `bufferConfig` ### `bufferConfig`
> [!WARNING]
> Deprecated, use source.bufferConfig instead
<PlatformsList types={['Android']} /> <PlatformsList types={['Android']} />
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below. Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
@ -907,6 +910,56 @@ source={{
}} }}
``` ```
### `bufferConfig`
<PlatformsList types={['Android']} />
Adjust the buffer settings. This prop takes an object with one or more of the properties listed below.
| Property | Type | Description |
| --------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| minBufferMs | number | The default minimum duration of media that the player will attempt to ensure is buffered at all times, in milliseconds. |
| maxBufferMs | number | The default maximum duration of media that the player will attempt to buffer, in milliseconds. |
| bufferForPlaybackMs | number | The default duration of media that must be buffered for playback to start or resume following a user action such as a seek, in milliseconds. |
| bufferForPlaybackAfterRebufferMs | number | The default duration of media that must be buffered for playback to resume after a rebuffer, in milliseconds. A rebuffer is defined to be caused by buffer depletion rather than a user action. |
| backBufferDurationMs | number | The number of milliseconds of buffer to keep before the current position. This allows rewinding without rebuffering within that duration. |
| maxHeapAllocationPercent | number | The percentage of available heap that the video can use to buffer, between 0 and 1 |
| minBackBufferMemoryReservePercent | number | The percentage of available app memory at which during startup the back buffer will be disabled, between 0 and 1 |
| minBufferMemoryReservePercent | number | The percentage of available app memory to keep in reserve that prevents buffer from using it, between 0 and 1 |
| cacheSizeMB | number | Cache size in MB, enabling this to prevent new src requests and save bandwidth while repeating videos, or 0 to disable. Android only. |
| live | object | Object containing another config set for live playback configuration, see next table |
Description of live object:
| Property | Type | Description |
| --------------------------------- | ------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| maxPlaybackSpeed | number | The maximum playback speed the player can use to catch up when trying to reach the target live offset. |
| minPlaybackSpeed | number | The minimum playback speed the player can use to fall back when trying to reach the target live offset. |
| maxOffsetMs | number | The maximum allowed live offset. Even when adjusting the offset to current network conditions, the player will not attempt to get above this offset during playback. |
| minOffsetMs | number | The minimum allowed live offset. Even when adjusting the offset to current network conditions, the player will not attempt to get below this offset during playback. |
| targetOffsetMs | number | The target live offset. The player will attempt to get close to this live offset during playback if possible. |
For android, more informations about live configuration can be find [here](https://developer.android.com/media/media3/exoplayer/live-streaming?hl=en)
Example with default values:
```javascript
bufferConfig={{
minBufferMs: 15000,
maxBufferMs: 50000,
bufferForPlaybackMs: 2500,
bufferForPlaybackAfterRebufferMs: 5000,
backBufferDurationMs: 120000,
cacheSizeMB: 0,
live: {
targetOffsetMs: 500,
},
}}
```
Please note that the Android cache is a global cache that is shared among all components; individual components can still opt out of caching behavior by setting cacheSizeMB to 0, but multiple components with a positive cacheSizeMB will be sharing the same one, and the cache size will always be the first value set; it will not change during the app's lifecycle.
#### `minLoadRetryCount` #### `minLoadRetryCount`
<PlatformsList types={['Android']} /> <PlatformsList types={['Android']} />

View File

@ -240,7 +240,7 @@ const BasicExample = () => {
}; };
useEffect(() => { useEffect(() => {
videoRef.current?.setSource(currentSrc); videoRef.current?.setSource({...currentSrc, bufferConfig: _bufferConfig });
}, [currentSrc]); }, [currentSrc]);
return ( return (
@ -284,7 +284,6 @@ const BasicExample = () => {
selectedAudioTrack={selectedAudioTrack} selectedAudioTrack={selectedAudioTrack}
selectedVideoTrack={selectedVideoTrack} selectedVideoTrack={selectedVideoTrack}
playInBackground={false} playInBackground={false}
bufferConfig={_bufferConfig}
preventsDisplaySleepDuringVideoPlayback={true} preventsDisplaySleepDuringVideoPlayback={true}
renderLoader={_renderLoader} renderLoader={_renderLoader}
onPlaybackRateChange={onPlaybackRateChange} onPlaybackRateChange={onPlaybackRateChange}

View File

@ -0,0 +1,52 @@
{
"name": "VideoPlayer",
"version": "1.0.0",
"private": true,
"scripts": {
"web": "expo start --web",
"android": "expo run:android",
"ios": "expo run:ios",
"windows": "react-native run-windows",
"start": "expo start",
"test": "jest",
"lint": "eslint .",
"pod-install": "cd ios && pod install && cd ..",
"pod-install:newarch": "cd ios && RCT_NEW_ARCH_ENABLED=1 bundle exec pod install && cd .."
},
"dependencies": {
"@expo/metro-runtime": "~3.2.1",
"@react-native-picker/picker": "2.7.5",
"expo": "^51.0.32",
"expo-asset": "~10.0.10",
"expo-image": "^1.12.15",
"expo-navigation-bar": "~3.0.7",
"react": "18.2.0",
"react-native": "0.74.5",
"react-dom": "18.2.0",
"react-native-web": "~0.19.10",
"react-native-windows": "0.74.19"
},
"devDependencies": {
"@babel/core": "^7.24.0",
"@babel/preset-env": "^7.22.10",
"@babel/runtime": "^7.22.10",
"@react-native/babel-preset": "0.74.85",
"@react-native/eslint-config": "0.74.85",
"@react-native/metro-config": "0.74.85",
"@react-native/typescript-config": "0.74.85",
"@types/react": "~18.2.79",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"babel-plugin-module-resolver": "5.0.0",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "^2.8.8",
"typescript": "~5.3.3"
},
"resolutions": {
"@types/react": "^18.0.24"
},
"engines": {
"node": ">=18"
}
}

View File

@ -0,0 +1,4 @@
import {registerRootComponent} from 'expo';
import VideoPlayer from './VideoPlayer';
registerRootComponent(VideoPlayer);

9711
examples/basic/yarn.lock Normal file

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,7 @@ import com.facebook.react.ReactPackage
import com.facebook.react.ReactHost import com.facebook.react.ReactHost
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load
import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.react.defaults.DefaultReactNativeHost
import com.facebook.react.soloader.OpenSourceMergedSoMapping
import com.facebook.soloader.SoLoader import com.facebook.soloader.SoLoader
import expo.modules.ApplicationLifecycleDispatcher import expo.modules.ApplicationLifecycleDispatcher
@ -42,7 +43,7 @@ class MainApplication : Application(), ReactApplication {
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
SoLoader.init(this, false) SoLoader.init(this, OpenSourceMergedSoMapping)
if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
// If you opted-in for the New Architecture, we load the native entry point for this app. // If you opted-in for the New Architecture, we load the native entry point for this app.
load() load()

View File

@ -2,11 +2,11 @@
buildscript { buildscript {
ext { ext {
buildToolsVersion = findProperty('android.buildToolsVersion') ?: '34.0.0' buildToolsVersion = findProperty('android.buildToolsVersion') ?: '35.0.0'
minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '23') minSdkVersion = Integer.parseInt(findProperty('android.minSdkVersion') ?: '24')
compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '34') compileSdkVersion = Integer.parseInt(findProperty('android.compileSdkVersion') ?: '35')
targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '34') targetSdkVersion = Integer.parseInt(findProperty('android.targetSdkVersion') ?: '35')
kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.23' kotlinVersion = findProperty('android.kotlinVersion') ?: '1.9.24'
ndkVersion = "26.1.10909125" ndkVersion = "26.1.10909125"
} }

View File

@ -22,9 +22,6 @@ org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# https://developer.android.com/topic/libraries/support-library/androidx-rn # https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Enable AAPT2 PNG crunching # Enable AAPT2 PNG crunching
android.enablePngCrunchInReleaseBuilds=true android.enablePngCrunchInReleaseBuilds=true
@ -38,7 +35,7 @@ reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# your application. You should enable this flag either if you want # your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that # to write custom TurboModules/Fabric components OR use libraries that
# are providing them. # are providing them.
newArchEnabled=false newArchEnabled=true
# Use this property to enable or disable the Hermes JS engine. # Use this property to enable or disable the Hermes JS engine.
# If set to false, you will be using JSC instead. # If set to false, you will be using JSC instead.

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-all.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

View File

@ -8,6 +8,7 @@ pluginManagement {
if(reactNativeMinor == 74 && reactNativePatch <= 3){ if(reactNativeMinor == 74 && reactNativePatch <= 3){
includeBuild("react-settings-plugin") includeBuild("react-settings-plugin")
} }
includeBuild("../node_modules/@react-native/gradle-plugin")
} }
plugins { id("com.facebook.react.settings") } plugins { id("com.facebook.react.settings") }

View File

@ -11,8 +11,8 @@
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; }; 3E461D99554A48A4959DE609 /* SplashScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */; };
69D28F37B56772B7A9D5E544 /* libPods-ExpoExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = C65020CA55EC90CEE9A23ED2 /* libPods-ExpoExample.a */; };
6E3E1907139F4681BB29BA3F /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD8985E3A84FEF8F310E21 /* noop-file.swift */; }; 6E3E1907139F4681BB29BA3F /* noop-file.swift in Sources */ = {isa = PBXBuildFile; fileRef = E1CD8985E3A84FEF8F310E21 /* noop-file.swift */; };
96905EF65AED1B983A6B3ABC /* libPods-ExpoExample.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 58EEBF8E8E6FB1BC6CAF49B5 /* libPods-ExpoExample.a */; };
B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; }; B18059E884C0ABDD17F3DC3D /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */; };
BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; }; BB2F792D24A3F905000567C9 /* Expo.plist in Resources */ = {isa = PBXBuildFile; fileRef = BB2F792C24A3F905000567C9 /* Expo.plist */; };
F6DD9B61853ED7F5FE2C32F9 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3BCFB4767DA89C6653566DA4 /* PrivacyInfo.xcprivacy */; }; F6DD9B61853ED7F5FE2C32F9 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 3BCFB4767DA89C6653566DA4 /* PrivacyInfo.xcprivacy */; };
@ -26,12 +26,12 @@
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ExpoExample/Info.plist; sourceTree = "<group>"; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = ExpoExample/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ExpoExample/main.m; sourceTree = "<group>"; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = ExpoExample/main.m; sourceTree = "<group>"; };
3BCFB4767DA89C6653566DA4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = ExpoExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; }; 3BCFB4767DA89C6653566DA4 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = ExpoExample/PrivacyInfo.xcprivacy; sourceTree = "<group>"; };
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-ExpoExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ExpoExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 5762883CF0477CB8DEB074D2 /* Pods-ExpoExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExpoExample.debug.xcconfig"; path = "Target Support Files/Pods-ExpoExample/Pods-ExpoExample.debug.xcconfig"; sourceTree = "<group>"; };
6C2E3173556A471DD304B334 /* Pods-ExpoExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExpoExample.debug.xcconfig"; path = "Target Support Files/Pods-ExpoExample/Pods-ExpoExample.debug.xcconfig"; sourceTree = "<group>"; }; 9C0AF52D744330C1CAD2989E /* Pods-ExpoExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExpoExample.release.xcconfig"; path = "Target Support Files/Pods-ExpoExample/Pods-ExpoExample.release.xcconfig"; sourceTree = "<group>"; };
7A4D352CD337FB3A3BF06240 /* Pods-ExpoExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExpoExample.release.xcconfig"; path = "Target Support Files/Pods-ExpoExample/Pods-ExpoExample.release.xcconfig"; sourceTree = "<group>"; };
AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = ExpoExample/SplashScreen.storyboard; sourceTree = "<group>"; }; AA286B85B6C04FC6940260E9 /* SplashScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = SplashScreen.storyboard; path = ExpoExample/SplashScreen.storyboard; sourceTree = "<group>"; };
B7DF2D7F8A384D51B801CEE7 /* ExpoExample-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "ExpoExample-Bridging-Header.h"; path = "ExpoExample/ExpoExample-Bridging-Header.h"; sourceTree = "<group>"; }; B7DF2D7F8A384D51B801CEE7 /* ExpoExample-Bridging-Header.h */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.c.h; name = "ExpoExample-Bridging-Header.h"; path = "ExpoExample/ExpoExample-Bridging-Header.h"; sourceTree = "<group>"; };
BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; }; BB2F792C24A3F905000567C9 /* Expo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Expo.plist; sourceTree = "<group>"; };
C65020CA55EC90CEE9A23ED2 /* libPods-ExpoExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-ExpoExample.a"; sourceTree = BUILT_PRODUCTS_DIR; };
E1CD8985E3A84FEF8F310E21 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "ExpoExample/noop-file.swift"; sourceTree = "<group>"; }; E1CD8985E3A84FEF8F310E21 /* noop-file.swift */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 4; includeInIndex = 0; lastKnownFileType = sourcecode.swift; name = "noop-file.swift"; path = "ExpoExample/noop-file.swift"; sourceTree = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-ExpoExample/ExpoModulesProvider.swift"; sourceTree = "<group>"; }; FAC715A2D49A985799AEE119 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-ExpoExample/ExpoModulesProvider.swift"; sourceTree = "<group>"; };
@ -42,7 +42,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
96905EF65AED1B983A6B3ABC /* libPods-ExpoExample.a in Frameworks */, 69D28F37B56772B7A9D5E544 /* libPods-ExpoExample.a in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -70,7 +70,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */, ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
58EEBF8E8E6FB1BC6CAF49B5 /* libPods-ExpoExample.a */, C65020CA55EC90CEE9A23ED2 /* libPods-ExpoExample.a */,
); );
name = Frameworks; name = Frameworks;
sourceTree = "<group>"; sourceTree = "<group>";
@ -125,8 +125,8 @@
D65327D7A22EEC0BE12398D9 /* Pods */ = { D65327D7A22EEC0BE12398D9 /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
6C2E3173556A471DD304B334 /* Pods-ExpoExample.debug.xcconfig */, 5762883CF0477CB8DEB074D2 /* Pods-ExpoExample.debug.xcconfig */,
7A4D352CD337FB3A3BF06240 /* Pods-ExpoExample.release.xcconfig */, 9C0AF52D744330C1CAD2989E /* Pods-ExpoExample.release.xcconfig */,
); );
path = Pods; path = Pods;
sourceTree = "<group>"; sourceTree = "<group>";
@ -146,14 +146,14 @@
isa = PBXNativeTarget; isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ExpoExample" */; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "ExpoExample" */;
buildPhases = ( buildPhases = (
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */, EBDF7B38F7D33D49CA2B39C6 /* [CP] Check Pods Manifest.lock */,
6E9FB0155D627BF633A3CB08 /* [Expo] Configure project */, 6E9FB0155D627BF633A3CB08 /* [Expo] Configure project */,
13B07F871A680F5B00A75B9A /* Sources */, 13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */, 13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */, 2ECC1AFFBE97E107FF88D15D /* [CP] Embed Pods Frameworks */,
CED90EB9939E56B1E5D48A24 /* [CP] Embed Pods Frameworks */, DC89C28FF1E7E51E27603886 /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
@ -225,26 +225,22 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n"; shellScript = "if [[ -f \"$PODS_ROOT/../.xcode.env\" ]]; then\n source \"$PODS_ROOT/../.xcode.env\"\nfi\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n# The project root by default is one level up from the ios directory\nexport PROJECT_ROOT=\"$PROJECT_DIR\"/..\n\nif [[ \"$CONFIGURATION\" = *Debug* ]]; then\n export SKIP_BUNDLING=1\nfi\nif [[ -z \"$ENTRY_FILE\" ]]; then\n # Set the entry JS file using the bundler's entry resolution.\n export ENTRY_FILE=\"$(\"$NODE_BINARY\" -e \"require('expo/scripts/resolveAppEntry')\" \"$PROJECT_ROOT\" ios absolute | tail -n 1)\"\nfi\n\nif [[ -z \"$CLI_PATH\" ]]; then\n # Use Expo CLI\n export CLI_PATH=\"$(\"$NODE_BINARY\" --print \"require.resolve('@expo/cli', { paths: [require.resolve('expo/package.json')] })\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n# Source .xcode.env.updates if it exists to allow\n# SKIP_BUNDLING to be unset if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.updates\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.updates\"\nfi\n# Source local changes to allow overrides\n# if needed\nif [[ -f \"$PODS_ROOT/../.xcode.env.local\" ]]; then\n source \"$PODS_ROOT/../.xcode.env.local\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n\n";
}; };
08A4A3CD28434E44B6B9DE2E /* [CP] Check Pods Manifest.lock */ = { 2ECC1AFFBE97E107FF88D15D /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputFileListPaths = (
);
inputPaths = ( inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock", "${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-frameworks.sh",
"${PODS_ROOT}/Manifest.lock", "${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
); );
name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ExpoExample-checkManifestLockResult.txt", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
6E9FB0155D627BF633A3CB08 /* [Expo] Configure project */ = { 6E9FB0155D627BF633A3CB08 /* [Expo] Configure project */ = {
@ -266,7 +262,7 @@
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-ExpoExample/expo-configure-project.sh\"\n"; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-ExpoExample/expo-configure-project.sh\"\n";
}; };
800E24972A6A228C8D4807E9 /* [CP] Copy Pods Resources */ = { DC89C28FF1E7E51E27603886 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
@ -276,36 +272,48 @@
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/RCTI18nStrings.bundle", "${PODS_CONFIGURATION_BUILD_DIR}/RCT-Folly/RCT-Folly_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-Core/React-Core_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/React-cxxreact/React-cxxreact_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/boost/boost_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/glog/glog_privacy.bundle",
); );
name = "[CP] Copy Pods Resources"; name = "[CP] Copy Pods Resources";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCTI18nStrings.bundle", "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RCT-Folly_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-Core_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/React-cxxreact_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/boost_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/glog_privacy.bundle",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-resources.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
CED90EB9939E56B1E5D48A24 /* [CP] Embed Pods Frameworks */ = { EBDF7B38F7D33D49CA2B39C6 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase; isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
); );
inputPaths = ( inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-frameworks.sh", );
"${PODS_XCFRAMEWORKS_BUILD_DIR}/hermes-engine/Pre-built/hermes.framework/hermes", inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
); );
name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/hermes.framework", "$(DERIVED_FILE_DIR)/Pods-ExpoExample-checkManifestLockResult.txt",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-ExpoExample/Pods-ExpoExample-frameworks.sh\"\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
@ -327,7 +335,7 @@
/* Begin XCBuildConfiguration section */ /* Begin XCBuildConfiguration section */
13B07F941A680F5B00A75B9A /* Debug */ = { 13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 6C2E3173556A471DD304B334 /* Pods-ExpoExample.debug.xcconfig */; baseConfigurationReference = 5762883CF0477CB8DEB074D2 /* Pods-ExpoExample.debug.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
@ -339,7 +347,7 @@
"FB_SONARKIT_ENABLED=1", "FB_SONARKIT_ENABLED=1",
); );
INFOPLIST_FILE = ExpoExample/Info.plist; INFOPLIST_FILE = ExpoExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@ -360,14 +368,14 @@
}; };
13B07F951A680F5B00A75B9A /* Release */ = { 13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration; isa = XCBuildConfiguration;
baseConfigurationReference = 7A4D352CD337FB3A3BF06240 /* Pods-ExpoExample.release.xcconfig */; baseConfigurationReference = 9C0AF52D744330C1CAD2989E /* Pods-ExpoExample.release.xcconfig */;
buildSettings = { buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = ExpoExample/ExpoExample.entitlements; CODE_SIGN_ENTITLEMENTS = ExpoExample/ExpoExample.entitlements;
CURRENT_PROJECT_VERSION = 1; CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = ExpoExample/Info.plist; INFOPLIST_FILE = ExpoExample/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.0; MARKETING_VERSION = 1.0;
OTHER_LDFLAGS = ( OTHER_LDFLAGS = (
@ -434,7 +442,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD = ""; LD = "";
LDPLUSPLUS = ""; LDPLUSPLUS = "";
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";
@ -447,6 +455,7 @@
); );
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
USE_HERMES = true; USE_HERMES = true;
}; };
name = Debug; name = Debug;
@ -493,7 +502,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 13.4; IPHONEOS_DEPLOYMENT_TARGET = 15.1;
LD = ""; LD = "";
LDPLUSPLUS = ""; LDPLUSPLUS = "";
LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)"; LD_RUNPATH_SEARCH_PATHS = "/usr/lib/swift $(inherited)";

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
{ {
"expo.jsEngine": "hermes", "expo.jsEngine": "hermes",
"EX_DEV_CLIENT_NETWORK_INSPECTOR": "true" "EX_DEV_CLIENT_NETWORK_INSPECTOR": "true",
"ios.deploymentTarget": "15.1"
} }

View File

@ -7,30 +7,47 @@
"start:tv": "EXPO_TV=1 expo start", "start:tv": "EXPO_TV=1 expo start",
"android:tv": "EXPO_TV=1 expo run:android", "android:tv": "EXPO_TV=1 expo run:android",
"android": "EXPO_TV=0 expo run:android", "android": "EXPO_TV=0 expo run:android",
"release:android": "cd android && EXPO_TV=0 ./gradlew assembleRelease && cd -",
"release:android:tv": "cd android && EXPO_TV=1 ./gradlew assembleRelease && cd -",
"ios:tv": "EXPO_TV=1 expo run:ios", "ios:tv": "EXPO_TV=1 expo run:ios",
"ios": "EXPO_TV=0 expo run:ios", "ios": "EXPO_TV=0 expo run:ios",
"web": "expo start --web", "web": "expo start --web",
"prebuild:tv": "EXPO_TV=1 expo prebuild", "prebuild:tv": "EXPO_TV=1 expo prebuild",
"prebuild": "EXPO_TV=0 expo prebuild", "prebuild": "EXPO_TV=0 expo prebuild",
"update-src": "echo 'Updating src from ../bare/src' && rm -r ./src && cp -r ../bare/src ./src && echo 'Updated src from ../bare/src'" "update-src": "echo 'Updating src from ../bare/src' && rm -r ./src && cp -r ../bare/src ./src && echo 'Updated src from ../bare/src'",
"clean": "rm -rf node_modules && rm -rf android/build/ && rm -rf android/app/build && rm -rf ./lib @@ rm -rf ./android/.gradle && rm -rf ./android/.idea && rm -rf ./.expo"
}, },
"dependencies": { "dependencies": {
"@expo/metro-runtime": "^3.2.3", "@expo/metro-runtime": "~4.0.0",
"@react-native-picker/picker": "2.8.1", "@react-native-picker/picker": "2.9.0",
"expo": "~51.0.39", "expo": "^52.0.7",
"expo-splash-screen": "~0.27.7", "expo-splash-screen": "~0.29.10",
"expo-status-bar": "~1.12.1", "expo-status-bar": "~2.0.0",
"react": "18.2.0", "react": "18.3.1",
"react-dom": "18.2.0", "react-dom": "18.3.1",
"react-native": "npm:react-native-tvos@~0.74.5-0", "react-native": "npm:react-native-tvos@0.76.2-0",
"react-native-web": "^0.19.13" "react-native-web": "^0.19.13"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.24.0", "@babel/core": "^7.25.2",
"@expo/config-plugins": "^8.0.10", "@babel/preset-env": "^7.25.3",
"@babel/runtime": "^7.25.0",
"@react-native-community/cli": "15.0.1",
"@react-native-community/cli-platform-android": "15.0.1",
"@react-native-community/cli-platform-ios": "15.0.1",
"@react-native/babel-preset": "0.76.3",
"@react-native/eslint-config": "0.76.3",
"@react-native/metro-config": "0.76.3",
"@react-native/typescript-config": "0.76.3",
"@types/react": "^18.2.6",
"@types/react-test-renderer": "^18.0.0",
"babel-jest": "^29.6.3",
"eslint": "^8.19.0",
"jest": "^29.6.3",
"prettier": "2.8.8",
"react-test-renderer": "18.3.1",
"@expo/config-plugins": "^9.0.9",
"@react-native-tvos/config-tv": "^0.0.10", "@react-native-tvos/config-tv": "^0.0.10",
"@react-native/metro-config": "^0.75.4",
"@types/react": "~18.2.45",
"babel-plugin-module-resolver": "^5.0.2", "babel-plugin-module-resolver": "^5.0.2",
"typescript": "~5.3.3" "typescript": "~5.3.3"
}, },

View File

@ -240,7 +240,7 @@ const BasicExample = () => {
}; };
useEffect(() => { useEffect(() => {
videoRef.current?.setSource(currentSrc); videoRef.current?.setSource({...currentSrc, bufferConfig: _bufferConfig });
}, [currentSrc]); }, [currentSrc]);
return ( return (
@ -284,7 +284,6 @@ const BasicExample = () => {
selectedAudioTrack={selectedAudioTrack} selectedAudioTrack={selectedAudioTrack}
selectedVideoTrack={selectedVideoTrack} selectedVideoTrack={selectedVideoTrack}
playInBackground={false} playInBackground={false}
bufferConfig={_bufferConfig}
preventsDisplaySleepDuringVideoPlayback={true} preventsDisplaySleepDuringVideoPlayback={true}
renderLoader={_renderLoader} renderLoader={_renderLoader}
onPlaybackRateChange={onPlaybackRateChange} onPlaybackRateChange={onPlaybackRateChange}

View File

@ -113,6 +113,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc var onVideoProgress: RCTDirectEventBlock? @objc var onVideoProgress: RCTDirectEventBlock?
@objc var onVideoBandwidthUpdate: RCTDirectEventBlock? @objc var onVideoBandwidthUpdate: RCTDirectEventBlock?
@objc var onVideoSeek: RCTDirectEventBlock? @objc var onVideoSeek: RCTDirectEventBlock?
@objc var onVideoSeekComplete: RCTDirectEventBlock?
@objc var onVideoEnd: RCTDirectEventBlock? @objc var onVideoEnd: RCTDirectEventBlock?
@objc var onTimedMetadata: RCTDirectEventBlock? @objc var onTimedMetadata: RCTDirectEventBlock?
@objc var onVideoAudioBecomingNoisy: RCTDirectEventBlock? @objc var onVideoAudioBecomingNoisy: RCTDirectEventBlock?
@ -782,34 +783,50 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
_paused = paused _paused = paused
} }
@objc @objc
func setSeek(_ time: NSNumber, _ tolerance: NSNumber) { func setSeek(_ time: NSNumber, _ tolerance: NSNumber) {
let item: AVPlayerItem? = _player?.currentItem let item: AVPlayerItem? = _player?.currentItem
_pendingSeek = true
guard item != nil, let player = _player, let item, item.status == AVPlayerItem.Status.readyToPlay else { guard item != nil, let player = _player, let item, item.status == AVPlayerItem.Status.readyToPlay else {
_pendingSeek = true
_pendingSeekTime = time.floatValue _pendingSeekTime = time.floatValue
return return
} }
RCTPlayerOperations.seek( let wasPaused = _paused
player: player, let seekTime = CMTimeMakeWithSeconds(Float64(time.floatValue), preferredTimescale: Int32(NSEC_PER_SEC))
playerItem: item, let toleranceTime = CMTimeMakeWithSeconds(Float64(tolerance.floatValue), preferredTimescale: Int32(NSEC_PER_SEC))
paused: _paused,
seekTime: time.floatValue, let currentTimeBeforeSeek = CMTimeGetSeconds(item.currentTime())
seekTolerance: tolerance.floatValue
) { [weak self] (_: Bool) in // Call onVideoSeek before starting the seek operation
guard let self else { return } let currentTime = NSNumber(value: Float(currentTimeBeforeSeek))
self.onVideoSeek?(["currentTime": currentTime,
"seekTime": time,
"target": self.reactTag])
_pendingSeek = true
let seekCompletionHandler: (Bool) -> Void = { [weak self] finished in
guard let self = self else { return }
self._pendingSeek = false
guard finished else {
return
}
self._playerObserver.addTimeObserverIfNotSet() self._playerObserver.addTimeObserverIfNotSet()
self.setPaused(self._paused) self.setPaused(self._paused)
self.onVideoSeek?(["currentTime": NSNumber(value: Float(CMTimeGetSeconds(item.currentTime()))),
let newCurrentTime = NSNumber(value: Float(CMTimeGetSeconds(item.currentTime())))
self.onVideoSeekComplete?(["currentTime": newCurrentTime,
"seekTime": time, "seekTime": time,
"target": self.reactTag as Any]) "target": self.reactTag as Any])
} }
_pendingSeek = false player.seek(to: seekTime, toleranceBefore: toleranceTime, toleranceAfter: toleranceTime, completionHandler: seekCompletionHandler)
} }
@objc @objc
@ -967,10 +984,16 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
guard let source = _source else { return } guard let source = _source else { return }
if !source.textTracks.isEmpty { // sideloaded text tracks if !source.textTracks.isEmpty { // sideloaded text tracks
RCTPlayerOperations.setSideloadedText(player: _player, textTracks: source.textTracks, criteria: _selectedTextTrackCriteria) RCTPlayerOperations.setSideloadedText(player: _player, textTracks: source.textTracks, criteria: _selectedTextTrackCriteria)
} else { // text tracks included in the HLS playlist§ } else { // text tracks included in the HLS playlist
Task { Task { [weak self] in
await RCTPlayerOperations.setMediaSelectionTrackForCharacteristic(player: _player, characteristic: AVMediaCharacteristic.legible, guard let self,
criteria: _selectedTextTrackCriteria) let player = self._player else { return }
await RCTPlayerOperations.setMediaSelectionTrackForCharacteristic(
player: player,
characteristic: .legible,
criteria: self._selectedTextTrackCriteria
)
} }
} }
} }
@ -1682,3 +1705,4 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc @objc
func setOnClick(_: Any) {} func setOnClick(_: Any) {}
} }

View File

@ -45,6 +45,7 @@ RCT_EXPORT_VIEW_PROPERTY(onVideoError, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoProgress, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoBandwidthUpdate, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoBandwidthUpdate, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoSeek, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoSeekComplete, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoEnd, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onTimedMetadata, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onTimedMetadata, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onVideoAudioBecomingNoisy, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoAudioBecomingNoisy, RCTDirectEventBlock);

View File

@ -1,6 +1,6 @@
{ {
"name": "react-native-video", "name": "react-native-video",
"version": "6.7.0", "version": "6.8.2",
"description": "A <Video /> element for react-native", "description": "A <Video /> element for react-native",
"main": "lib/index", "main": "lib/index",
"source": "src/index.ts", "source": "src/index.ts",
@ -32,9 +32,12 @@
"react-native": "0.73.2", "react-native": "0.73.2",
"react-native-windows": "^0.61.0-0", "react-native-windows": "^0.61.0-0",
"release-it": "^16.2.1", "release-it": "^16.2.1",
"typescript": "5.1.6" "typescript": "5.1.6",
"patch-package": "^8.0.0"
},
"dependencies": {
"shaka-player": "^4.11.7"
}, },
"dependencies": {},
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",
"react-native": "*" "react-native": "*"

View File

@ -0,0 +1,39 @@
diff --git a/node_modules/shaka-player/dist/shaka-player.compiled.d.ts b/node_modules/shaka-player/dist/shaka-player.compiled.d.ts
index 19c0930..cc0a3fd 100644
--- a/node_modules/shaka-player/dist/shaka-player.compiled.d.ts
+++ b/node_modules/shaka-player/dist/shaka-player.compiled.d.ts
@@ -5117,3 +5117,5 @@ declare namespace shaka.extern {
declare namespace shaka.extern {
type TransmuxerPlugin = ( ) => shaka.extern.Transmuxer ;
}
+
+export default shaka;
diff --git a/node_modules/shaka-player/dist/shaka-player.ui.d.ts b/node_modules/shaka-player/dist/shaka-player.ui.d.ts
index 1618ca0..a6076c6 100644
--- a/node_modules/shaka-player/dist/shaka-player.ui.d.ts
+++ b/node_modules/shaka-player/dist/shaka-player.ui.d.ts
@@ -5830,3 +5830,5 @@ declare namespace shaka.extern {
declare namespace shaka.extern {
type UIVolumeBarColors = { base : string , level : string } ;
}
+
+export default shaka;
diff --git a/node_modules/shaka-player/index.d.ts b/node_modules/shaka-player/index.d.ts
new file mode 100644
index 0000000..3ebfd96
--- /dev/null
+++ b/node_modules/shaka-player/index.d.ts
@@ -0,0 +1,2 @@
+/// <reference path="./dist/shaka-player.compiled.d.ts" />
+/// <reference path="./dist/shaka-player.ui.d.ts" />
\ No newline at end of file
diff --git a/node_modules/shaka-player/ui.d.ts b/node_modules/shaka-player/ui.d.ts
new file mode 100644
index 0000000..84a3be0
--- /dev/null
+++ b/node_modules/shaka-player/ui.d.ts
@@ -0,0 +1,3 @@
+import shaka from 'shaka-player/dist/shaka-player.ui'
+export * from 'shaka-player/dist/shaka-player.ui'
+export default shaka;
\ No newline at end of file

View File

@ -32,6 +32,7 @@ import type {
OnPlaybackStateChangedData, OnPlaybackStateChangedData,
OnProgressData, OnProgressData,
OnSeekData, OnSeekData,
OnSeekCompleteData,
OnTextTrackDataChangedData, OnTextTrackDataChangedData,
OnTimedMetadataData, OnTimedMetadataData,
OnVideoAspectRatioData, OnVideoAspectRatioData,
@ -45,7 +46,7 @@ import {
resolveAssetSourceForVideo, resolveAssetSourceForVideo,
} from './utils'; } from './utils';
import NativeVideoManager from './specs/NativeVideoManager'; import NativeVideoManager from './specs/NativeVideoManager';
import {ViewType, CmcdMode, VideoRef} from './types'; import {type VideoSaveData, ViewType, CmcdMode, VideoRef} from './types';
import type { import type {
OnLoadData, OnLoadData,
OnTextTracksData, OnTextTracksData,
@ -81,6 +82,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onError, onError,
onProgress, onProgress,
onSeek, onSeek,
onSeekComplete,
onEnd, onEnd,
onBuffer, onBuffer,
onBandwidthUpdate, onBandwidthUpdate,
@ -108,6 +110,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onAspectRatio, onAspectRatio,
localSourceEncryptionKeyScheme, localSourceEncryptionKeyScheme,
minLoadRetryCount, minLoadRetryCount,
bufferConfig,
...rest ...rest
}, },
ref, ref,
@ -150,6 +153,11 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
if (!_source) { if (!_source) {
return undefined; return undefined;
} }
const isLocalAssetFile =
typeof _source === 'number' ||
('uri' in _source && typeof _source.uri === 'number');
const resolvedSource = resolveAssetSourceForVideo(_source); const resolvedSource = resolveAssetSourceForVideo(_source);
let uri = resolvedSource.uri || ''; let uri = resolvedSource.uri || '';
if (uri && uri.match(/^\//)) { if (uri && uri.match(/^\//)) {
@ -219,10 +227,13 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
const _minLoadRetryCount = const _minLoadRetryCount =
_source.minLoadRetryCount || minLoadRetryCount; _source.minLoadRetryCount || minLoadRetryCount;
const _bufferConfig = _source.bufferConfig || bufferConfig;
return { return {
uri, uri,
isNetwork, isNetwork,
isAsset, isAsset,
isLocalAssetFile,
shouldCache: resolvedSource.shouldCache || false, shouldCache: resolvedSource.shouldCache || false,
type: resolvedSource.type || '', type: resolvedSource.type || '',
mainVer: resolvedSource.mainVer || 0, mainVer: resolvedSource.mainVer || 0,
@ -240,6 +251,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
textTracksAllowChunklessPreparation: textTracksAllowChunklessPreparation:
resolvedSource.textTracksAllowChunklessPreparation, resolvedSource.textTracksAllowChunklessPreparation,
minLoadRetryCount: _minLoadRetryCount, minLoadRetryCount: _minLoadRetryCount,
bufferConfig: _bufferConfig,
}; };
}, },
[ [
@ -251,6 +263,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
minLoadRetryCount, minLoadRetryCount,
source?.cmcd, source?.cmcd,
textTracks, textTracks,
bufferConfig,
], ],
); );
@ -458,6 +471,13 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
[onSeek], [onSeek],
); );
const onVideoSeekComplete = useCallback(
(e: NativeSyntheticEvent<OnSeekCompleteData>) => {
onSeekComplete?.(e.nativeEvent);
},
[onSeekComplete]
);
const onVideoPlaybackStateChanged = useCallback( const onVideoPlaybackStateChanged = useCallback(
(e: NativeSyntheticEvent<OnPlaybackStateChangedData>) => { (e: NativeSyntheticEvent<OnPlaybackStateChangedData>) => {
onPlaybackStateChanged?.(e.nativeEvent); onPlaybackStateChanged?.(e.nativeEvent);
@ -768,9 +788,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
const _style: StyleProp<ViewStyle> = useMemo( const _style: StyleProp<ViewStyle> = useMemo(
() => ({ () => ({
...StyleSheet.absoluteFillObject, ...StyleSheet.absoluteFillObject,
...(showPoster ? {display: 'none'} : {}),
}), }),
[showPoster], [],
); );
return ( return (
@ -800,6 +819,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
onVideoError={onError ? onVideoError : undefined} onVideoError={onError ? onVideoError : undefined}
onVideoProgress={onProgress ? onVideoProgress : undefined} onVideoProgress={onProgress ? onVideoProgress : undefined}
onVideoSeek={onSeek ? onVideoSeek : undefined} onVideoSeek={onSeek ? onVideoSeek : undefined}
onVideoSeekComplete={onSeekComplete ? onVideoSeekComplete : undefined}
onVideoEnd={onEnd} onVideoEnd={onEnd}
onVideoBuffer={onBuffer ? onVideoBuffer : undefined} onVideoBuffer={onBuffer ? onVideoBuffer : undefined}
onVideoPlaybackStateChanged={ onVideoPlaybackStateChanged={

View File

@ -35,6 +35,7 @@ export type VideoSrc = Readonly<{
uri?: string; uri?: string;
isNetwork?: boolean; isNetwork?: boolean;
isAsset?: boolean; isAsset?: boolean;
isLocalAssetFile?: boolean;
shouldCache?: boolean; shouldCache?: boolean;
type?: string; type?: string;
mainVer?: Int32; mainVer?: Int32;
@ -51,6 +52,7 @@ export type VideoSrc = Readonly<{
textTracks?: TextTracks; textTracks?: TextTracks;
ad?: AdsConfig; ad?: AdsConfig;
minLoadRetryCount?: Int32; // Android minLoadRetryCount?: Int32; // Android
bufferConfig?: BufferConfig; // Android
}>; }>;
type DRMType = WithDefault<string, 'widevine'>; type DRMType = WithDefault<string, 'widevine'>;
@ -203,6 +205,12 @@ export type OnSeekData = Readonly<{
seekTime: Float; seekTime: Float;
}>; }>;
export type OnSeekCompleteData = Readonly<{
currentTime: number;
seekTime: number;
target: number;
}>;
export type OnPlaybackStateChangedData = Readonly<{ export type OnPlaybackStateChangedData = Readonly<{
isPlaying: boolean; isPlaying: boolean;
isSeeking: boolean; isSeeking: boolean;
@ -358,7 +366,6 @@ export interface VideoNativeProps extends ViewProps {
restoreUserInterfaceForPIPStopCompletionHandler?: boolean; restoreUserInterfaceForPIPStopCompletionHandler?: boolean;
debug?: DebugConfig; debug?: DebugConfig;
showNotificationControls?: WithDefault<boolean, false>; // Android, iOS showNotificationControls?: WithDefault<boolean, false>; // Android, iOS
bufferConfig?: BufferConfig; // Android
currentPlaybackTime?: Double; // Android currentPlaybackTime?: Double; // Android
disableDisconnectError?: boolean; // Android disableDisconnectError?: boolean; // Android
focusable?: boolean; // Android focusable?: boolean; // Android
@ -377,6 +384,7 @@ export interface VideoNativeProps extends ViewProps {
onVideoProgress?: DirectEventHandler<OnProgressData>; onVideoProgress?: DirectEventHandler<OnProgressData>;
onVideoBandwidthUpdate?: DirectEventHandler<OnBandwidthUpdateData>; onVideoBandwidthUpdate?: DirectEventHandler<OnBandwidthUpdateData>;
onVideoSeek?: DirectEventHandler<OnSeekData>; onVideoSeek?: DirectEventHandler<OnSeekData>;
onVideoSeekComplete?: DirectEventHandler<OnSeekCompleteData>;
onVideoEnd?: DirectEventHandler<{}>; // all onVideoEnd?: DirectEventHandler<{}>; // all
onVideoAudioBecomingNoisy?: DirectEventHandler<{}>; onVideoAudioBecomingNoisy?: DirectEventHandler<{}>;
onVideoFullscreenPlayerWillPresent?: DirectEventHandler<{}>; // ios, android onVideoFullscreenPlayerWillPresent?: DirectEventHandler<{}>; // ios, android

View File

@ -12,6 +12,7 @@ import type {
OnPlaybackStateChangedData, OnPlaybackStateChangedData,
OnProgressData, OnProgressData,
OnSeekData, OnSeekData,
OnSeekCompleteData,
OnTextTrackDataChangedData, OnTextTrackDataChangedData,
OnTimedMetadataData, OnTimedMetadataData,
OnVideoAspectRatioData, OnVideoAspectRatioData,
@ -260,6 +261,7 @@ export interface ReactVideoEvents {
onReceiveAdEvent?: (e: OnReceiveAdEventData) => void; //Android, iOS onReceiveAdEvent?: (e: OnReceiveAdEventData) => void; //Android, iOS
onRestoreUserInterfaceForPictureInPictureStop?: () => void; //iOS onRestoreUserInterfaceForPictureInPictureStop?: () => void; //iOS
onSeek?: (e: OnSeekData) => void; //Android, iOS, Windows UWP onSeek?: (e: OnSeekData) => void; //Android, iOS, Windows UWP
onSeekComplete?: (e: OnSeekCompleteData) => void; // iOS
onPlaybackStateChanged?: (e: OnPlaybackStateChangedData) => void; // Android, iOS onPlaybackStateChanged?: (e: OnPlaybackStateChangedData) => void; // Android, iOS
onTimedMetadata?: (e: OnTimedMetadataData) => void; //Android, iOS onTimedMetadata?: (e: OnTimedMetadataData) => void; //Android, iOS
onAudioTracks?: (e: OnAudioTracksData) => void; // Android onAudioTracks?: (e: OnAudioTracksData) => void; // Android

View File

@ -24,6 +24,7 @@ export type ReactVideoSourceProperties = {
uri?: string; uri?: string;
isNetwork?: boolean; isNetwork?: boolean;
isAsset?: boolean; isAsset?: boolean;
isLocalAssetFile?: boolean;
shouldCache?: boolean; shouldCache?: boolean;
type?: string; type?: string;
mainVer?: number; mainVer?: number;
@ -40,6 +41,7 @@ export type ReactVideoSourceProperties = {
textTracks?: TextTracks; textTracks?: TextTracks;
ad?: AdConfig; ad?: AdConfig;
minLoadRetryCount?: number; // Android minLoadRetryCount?: number; // Android
bufferConfig?: BufferConfig;
}; };
export type ReactVideoSource = Readonly< export type ReactVideoSource = Readonly<
@ -289,6 +291,7 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
adLanguage?: ISO639_1; adLanguage?: ISO639_1;
audioOutput?: AudioOutput; // Mobile audioOutput?: AudioOutput; // Mobile
automaticallyWaitsToMinimizeStalling?: boolean; // iOS automaticallyWaitsToMinimizeStalling?: boolean; // iOS
/** @deprecated Use source.bufferConfig */
bufferConfig?: BufferConfig; // Android bufferConfig?: BufferConfig; // Android
bufferingStrategy?: BufferingStrategyType; bufferingStrategy?: BufferingStrategyType;
chapters?: Chapters[]; // iOS chapters?: Chapters[]; // iOS