diff --git a/CHANGELOG.md b/CHANGELOG.md index 051a5a690e..5f26b9d546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,61 @@ +# [6.4.2+dolbyxp.1.5](https://github.com/miquido/react-native-video/compare/6.3.0+dolbyxp.1.5...miquido:react-native-video:6.4.2+dolbyxp.1.5) + +Sync with 6.4.2. + +## [6.4.2](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.4.1...v6.4.2) (2024-07-15) + + +### Bug Fixes + +* **android:** exit fullscreen mode after finishing video playback ([#3978](https://github.com/TheWidlarzGroup/react-native-video/issues/3978)) ([4b8d09e](https://github.com/TheWidlarzGroup/react-native-video/commit/4b8d09e61f79a319ba5816dd342b5c0fd02d6e07)) +* **android:** fix android notification controller order ([#4002](https://github.com/TheWidlarzGroup/react-native-video/issues/4002)) ([05623c9](https://github.com/TheWidlarzGroup/react-native-video/commit/05623c9f5447f67acb535487de8918210b5ffec7)) +* **android:** fix onVideoLoad event field key ([#4001](https://github.com/TheWidlarzGroup/react-native-video/issues/4001)) ([f82268b](https://github.com/TheWidlarzGroup/react-native-video/commit/f82268be1bc33e5c61dbb031d7937197da0b67e5)) +* **android:** handle aspect ratio for rotated videos ([#4000](https://github.com/TheWidlarzGroup/react-native-video/issues/4000)) ([0a55ace](https://github.com/TheWidlarzGroup/react-native-video/commit/0a55ace0ca92f56394235f7c651d3a160e6a3c90)) +* **android:** resolve compatibility issue ([5cd5e5e](https://github.com/TheWidlarzGroup/react-native-video/commit/5cd5e5efe70b49d76fb27e3220a1df12b32901a6)) +* **example/basic:** select resizeMode ([#3989](https://github.com/TheWidlarzGroup/react-native-video/issues/3989)) ([39cf477](https://github.com/TheWidlarzGroup/react-native-video/commit/39cf477ceb37c6ecc38cbdd9077a556c81fd9c3d)) +* **ts:** make multiDrm prop optional type ([#3999](https://github.com/TheWidlarzGroup/react-native-video/issues/3999)) ([79c3076](https://github.com/TheWidlarzGroup/react-native-video/commit/79c30767fcf67e75e70ceb64a17736b5e3de63c6)) + +## [6.4.1](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.4.0...v6.4.1) (2024-07-12) + + +### Bug Fixes + +* expo plugin export ([#3992](https://github.com/TheWidlarzGroup/react-native-video/issues/3992)) ([de8ade0](https://github.com/TheWidlarzGroup/react-native-video/commit/de8ade06202cfdb3dd7fec635b6e8c6cdfd04e47)) + +## [6.4.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.3.0...v6.4.0) (2024-07-12) + + +* fix(ios): remove pip check for other platforms (#3991) (40a72825) +* feat: add `isSeeking` to `onPlaybackStateChanged` (#3899) (111a5d21) +* chore(android): migrate DataSourceUtil to Kotlin (#3984) (b25e43ee) +* chore(android): migrate AspectRatioFrameLayout to Kotlin (#3985) (452e42f1) +* refactor: move view type and drm in source (#3867) (66dcf32b) +* feat: add expo plugins (#3933) (08f6caa6) +* docs: update deprecated tool (#3982) (25c74e05) +* chore(android): migrate DefaultReactExoplayerConfig to Kotlin (#3983) (1728373d) +* fix(ios): don't pause playback when entering background (#3973) (ccffcfd7) +* chore(example/basic): refactor state variable (#3949) (a3ecc010) +* feat(android): Bump default media3 version from v1.1.1 to v1.3.1 (#3977) :warning: need targetSdkVersion 34 (7562669f) +* feat: modified Fabric example android build.gradle for resolving build issue (#3976) (1d6fb297) +* chore: upgrade react-native & expo version in the basic example app (#3964) (01a00b12) +* refactor(android): migrate VideoEventEmitter to Kotlin (#3962) (3c9b1b57) +* fix(ios): fix fullscreen view controller ANR (#3952) (7def3ac3) +* chore(example/fabric): bump up fabric example android deps (#3957) (de6e7196) +* refactor(ios): refactor NowPlayingInfoCenerManager.swift (#3968) (76c63291) +* fix(android): build issue on the latest react-native version (#3963) (530686ca) +* feat(fabric): updated ios podspec for implementing new architecture (#3961) (df29c231) +* fix(android): fix wrong module name (#3959) (3f11894c) +* refactor(android): migrate ReactVideoPackage to Kotlin (#3955) (702a0d9d) +* refactor(android): migrate VideoDecoderPropertiesModule to Kotlin (#3954) (99585987) +* feat: bump up fabric example react-native iOS (#3951) (e5a2ee3b) +* fix(android): added setAllowChunklessPreparation to HlsMediaSource.Factory to allow build success on projects without HLS support (#3948) (#3950) (322d7e99) +* refactor: basic example from class component to functional component (#3934) (d4f16486) +* chore(android): rework view type (#3940) (b431d09e) +* chore: update homepage field in package.json (#3945) (6e133768) +* feat(android): allow building exoplayer from source (#3932) (a7d834a8) +* feat: add plugins management (#3909) (91d27a60) +* Chore(docs): fix typo (#3938) (3cfb96ad) + # [6.3.0+dolbyxp.1.5](https://github.com/miquido/react-native-video/compare/6.3.0+dolbyxp.1.4...miquido:react-native-video:6.3.0+dolbyxp.1.5) diff --git a/android/build.gradle b/android/build.gradle index 1ba46ae425..7920bf6584 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -15,8 +15,11 @@ buildscript { } } +// This looks funny but it's necessary to keep backwards compatibility (: def safeExtGet(prop) { - return rootProject.ext.has(prop) ? rootProject.ext.get(prop) : project.properties["RNVideo_" + prop] + return rootProject.ext.has(prop) ? + rootProject.ext.get(prop) : rootProject.ext.has("RNVideo_" + prop) ? + rootProject.ext.get("RNVideo_" + prop) : project.properties["RNVideo_" + prop] } def isNewArchitectureEnabled() { @@ -43,6 +46,7 @@ def ExoplayerDependenciesList = [ "useExoplayerHls", "useExoplayerRtsp", ] +def media3_buildFromSource = safeExtGet('buildFromMedia3Source').toBoolean() ?: false def ExoplayerDependencies = ExoplayerDependenciesList.collectEntries { property -> [(property): safeExtGet(property)?.toBoolean() ?: false] @@ -52,14 +56,17 @@ ExoplayerDependenciesList.each { propertyName -> def propertyValue = ExoplayerDependencies[propertyName] println "$propertyName: $propertyValue" } +println "buildFromSource: $media3_buildFromSource" // This string is used to define build path. // As react native build output directory is react-native path of the module. // We need to force a new path on each configuration change. // If you add a new build parameter, please add the new value in this string -def configStringPath = ExoplayerDependencies.collect { property, value -> - property + value -}.join('').md5() +def configStringPath = ExoplayerDependencies + .collect { property, value -> property + value} + .join('') + .concat("buildFromSource:$media3_buildFromSource") + .md5() if (isNewArchitectureEnabled()) { apply plugin: "com.facebook.react" @@ -191,46 +198,87 @@ dependencies { implementation "androidx.activity:activity-ktx:$androidxActivity_version" // For media playback using ExoPlayer - implementation "androidx.media3:media3-exoplayer:$media3_version" + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer")) + } else { + implementation "androidx.media3:media3-exoplayer:$media3_version" + } if (ExoplayerDependencies["useExoplayerSmoothStreaming"]) { // For Smooth Streaming playback support with ExoPlayer - implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version" + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer-smoothstreaming")) + } else { + implementation "androidx.media3:media3-exoplayer-smoothstreaming:$media3_version" + } } if (ExoplayerDependencies["useExoplayerDash"]) { // For DASH playback support with ExoPlayer - implementation "androidx.media3:media3-exoplayer-dash:$media3_version" + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer-dash")) + } else { + implementation "androidx.media3:media3-exoplayer-dash:$media3_version" + } } if (ExoplayerDependencies["useExoplayerHls"]) { - // For HLS playback support with ExoPlayer - implementation "androidx.media3:media3-exoplayer-hls:$media3_version" + // For HLS playback support with ExoPlayer + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer-hls")) + } else { + implementation "androidx.media3:media3-exoplayer-hls:$media3_version" + } } // For RTSP playback support with ExoPlayer if (ExoplayerDependencies["useExoplayerRtsp"]) { - implementation "androidx.media3:media3-exoplayer-rtsp:$media3_version" + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer-rtsp")) + } else { + implementation "androidx.media3:media3-exoplayer-rtsp:$media3_version" + } } // For ad insertion using the Interactive Media Ads SDK with ExoPlayer if (ExoplayerDependencies["useExoplayerIMA"]) { - implementation "androidx.media3:media3-exoplayer-ima:$media3_version" + if (media3_buildFromSource) { + implementation(project(":media-lib-exoplayer-ima")) + } else { + implementation "androidx.media3:media3-exoplayer-ima:$media3_version" + } } - // For loading data using the OkHttp network stack - implementation "androidx.media3:media3-datasource-okhttp:$media3_version" + if (media3_buildFromSource) { + // For loading data using the OkHttp network stack + implementation(project(":media-lib-datasource-okhttp")) - // For building media playback UIs - implementation "androidx.media3:media3-ui:$media3_version" + // For building media playback UIs + implementation(project(":media-lib-ui")) - // For exposing and controlling media sessions - implementation "androidx.media3:media3-session:$media3_version" + // For exposing and controlling media sessions + implementation(project(":media-lib-session")) - // Common functionality for loading data - implementation "androidx.media3:media3-datasource:$media3_version" - // Common functionality used across multiple media libraries - implementation "androidx.media3:media3-common:$media3_version" + // Common functionality for loading data + implementation(project(":media-lib-datasource")) + // Common functionality used across multiple media libraries + implementation(project(":media-lib-common")) + } else { + // For loading data using the OkHttp network stack + implementation "androidx.media3:media3-datasource-okhttp:$media3_version" + + // For building media playback UIs + implementation "androidx.media3:media3-ui:$media3_version" + + // For exposing and controlling media sessions + implementation "androidx.media3:media3-session:$media3_version" + + // Common functionality for loading data + implementation "androidx.media3:media3-datasource:$media3_version" + + // Common functionality used across multiple media libraries + implementation "androidx.media3:media3-common:$media3_version" + } implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" } diff --git a/android/gradle.properties b/android/gradle.properties index f19a0a192f..d4b231664b 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,10 +1,10 @@ RNVideo_kotlinVersion=1.7.0 -RNVideo_minSdkVersion=21 -RNVideo_targetSdkVersion=31 -RNVideo_compileSdkVersion=31 -RNVideo_ndkversion=21.4.7075529 -RNVideo_buildToolsVersion=30.0.2 -RNVideo_media3Version=1.1.1 +RNVideo_minSdkVersion=23 +RNVideo_targetSdkVersion=34 +RNVideo_compileSdkVersion=34 +RNVideo_ndkversion=26.1.10909125 +RNVideo_buildToolsVersion=34.0.0 +RNVideo_media3Version=1.3.1 RNVideo_useExoplayerIMA=false RNVideo_useExoplayerRtsp=false RNVideo_useExoplayerSmoothStreaming=true @@ -12,3 +12,4 @@ RNVideo_useExoplayerDash=true RNVideo_useExoplayerHls=true RNVideo_androidxCoreVersion=1.9.0 RNVideo_androidxActivityVersion=1.7.0 +RNVideo_buildFromMedia3Source=false diff --git a/android/src/main/java/com/brentvatne/common/api/DRMProps.kt b/android/src/main/java/com/brentvatne/common/api/DRMProps.kt index a26d048ac2..0c495e1177 100644 --- a/android/src/main/java/com/brentvatne/common/api/DRMProps.kt +++ b/android/src/main/java/com/brentvatne/common/api/DRMProps.kt @@ -1,6 +1,7 @@ package com.brentvatne.common.api import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetArray +import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetBool import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetString import com.facebook.react.bridge.ReadableMap import java.util.UUID @@ -29,12 +30,28 @@ class DRMProps { * DRM Http Header to access to license server */ var drmLicenseHeader: Array = emptyArray() + + /** + * Flag to enable key rotation support + */ + var multiDrm: Boolean = false + + /** return true if this and src are equals */ + override fun equals(other: Any?): Boolean { + if (other == null || other !is DRMProps) return false + return drmType == other.drmType && + drmLicenseServer == other.drmLicenseServer && + multiDrm == other.multiDrm && + drmLicenseHeader.contentDeepEquals(other.drmLicenseHeader) // drmLicenseHeader is never null + } + companion object { private const val PROP_DRM_TYPE = "type" private const val PROP_DRM_LICENSE_SERVER = "licenseServer" private const val PROP_DRM_HEADERS = "headers" private const val PROP_DRM_HEADERS_KEY = "key" private const val PROP_DRM_HEADERS_VALUE = "value" + private const val PROP_DRM_MULTI_DRM = "multiDrm" /** parse the source ReadableMap received from app */ @JvmStatic @@ -44,6 +61,7 @@ class DRMProps { drm = DRMProps() drm.drmType = safeGetString(src, PROP_DRM_TYPE) drm.drmLicenseServer = safeGetString(src, PROP_DRM_LICENSE_SERVER) + drm.multiDrm = safeGetBool(src, PROP_DRM_MULTI_DRM, false) val drmHeadersArray = safeGetArray(src, PROP_DRM_HEADERS) if (drm.drmType != null && drm.drmLicenseServer != null) { if (drmHeadersArray != null) { diff --git a/android/src/main/java/com/brentvatne/common/api/Source.kt b/android/src/main/java/com/brentvatne/common/api/Source.kt index b19fa8d94f..ba4f849605 100644 --- a/android/src/main/java/com/brentvatne/common/api/Source.kt +++ b/android/src/main/java/com/brentvatne/common/api/Source.kt @@ -6,6 +6,7 @@ import android.content.Context import android.content.res.Resources import android.net.Uri import android.text.TextUtils +import com.brentvatne.common.api.DRMProps.Companion.parse import com.brentvatne.common.toolbox.DebugLog import com.brentvatne.common.toolbox.DebugLog.e import com.brentvatne.common.toolbox.ReactBridgeUtils.safeGetArray @@ -46,6 +47,11 @@ class Source { /** http header list */ val headers: MutableMap = HashMap() + /** + * DRM properties linked to the source + */ + var drmProps: DRMProps? = null + /** enable chunkless preparation for HLS * see: */ @@ -61,7 +67,8 @@ class Source { cropStartMs == other.cropStartMs && cropEndMs == other.cropEndMs && startPositionMs == other.startPositionMs && - extension == other.extension + extension == other.extension && + drmProps == other.drmProps ) } @@ -123,6 +130,7 @@ class Source { private const val PROP_SRC_TYPE = "type" private const val PROP_SRC_METADATA = "metadata" private const val PROP_SRC_HEADERS = "requestHeaders" + private const val PROP_SRC_DRM = "drm" private const val PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION = "textTracksAllowChunklessPreparation" @SuppressLint("DiscouragedApi") @@ -180,6 +188,7 @@ class Source { source.cropStartMs = safeGetInt(src, PROP_SRC_CROP_START, -1) source.cropEndMs = safeGetInt(src, PROP_SRC_CROP_END, -1) source.extension = safeGetString(src, PROP_SRC_TYPE, null) + source.drmProps = parse(safeGetMap(src, PROP_SRC_DRM)) source.textTracksAllowChunklessPreparation = safeGetBool(src, PROP_SRC_TEXT_TRACKS_ALLOW_CHUNKLESS_PREPARATION, true) val propSrcHeadersArray = safeGetArray(src, PROP_SRC_HEADERS) diff --git a/android/src/main/java/com/brentvatne/common/api/ViewType.kt b/android/src/main/java/com/brentvatne/common/api/ViewType.kt new file mode 100644 index 0000000000..c171a231a2 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/api/ViewType.kt @@ -0,0 +1,19 @@ +package com.brentvatne.common.api + +internal object ViewType { + /** + * View used will be a TextureView. + */ + const val VIEW_TYPE_TEXTURE = 0 + + /** + * View used will be a SurfaceView. + */ + const val VIEW_TYPE_SURFACE = 1 + + /** + * View used will be a SurfaceView with secure flag set. + */ + const val VIEW_TYPE_SURFACE_SECURE = 2 + annotation class ViewType +} diff --git a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java deleted file mode 100644 index bb8c061e26..0000000000 --- a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java +++ /dev/null @@ -1,519 +0,0 @@ -package com.brentvatne.common.react; - -import static com.brentvatne.exoplayer.LocaleUtils.getLanguageDisplayName; - -import android.view.View; - -import androidx.annotation.Nullable; -import androidx.annotation.StringDef; -import androidx.media3.common.Format; -import androidx.media3.exoplayer.dash.manifest.Representation; - -import com.brentvatne.common.api.TimedMetadata; -import com.brentvatne.exoplayer.ManifestUtils; -import com.brentvatne.exoplayer.TrackInfo; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.UIManager; -import com.facebook.react.bridge.WritableArray; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.uimanager.UIManagerHelper; -import com.facebook.react.uimanager.common.ViewUtil; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -public class VideoEventEmitter { - - private final ReactContext mReactContext; - - private int viewId = View.NO_ID; - - public VideoEventEmitter(ReactContext reactContext) { - this.mReactContext = reactContext; - } - - private static final String EVENT_LOAD_START = "onVideoLoadStart"; - private static final String EVENT_LOAD = "onVideoLoad"; - private static final String EVENT_ERROR = "onVideoError"; - private static final String EVENT_PROGRESS = "onVideoProgress"; - private static final String EVENT_BANDWIDTH = "onVideoBandwidthUpdate"; - private static final String EVENT_CONTROLS_VISIBILITY_CHANGE = "onControlsVisibilityChange"; - private static final String EVENT_SEEK = "onVideoSeek"; - private static final String EVENT_END = "onVideoEnd"; - private static final String EVENT_FULLSCREEN_WILL_PRESENT = "onVideoFullscreenPlayerWillPresent"; - private static final String EVENT_FULLSCREEN_DID_PRESENT = "onVideoFullscreenPlayerDidPresent"; - private static final String EVENT_FULLSCREEN_WILL_DISMISS = "onVideoFullscreenPlayerWillDismiss"; - private static final String EVENT_FULLSCREEN_DID_DISMISS = "onVideoFullscreenPlayerDidDismiss"; - - private static final String EVENT_STALLED = "onPlaybackStalled"; - private static final String EVENT_RESUME = "onPlaybackResume"; - private static final String EVENT_READY = "onReadyForDisplay"; - private static final String EVENT_BUFFER = "onVideoBuffer"; - private static final String EVENT_PLAYBACK_STATE_CHANGED = "onVideoPlaybackStateChanged"; - private static final String EVENT_IDLE = "onVideoIdle"; - private static final String EVENT_TIMED_METADATA = "onTimedMetadata"; - private static final String EVENT_AUDIO_BECOMING_NOISY = "onVideoAudioBecomingNoisy"; - private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged"; - private static final String EVENT_PLAYBACK_RATE_CHANGE = "onPlaybackRateChange"; - private static final String EVENT_VOLUME_CHANGE = "onVolumeChange"; - private static final String EVENT_AUDIO_TRACKS = "onAudioTracks"; - private static final String EVENT_TEXT_TRACKS = "onTextTracks"; - - private static final String EVENT_TEXT_TRACK_DATA_CHANGED = "onTextTrackDataChanged"; - private static final String EVENT_VIDEO_TRACKS = "onVideoTracks"; - private static final String EVENT_ON_RECEIVE_AD_EVENT = "onReceiveAdEvent"; - - static public final String[] Events = { - EVENT_LOAD_START, - EVENT_LOAD, - EVENT_ERROR, - EVENT_PROGRESS, - EVENT_SEEK, - EVENT_END, - EVENT_FULLSCREEN_WILL_PRESENT, - EVENT_FULLSCREEN_DID_PRESENT, - EVENT_FULLSCREEN_WILL_DISMISS, - EVENT_FULLSCREEN_DID_DISMISS, - EVENT_STALLED, - EVENT_RESUME, - EVENT_READY, - EVENT_BUFFER, - EVENT_PLAYBACK_STATE_CHANGED, - EVENT_IDLE, - EVENT_TIMED_METADATA, - EVENT_AUDIO_BECOMING_NOISY, - EVENT_AUDIO_FOCUS_CHANGE, - EVENT_PLAYBACK_RATE_CHANGE, - EVENT_VOLUME_CHANGE, - EVENT_AUDIO_TRACKS, - EVENT_TEXT_TRACKS, - EVENT_TEXT_TRACK_DATA_CHANGED, - EVENT_VIDEO_TRACKS, - EVENT_BANDWIDTH, - EVENT_CONTROLS_VISIBILITY_CHANGE, - EVENT_ON_RECEIVE_AD_EVENT - }; - - @Retention(RetentionPolicy.SOURCE) - @StringDef({ - EVENT_LOAD_START, - EVENT_LOAD, - EVENT_ERROR, - EVENT_PROGRESS, - EVENT_SEEK, - EVENT_END, - EVENT_FULLSCREEN_WILL_PRESENT, - EVENT_FULLSCREEN_DID_PRESENT, - EVENT_FULLSCREEN_WILL_DISMISS, - EVENT_FULLSCREEN_DID_DISMISS, - EVENT_STALLED, - EVENT_RESUME, - EVENT_READY, - EVENT_BUFFER, - EVENT_PLAYBACK_STATE_CHANGED, - EVENT_IDLE, - EVENT_TIMED_METADATA, - EVENT_AUDIO_BECOMING_NOISY, - EVENT_AUDIO_FOCUS_CHANGE, - EVENT_PLAYBACK_RATE_CHANGE, - EVENT_VOLUME_CHANGE, - EVENT_AUDIO_TRACKS, - EVENT_TEXT_TRACKS, - EVENT_TEXT_TRACK_DATA_CHANGED, - EVENT_VIDEO_TRACKS, - EVENT_BANDWIDTH, - EVENT_CONTROLS_VISIBILITY_CHANGE, - EVENT_ON_RECEIVE_AD_EVENT - }) - @interface VideoEvents { - } - - private static final String EVENT_PROP_FAST_FORWARD = "canPlayFastForward"; - private static final String EVENT_PROP_SLOW_FORWARD = "canPlaySlowForward"; - private static final String EVENT_PROP_SLOW_REVERSE = "canPlaySlowReverse"; - private static final String EVENT_PROP_REVERSE = "canPlayReverse"; - private static final String EVENT_PROP_STEP_FORWARD = "canStepForward"; - private static final String EVENT_PROP_STEP_BACKWARD = "canStepBackward"; - - private static final String EVENT_PROP_DURATION = "duration"; - private static final String EVENT_PROP_PLAYABLE_DURATION = "playableDuration"; - private static final String EVENT_PROP_SEEKABLE_DURATION = "seekableDuration"; - private static final String EVENT_PROP_CURRENT_TIME = "currentTime"; - private static final String EVENT_PROP_CURRENT_PLAYBACK_TIME = "currentPlaybackTime"; - private static final String EVENT_PROP_SEEK_TIME = "seekTime"; - private static final String EVENT_PROP_NATURAL_SIZE = "naturalSize"; - private static final String EVENT_PROP_TRACK_ID = "trackId"; - private static final String EVENT_PROP_WIDTH = "width"; - private static final String EVENT_PROP_HEIGHT = "height"; - private static final String EVENT_PROP_ORIENTATION = "orientation"; - private static final String EVENT_PROP_VIDEO_TRACKS = "videoTracks"; - private static final String EVENT_PROP_AUDIO_TRACKS = "audioTracks"; - private static final String EVENT_PROP_TEXT_TRACKS = "textTracks"; - private static final String EVENT_PROP_TEXT_TRACK_DATA = "subtitleTracks"; - private static final String EVENT_PROP_HAS_AUDIO_FOCUS = "hasAudioFocus"; - private static final String EVENT_PROP_IS_BUFFERING = "isBuffering"; - private static final String EVENT_PROP_PLAYBACK_RATE = "playbackRate"; - private static final String EVENT_PROP_VOLUME = "volume"; - - private static final String EVENT_PROP_ERROR = "error"; - private static final String EVENT_PROP_ERROR_STRING = "errorString"; - private static final String EVENT_PROP_ERROR_EXCEPTION = "errorException"; - private static final String EVENT_PROP_ERROR_TRACE = "errorStackTrace"; - private static final String EVENT_PROP_ERROR_CODE = "errorCode"; - - private static final String EVENT_PROP_TIMED_METADATA = "metadata"; - - private static final String EVENT_PROP_BITRATE = "bitrate"; - - private static final String EVENT_PROP_IS_PLAYING = "isPlaying"; - - private static final String EVENT_CONTROLS_VISIBLE = "isVisible"; - - public void setViewId(int viewId) { - this.viewId = viewId; - } - - public void loadStart() { - receiveEvent(EVENT_LOAD_START, null); - } - - WritableMap aspectRatioToNaturalSize(int videoWidth, int videoHeight) { - WritableMap naturalSize = Arguments.createMap(); - naturalSize.putInt(EVENT_PROP_WIDTH, videoWidth); - naturalSize.putInt(EVENT_PROP_HEIGHT, videoHeight); - if (videoWidth > videoHeight) { - naturalSize.putString(EVENT_PROP_ORIENTATION, "landscape"); - } else if (videoWidth < videoHeight) { - naturalSize.putString(EVENT_PROP_ORIENTATION, "portrait"); - } else { - naturalSize.putString(EVENT_PROP_ORIENTATION, "square"); - } - return naturalSize; - } - - public void load( - long duration, - long currentPosition, - int videoWidth, - int videoHeight, - List audioTracks, - List videoTracks, - List textTracks, - @Nullable Object manifest, - String trackId) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_DURATION, duration / 1000D); - event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); - - WritableMap naturalSize = aspectRatioToNaturalSize(videoWidth, videoHeight); - event.putMap(EVENT_PROP_NATURAL_SIZE, naturalSize); - event.putString(EVENT_PROP_TRACK_ID, trackId); - WritableArray videoTrackArray = Arguments.createArray(); - for (TrackInfo track : videoTracks) { - videoTrackArray.pushMap(createVideoTrackInfo(track, false, manifest)); - } - event.putArray(EVENT_PROP_VIDEO_TRACKS, videoTrackArray); - WritableArray audioTrackArray = Arguments.createArray(); - for (TrackInfo track : audioTracks) { - audioTrackArray.pushMap(createAudioTrackInfo(track, false, manifest)); - } - event.putArray(EVENT_PROP_AUDIO_TRACKS, audioTrackArray); - WritableArray textTrackArray = Arguments.createArray(); - for (TrackInfo track : textTracks) { - textTrackArray.pushMap(createTextTrackInfo(track, false)); - } - event.putArray(EVENT_PROP_TEXT_TRACKS, textTrackArray); - - // TODO: Actually check if you can. - event.putBoolean(EVENT_PROP_FAST_FORWARD, true); - event.putBoolean(EVENT_PROP_SLOW_FORWARD, true); - event.putBoolean(EVENT_PROP_SLOW_REVERSE, true); - event.putBoolean(EVENT_PROP_REVERSE, true); - event.putBoolean(EVENT_PROP_FAST_FORWARD, true); - event.putBoolean(EVENT_PROP_STEP_BACKWARD, true); - event.putBoolean(EVENT_PROP_STEP_FORWARD, true); - - receiveEvent(EVENT_LOAD, event); - } - - public void audioTracks(List audioTracks, @Nullable TrackInfo selectedTrack, @Nullable Object manifest) { - WritableMap event = Arguments.createMap(); - WritableArray audioTrackArray = Arguments.createArray(); - for (TrackInfo track : audioTracks) { - boolean selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex; - audioTrackArray.pushMap(createAudioTrackInfo(track, selected, manifest)); - } - event.putArray(EVENT_PROP_AUDIO_TRACKS, audioTrackArray); - receiveEvent(EVENT_AUDIO_TRACKS, event); - } - - public void videoTracks(List videoTracks, @Nullable TrackInfo selectedTrack, @Nullable Object manifest) { - WritableMap event = Arguments.createMap(); - WritableArray videoTrackArray = Arguments.createArray(); - for (TrackInfo track : videoTracks) { - boolean selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex; - videoTrackArray.pushMap(createVideoTrackInfo(track, selected, manifest)); - } - event.putArray(EVENT_PROP_VIDEO_TRACKS, videoTrackArray); - receiveEvent(EVENT_VIDEO_TRACKS, event); - } - - public void textTracks(List textTracks, @Nullable TrackInfo selectedTrack) { - WritableMap event = Arguments.createMap(); - WritableArray textTrackArray = Arguments.createArray(); - for (TrackInfo track : textTracks) { - boolean selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex; - textTrackArray.pushMap(createTextTrackInfo(track, selected)); - } - event.putArray(EVENT_PROP_TEXT_TRACKS, textTrackArray); - receiveEvent(EVENT_TEXT_TRACKS, event); - } - public void textTrackDataChanged(String textTrackData){ - WritableMap event = Arguments.createMap(); - event.putString(EVENT_PROP_TEXT_TRACK_DATA, textTrackData); - receiveEvent(EVENT_TEXT_TRACK_DATA_CHANGED, event); - } - - public void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double currentPlaybackTime) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); - event.putDouble(EVENT_PROP_PLAYABLE_DURATION, bufferedDuration / 1000D); - event.putDouble(EVENT_PROP_SEEKABLE_DURATION, seekableDuration / 1000D); - event.putDouble(EVENT_PROP_CURRENT_PLAYBACK_TIME, currentPlaybackTime); - receiveEvent(EVENT_PROGRESS, event); - } - - public void bandwidthReport(double bitRateEstimate, int height, int width, String id) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_BITRATE, bitRateEstimate); - event.putInt(EVENT_PROP_WIDTH, width); - event.putInt(EVENT_PROP_HEIGHT, height); - event.putString(EVENT_PROP_TRACK_ID, id); - receiveEvent(EVENT_BANDWIDTH, event); - } - - public void seek(long currentPosition, long seekTime) { - WritableMap event = Arguments.createMap(); - event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); - event.putDouble(EVENT_PROP_SEEK_TIME, seekTime / 1000D); - receiveEvent(EVENT_SEEK, event); - } - - public void ready() { - receiveEvent(EVENT_READY, null); - } - - public void buffering(boolean isBuffering) { - WritableMap map = Arguments.createMap(); - map.putBoolean(EVENT_PROP_IS_BUFFERING, isBuffering); - receiveEvent(EVENT_BUFFER, map); - } - - public void playbackStateChanged(boolean isPlaying) { - WritableMap map = Arguments.createMap(); - map.putBoolean(EVENT_PROP_IS_PLAYING, isPlaying); - receiveEvent(EVENT_PLAYBACK_STATE_CHANGED, map); - } - - public void idle() { - receiveEvent(EVENT_IDLE, null); - } - - public void end() { - receiveEvent(EVENT_END, null); - } - - public void controlsVisibilityChanged(boolean isVisible) { - WritableMap map = Arguments.createMap(); - map.putBoolean(EVENT_CONTROLS_VISIBLE, isVisible); - receiveEvent(EVENT_CONTROLS_VISIBILITY_CHANGE, map); - } - - public void fullscreenWillPresent() { - receiveEvent(EVENT_FULLSCREEN_WILL_PRESENT, null); - } - - public void fullscreenDidPresent() { - receiveEvent(EVENT_FULLSCREEN_DID_PRESENT, null); - } - - public void fullscreenWillDismiss() { - receiveEvent(EVENT_FULLSCREEN_WILL_DISMISS, null); - } - - public void fullscreenDidDismiss() { - receiveEvent(EVENT_FULLSCREEN_DID_DISMISS, null); - } - - public void error(String errorString, Exception exception) { - _error(errorString, exception, "0001"); - } - - public void error(String errorString, Exception exception, String errorCode) { - _error(errorString, exception, errorCode); - } - - void _error(String errorString, Exception exception, String errorCode) { - // Prepare stack trace - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - exception.printStackTrace(pw); - String stackTrace = sw.toString(); - - WritableMap error = Arguments.createMap(); - error.putString(EVENT_PROP_ERROR_STRING, errorString); - error.putString(EVENT_PROP_ERROR_EXCEPTION, exception.toString()); - error.putString(EVENT_PROP_ERROR_CODE, errorCode); - error.putString(EVENT_PROP_ERROR_TRACE, stackTrace); - WritableMap event = Arguments.createMap(); - event.putMap(EVENT_PROP_ERROR, error); - receiveEvent(EVENT_ERROR, event); - } - - public void playbackRateChange(float rate) { - WritableMap map = Arguments.createMap(); - map.putDouble(EVENT_PROP_PLAYBACK_RATE, (double)rate); - receiveEvent(EVENT_PLAYBACK_RATE_CHANGE, map); - } - - public void volumeChange(float volume) { - WritableMap map = Arguments.createMap(); - map.putDouble(EVENT_PROP_VOLUME, volume); - receiveEvent(EVENT_VOLUME_CHANGE, map); - } - - public void timedMetadata(ArrayList _metadataArrayList) { - if (_metadataArrayList.size() == 0) { - return; - } - WritableArray metadataArray = Arguments.createArray(); - - for (int i = 0; i < _metadataArrayList.size(); i++) { - WritableMap map = Arguments.createMap(); - map.putString("identifier", _metadataArrayList.get(i).getIdentifier()); - map.putString("value", _metadataArrayList.get(i).getValue()); - metadataArray.pushMap(map); - } - - WritableMap event = Arguments.createMap(); - event.putArray(EVENT_PROP_TIMED_METADATA, metadataArray); - receiveEvent(EVENT_TIMED_METADATA, event); - } - - public void audioFocusChanged(boolean hasFocus) { - WritableMap map = Arguments.createMap(); - map.putBoolean(EVENT_PROP_HAS_AUDIO_FOCUS, hasFocus); - receiveEvent(EVENT_AUDIO_FOCUS_CHANGE, map); - } - - public void audioBecomingNoisy() { - receiveEvent(EVENT_AUDIO_BECOMING_NOISY, null); - } - - public void receiveAdEvent(String event, Map data) { - WritableMap map = Arguments.createMap(); - map.putString("event", event); - - WritableMap dataMap = Arguments.createMap(); - for (Map.Entry entry : data.entrySet()) { - dataMap.putString(entry.getKey(), entry.getValue()); - } - map.putMap("data", dataMap); - - receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map); - } - - public void receiveAdEvent(String event) { - WritableMap map = Arguments.createMap(); - map.putString("event", event); - - receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map); - } - - public void receiveAdErrorEvent(String message, String code, String type) { - WritableMap map = Arguments.createMap(); - map.putString("event", "ERROR"); - - WritableMap dataMap = Arguments.createMap(); - dataMap.putString("message", message); - dataMap.putString("code", code); - dataMap.putString("type", type); - map.putMap("data", dataMap); - - receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map); - } - - private void receiveEvent(@VideoEvents String type, WritableMap event) { - UIManager uiManager = UIManagerHelper.getUIManager(mReactContext, ViewUtil.getUIManagerType(viewId)); - - if(uiManager != null) { - uiManager.receiveEvent(UIManagerHelper.getSurfaceId(mReactContext), viewId, type, event); - } - } - - @Nullable - private static WritableMap createAudioTrackInfo(TrackInfo track, boolean selected, @Nullable Object manifest) { - if (track == null) return null; - long complexIndex = track.complexIndex; - Format format = track.format; - WritableMap audioTrack = Arguments.createMap(); - audioTrack.putDouble("index", complexIndex); - audioTrack.putString("trackId", format.id != null ? format.id : String.valueOf(complexIndex)); - audioTrack.putString("title", getLanguageDisplayName(format.language)); - audioTrack.putString("type", format.sampleMimeType); - audioTrack.putString("language", format.language); - audioTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate); - audioTrack.putString("codecs", format.codecs); - audioTrack.putString("channels", String.valueOf(format.channelCount != Format.NO_VALUE ? format.channelCount : 0)); - audioTrack.putBoolean("selected", selected); - if (manifest != null) { - Representation representation = ManifestUtils.getRepresentationOf(manifest, track); - audioTrack.putString("file", ManifestUtils.getRepresentationFileName(representation)); - audioTrack.putString("supplementalProperties", ManifestUtils.getRepresentationSupplementalProperties(representation)); - } - return audioTrack; - } - - @Nullable - private static WritableMap createVideoTrackInfo(TrackInfo track, boolean selected, @Nullable Object manifest) { - if (track == null) return null; - long complexIndex = track.complexIndex; - Format format = track.format; - WritableMap videoTrack = Arguments.createMap(); - videoTrack.putDouble("index", complexIndex); - videoTrack.putString("trackId", format.id != null ? format.id : String.valueOf(complexIndex)); - videoTrack.putInt("width", format.width == Format.NO_VALUE ? 0 : format.width); - videoTrack.putInt("height", format.height == Format.NO_VALUE ? 0 : format.height); - videoTrack.putInt("bitrate", format.bitrate == Format.NO_VALUE ? 0 : format.bitrate); - videoTrack.putString("codecs", format.codecs); - videoTrack.putBoolean("selected", selected); - videoTrack.putInt("rotation", format.rotationDegrees); - if (manifest != null) { - Representation representation = ManifestUtils.getRepresentationOf(manifest, track); - videoTrack.putString("file", ManifestUtils.getRepresentationFileName(representation)); - videoTrack.putString("supplementalProperties", ManifestUtils.getRepresentationSupplementalProperties(representation)); - } - return videoTrack; - } - - @Nullable - private static WritableMap createTextTrackInfo(TrackInfo track, boolean selected) { - if (track == null) return null; - long complexIndex = track.complexIndex; - Format format = track.format; - WritableMap textTrack = Arguments.createMap(); - textTrack.putDouble("index", complexIndex); - textTrack.putString("trackId", format.id != null ? format.id : String.valueOf(complexIndex)); - textTrack.putString("title", getLanguageDisplayName(format.language)); - textTrack.putString("type", format.sampleMimeType); - textTrack.putString("language", format.language); - textTrack.putBoolean("selected", selected); - return textTrack; - } -} diff --git a/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt new file mode 100644 index 0000000000..bd8ca41377 --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.kt @@ -0,0 +1,406 @@ +package com.brentvatne.common.react + +import androidx.media3.common.Format +import com.brentvatne.common.api.TimedMetadata +import com.brentvatne.exoplayer.LocaleUtils.getLanguageDisplayName +import com.brentvatne.exoplayer.ManifestUtils.getRepresentationFileName +import com.brentvatne.exoplayer.ManifestUtils.getRepresentationOf +import com.brentvatne.exoplayer.ManifestUtils.getRepresentationSupplementalProperties +import com.brentvatne.exoplayer.ReactExoplayerView +import com.brentvatne.exoplayer.TrackInfo +import com.facebook.react.bridge.Arguments +import com.facebook.react.bridge.WritableMap +import com.facebook.react.uimanager.ThemedReactContext +import com.facebook.react.uimanager.UIManagerHelper +import com.facebook.react.uimanager.events.Event +import com.facebook.react.uimanager.events.EventDispatcher +import java.io.PrintWriter +import java.io.StringWriter + +enum class EventTypes(val eventName: String) { + EVENT_LOAD_START("onVideoLoadStart"), + EVENT_LOAD("onVideoLoad"), + EVENT_ERROR("onVideoError"), + EVENT_PROGRESS("onVideoProgress"), + EVENT_BANDWIDTH("onVideoBandwidthUpdate"), + EVENT_CONTROLS_VISIBILITY_CHANGE("onControlsVisibilityChange"), + EVENT_SEEK("onVideoSeek"), + EVENT_END("onVideoEnd"), + EVENT_FULLSCREEN_WILL_PRESENT("onVideoFullscreenPlayerWillPresent"), + EVENT_FULLSCREEN_DID_PRESENT("onVideoFullscreenPlayerDidPresent"), + EVENT_FULLSCREEN_WILL_DISMISS("onVideoFullscreenPlayerWillDismiss"), + EVENT_FULLSCREEN_DID_DISMISS("onVideoFullscreenPlayerDidDismiss"), + + EVENT_READY("onReadyForDisplay"), + EVENT_BUFFER("onVideoBuffer"), + EVENT_PLAYBACK_STATE_CHANGED("onVideoPlaybackStateChanged"), + EVENT_IDLE("onVideoIdle"), + EVENT_TIMED_METADATA("onTimedMetadata"), + EVENT_AUDIO_BECOMING_NOISY("onVideoAudioBecomingNoisy"), + EVENT_AUDIO_FOCUS_CHANGE("onAudioFocusChanged"), + EVENT_PLAYBACK_RATE_CHANGE("onPlaybackRateChange"), + EVENT_VOLUME_CHANGE("onVolumeChange"), + EVENT_AUDIO_TRACKS("onAudioTracks"), + EVENT_TEXT_TRACKS("onTextTracks"), + + EVENT_TEXT_TRACK_DATA_CHANGED("onTextTrackDataChanged"), + EVENT_VIDEO_TRACKS("onVideoTracks"), + EVENT_ON_RECEIVE_AD_EVENT("onReceiveAdEvent"); + + companion object { + fun toMap() = + mutableMapOf().apply { + EventTypes.values().toList().forEach { eventType -> + put("top${eventType.eventName.removePrefix("on")}", mapOf("registrationName" to eventType.eventName)) + } + } + } +} + +class VideoEventEmitter { + lateinit var onVideoLoadStart: () -> Unit + lateinit var onVideoLoad: ( + duration: Long, + currentPosition: Long, + videoWidth: Int, + videoHeight: Int, + audioTracks: List, + textTracks: List, + videoTracks: List, + manifest: Any?, + trackId: String + ) -> Unit + lateinit var onVideoError: (errorString: String, exception: Exception, errorCode: String) -> Unit + lateinit var onVideoProgress: (currentPosition: Long, bufferedDuration: Long, seekableDuration: Long, currentPlaybackTime: Double) -> Unit + lateinit var onVideoBandwidthUpdate: (bitRateEstimate: Long, height: Int, width: Int, trackId: String) -> Unit + lateinit var onVideoPlaybackStateChanged: (isPlaying: Boolean, isSeeking: Boolean) -> Unit + lateinit var onVideoSeek: (currentPosition: Long, seekTime: Long) -> Unit + lateinit var onVideoEnd: () -> Unit + lateinit var onVideoFullscreenPlayerWillPresent: () -> Unit + lateinit var onVideoFullscreenPlayerDidPresent: () -> Unit + lateinit var onVideoFullscreenPlayerWillDismiss: () -> Unit + lateinit var onVideoFullscreenPlayerDidDismiss: () -> Unit + lateinit var onReadyForDisplay: () -> Unit + lateinit var onVideoBuffer: (isBuffering: Boolean) -> Unit + lateinit var onControlsVisibilityChange: (isVisible: Boolean) -> Unit + lateinit var onVideoIdle: () -> Unit + lateinit var onTimedMetadata: (metadataArrayList: ArrayList) -> Unit + lateinit var onVideoAudioBecomingNoisy: () -> Unit + lateinit var onAudioFocusChanged: (hasFocus: Boolean) -> Unit + lateinit var onPlaybackRateChange: (rate: Float) -> Unit + lateinit var onVolumeChange: (volume: Float) -> Unit + lateinit var onAudioTracks: (audioTracks: List, selectedTrack: TrackInfo?, manifest: Any?) -> Unit + lateinit var onTextTracks: (textTracks: List, selectedTrack: TrackInfo?) -> Unit + lateinit var onVideoTracks: (videoTracks: List, selectedTrack: TrackInfo?, manifest: Any?) -> Unit + lateinit var onTextTrackDataChanged: (textTrackData: String) -> Unit + lateinit var onReceiveAdEvent: (adEvent: String, adData: Map?) -> Unit + + fun addEventEmitters(reactContext: ThemedReactContext, view: ReactExoplayerView) { + val dispatcher = UIManagerHelper.getEventDispatcherForReactTag(reactContext, view.id) + val surfaceId = UIManagerHelper.getSurfaceId(reactContext) + + if (dispatcher != null) { + val event = EventBuilder(surfaceId, view.id, dispatcher) + + onVideoLoadStart = { + event.dispatch(EventTypes.EVENT_LOAD_START) + } + onVideoLoad = { duration, currentPosition, videoWidth, videoHeight, audioTracks, textTracks, videoTracks, manifest, trackId -> + event.dispatch(EventTypes.EVENT_LOAD) { + putOnLoadData(duration, currentPosition, videoWidth, videoHeight, audioTracks, textTracks, videoTracks, manifest, trackId) + } + } + onVideoError = { errorString, exception, errorCode -> + event.dispatch(EventTypes.EVENT_ERROR) { + putMap( + "error", + Arguments.createMap().apply { + // Prepare stack trace + val sw = StringWriter() + val pw = PrintWriter(sw) + exception.printStackTrace(pw) + val stackTrace = sw.toString() + + putString("errorString", errorString) + putString("errorException", exception.toString()) + putString("errorCode", errorCode) + putString("errorStackTrace", stackTrace) + } + ) + } + } + onVideoProgress = { currentPosition, bufferedDuration, seekableDuration, currentPlaybackTime -> + event.dispatch(EventTypes.EVENT_PROGRESS) { + putDouble("currentTime", currentPosition / 1000.0) + putDouble("playableDuration", bufferedDuration / 1000.0) + putDouble("seekableDuration", seekableDuration / 1000.0) + putDouble("currentPlaybackTime", currentPlaybackTime) + } + } + onVideoBandwidthUpdate = { bitRateEstimate, height, width, trackId -> + event.dispatch(EventTypes.EVENT_BANDWIDTH) { + putDouble("bitrate", bitRateEstimate.toDouble()) + putInt("width", width) + putInt("height", height) + putString("trackId", trackId) + } + } + onVideoPlaybackStateChanged = { isPlaying, isSeeking -> + event.dispatch(EventTypes.EVENT_PLAYBACK_STATE_CHANGED) { + putBoolean("isPlaying", isPlaying) + putBoolean("isSeeking", isSeeking) + } + } + onVideoSeek = { currentPosition, seekTime -> + event.dispatch(EventTypes.EVENT_SEEK) { + putDouble("currentTime", currentPosition / 1000.0) + putDouble("seekTime", seekTime / 1000.0) + } + } + onVideoEnd = { + event.dispatch(EventTypes.EVENT_END) + } + onVideoFullscreenPlayerWillPresent = { + event.dispatch(EventTypes.EVENT_FULLSCREEN_WILL_PRESENT) + } + onVideoFullscreenPlayerDidPresent = { + event.dispatch(EventTypes.EVENT_FULLSCREEN_DID_PRESENT) + } + onVideoFullscreenPlayerWillDismiss = { + event.dispatch(EventTypes.EVENT_FULLSCREEN_WILL_DISMISS) + } + onVideoFullscreenPlayerDidDismiss = { + event.dispatch(EventTypes.EVENT_FULLSCREEN_DID_DISMISS) + } + onReadyForDisplay = { + event.dispatch(EventTypes.EVENT_READY) + } + onVideoBuffer = { isBuffering -> + event.dispatch(EventTypes.EVENT_BUFFER) { + putBoolean("isBuffering", isBuffering) + } + } + onControlsVisibilityChange = { isVisible -> + event.dispatch(EventTypes.EVENT_CONTROLS_VISIBILITY_CHANGE) { + putBoolean("isVisible", isVisible) + } + } + onVideoIdle = { + event.dispatch(EventTypes.EVENT_IDLE) + } + onTimedMetadata = fn@{ metadataArrayList -> + if (metadataArrayList.size == 0) { + return@fn + } + event.dispatch(EventTypes.EVENT_TIMED_METADATA) { + putArray( + "metadata", + Arguments.createArray().apply { + metadataArrayList.forEachIndexed { i, metadata -> + pushMap( + Arguments.createMap().apply { + putString("identifier", metadata.identifier) + putString("value", metadata.value) + } + ) + } + } + ) + } + } + onVideoAudioBecomingNoisy = { + event.dispatch(EventTypes.EVENT_AUDIO_BECOMING_NOISY) + } + onAudioFocusChanged = { hasFocus -> + event.dispatch(EventTypes.EVENT_AUDIO_FOCUS_CHANGE) { + putBoolean("hasAudioFocus", hasFocus) + } + } + onPlaybackRateChange = { rate -> + event.dispatch(EventTypes.EVENT_PLAYBACK_RATE_CHANGE) { + putDouble("playbackRate", rate.toDouble()) + } + } + onVolumeChange = { volume -> + event.dispatch(EventTypes.EVENT_VOLUME_CHANGE) { + putDouble("volume", volume.toDouble()) + } + } + onAudioTracks = { audioTracks, selectedTrack, manifest -> + event.dispatch(EventTypes.EVENT_AUDIO_TRACKS) { + putAudioTracksData(audioTracks, selectedTrack, manifest) + } + } + onTextTracks = { textTracks, selectedTrack -> + event.dispatch(EventTypes.EVENT_TEXT_TRACKS) { + putTextTracksData(textTracks, selectedTrack) + } + } + onVideoTracks = { videoTracks, selectedTrack, manifest -> + event.dispatch(EventTypes.EVENT_VIDEO_TRACKS) { + putVideoTracksData(videoTracks, selectedTrack, manifest) + } + } + onTextTrackDataChanged = { textTrackData -> + event.dispatch(EventTypes.EVENT_TEXT_TRACK_DATA_CHANGED) { + putString("subtitleTracks", textTrackData) + } + } + onReceiveAdEvent = { adEvent, adData -> + event.dispatch(EventTypes.EVENT_ON_RECEIVE_AD_EVENT) { + putString("event", adEvent) + putMap( + "data", + Arguments.createMap().apply { + adData?.let { data -> + for ((key, value) in data) { + putString(key!!, value) + } + } + } + ) + } + } + } + } + + private fun WritableMap.putOnLoadData( + duration: Long, + currentPosition: Long, + videoWidth: Int, + videoHeight: Int, + audioTracks: List, + textTracks: List, + videoTracks: List, + manifest: Any?, + trackId: String + ) = apply { + putDouble("duration", duration / 1000.0) + putDouble("currentTime", currentPosition / 1000.0) + + val naturalSize: WritableMap = aspectRatioToNaturalSize(videoWidth, videoHeight) + putMap("naturalSize", naturalSize) + putString("trackId", trackId) + putArray("videoTracks", Arguments.makeNativeArray(videoTracks.map { createVideoTrackInfo(it, false, manifest) })) + putArray("audioTracks", Arguments.makeNativeArray(audioTracks.map { createAudioTrackInfo(it, false, manifest) })) + putArray("textTracks", Arguments.makeNativeArray(textTracks.map { createTextTrackInfo(it, false) })) + + // TODO: Actually check if you can. + putBoolean("canPlayFastForward", true) + putBoolean("canPlaySlowForward", true) + putBoolean("canPlaySlowReverse", true) + putBoolean("canPlayReverse", true) + putBoolean("canPlayFastForward", true) + putBoolean("canStepBackward", true) + putBoolean("canStepForward", true) + } + + private fun WritableMap.putAudioTracksData(audioTracks: List, selectedTrack: TrackInfo?, manifest: Any?): WritableMap = + apply { + audioTracks + .map { track -> + val selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex + createAudioTrackInfo(track, selected, manifest) + } + .let { putArray("audioTracks", Arguments.makeNativeArray(it)) } + } + + private fun WritableMap.putVideoTracksData(videoTracks: List, selectedTrack: TrackInfo?, manifest: Any?): WritableMap = + apply { + videoTracks + .map { track -> + val selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex + createVideoTrackInfo(track, selected, manifest) + } + .let { putArray("videoTracks", Arguments.makeNativeArray(it)) } + } + + private fun WritableMap.putTextTracksData(textTracks: List, selectedTrack: TrackInfo?): WritableMap = + apply { + textTracks + .map { track -> + val selected = selectedTrack != null && selectedTrack.complexIndex == track.complexIndex + createTextTrackInfo(track, selected) + } + .let { putArray("textTracks", Arguments.makeNativeArray(it)) } + } + + private class EventBuilder(private val surfaceId: Int, private val viewId: Int, private val dispatcher: EventDispatcher) { + fun dispatch(event: EventTypes, paramsSetter: (WritableMap.() -> Unit)? = null) = + dispatcher.dispatchEvent(object : Event>(surfaceId, viewId) { + override fun getEventName() = "top${event.eventName.removePrefix("on")}" + override fun getEventData() = Arguments.createMap().apply(paramsSetter ?: {}) + }) + } + + private fun aspectRatioToNaturalSize(videoWidth: Int, videoHeight: Int): WritableMap = + Arguments.createMap().apply { + putInt("width", videoWidth) + putInt("height", videoHeight) + val orientation = if (videoWidth > videoHeight) { + "landscape" + } else if (videoWidth < videoHeight) { + "portrait" + } else { + "square" + } + putString("orientation", orientation) + } + + private fun createAudioTrackInfo(track: TrackInfo?, selected: Boolean, manifest: Any?): WritableMap? { + if (track == null) return null + val complexIndex = track.complexIndex + val format = track.format + val audioTrack = Arguments.createMap() + audioTrack.putDouble("index", complexIndex.toDouble()) + audioTrack.putString("trackId", if (format.id != null) format.id else complexIndex.toString()) + audioTrack.putString("title", getLanguageDisplayName(format.language)) + audioTrack.putString("type", format.sampleMimeType) + audioTrack.putString("language", format.language) + audioTrack.putInt("bitrate", if (format.bitrate == Format.NO_VALUE) 0 else format.bitrate) + audioTrack.putString("codecs", format.codecs) + audioTrack.putString("channels", (if (format.channelCount != Format.NO_VALUE) format.channelCount else 0).toString()) + audioTrack.putBoolean("selected", selected) + if (manifest != null) { + val representation = getRepresentationOf(manifest, track) + audioTrack.putString("file", getRepresentationFileName(representation)) + audioTrack.putString("supplementalProperties", getRepresentationSupplementalProperties(representation)) + } + return audioTrack + } + + private fun createVideoTrackInfo(track: TrackInfo?, selected: Boolean, manifest: Any?): WritableMap? { + if (track == null) return null + val complexIndex = track.complexIndex + val format = track.format + val videoTrack = Arguments.createMap() + videoTrack.putDouble("index", complexIndex.toDouble()) + videoTrack.putString("trackId", if (format.id != null) format.id else complexIndex.toString()) + videoTrack.putInt("width", if (format.width == Format.NO_VALUE) 0 else format.width) + videoTrack.putInt("height", if (format.height == Format.NO_VALUE) 0 else format.height) + videoTrack.putInt("bitrate", if (format.bitrate == Format.NO_VALUE) 0 else format.bitrate) + videoTrack.putString("codecs", format.codecs) + videoTrack.putBoolean("selected", selected) + videoTrack.putInt("rotation", format.rotationDegrees) + if (manifest != null) { + val representation = getRepresentationOf(manifest, track) + videoTrack.putString("file", getRepresentationFileName(representation)) + videoTrack.putString("supplementalProperties", getRepresentationSupplementalProperties(representation)) + } + return videoTrack + } + + private fun createTextTrackInfo(track: TrackInfo?, selected: Boolean): WritableMap? { + if (track == null) return null + val complexIndex = track.complexIndex + val format = track.format + val textTrack = Arguments.createMap() + textTrack.putDouble("index", complexIndex.toDouble()) + textTrack.putString("trackId", if (format.id != null) format.id else complexIndex.toString()) + textTrack.putString("title", getLanguageDisplayName(format.language)) + textTrack.putString("type", format.sampleMimeType) + textTrack.putString("language", format.language) + textTrack.putBoolean("selected", selected) + return textTrack + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java b/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java deleted file mode 100644 index 261f185ddb..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.brentvatne.exoplayer; - -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -import com.brentvatne.common.api.ResizeMode; - -/** - * A {@link FrameLayout} that resizes itself to match a specified aspect ratio. - */ -public final class AspectRatioFrameLayout extends FrameLayout { - - /** - * The {@link FrameLayout} will not resize itself if the fractional difference between its natural - * aspect ratio and the requested aspect ratio falls below this threshold. - *

- * This tolerance allows the view to occupy the whole of the screen when the requested aspect - * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce - * the number of view layers that need to be composited by the underlying system, which can help - * to reduce power consumption. - */ - private static final float MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f; - - private float videoAspectRatio; - private @ResizeMode.Mode int resizeMode = ResizeMode.RESIZE_MODE_FIT; - - public AspectRatioFrameLayout(Context context) { - this(context, null); - } - - public AspectRatioFrameLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - /** - * Set the aspect ratio that this view should satisfy. - * - * @param widthHeightRatio The width to height ratio. - */ - public void setAspectRatio(float widthHeightRatio) { - if (this.videoAspectRatio != widthHeightRatio) { - this.videoAspectRatio = widthHeightRatio; - requestLayout(); - } - } - - /** - * Get the aspect ratio that this view should satisfy. - * - * @return widthHeightRatio The width to height ratio. - */ - public float getAspectRatio() { - return videoAspectRatio; - } - - public void invalidateAspectRatio() { - videoAspectRatio = 0; - } - - /** - * Sets the resize mode which can be of value {@link ResizeMode.Mode} - * - * @param resizeMode The resize mode. - */ - public void setResizeMode(@ResizeMode.Mode int resizeMode) { - if (this.resizeMode != resizeMode) { - this.resizeMode = resizeMode; - requestLayout(); - } - } - - /** - * Gets the resize mode which can be of value {@link ResizeMode.Mode} - * - * @return resizeMode The resize mode. - */ - public @ResizeMode.Mode int getResizeMode() { - return resizeMode; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - if (videoAspectRatio == 0) { - // Aspect ratio not set. - return; - } - - int measuredWidth = getMeasuredWidth(); - int measuredHeight = getMeasuredHeight(); - int width = measuredWidth; - int height = measuredHeight; - - float viewAspectRatio = (float) measuredWidth / measuredHeight; - float aspectDeformation = videoAspectRatio / viewAspectRatio - 1; - if (Math.abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) { - // We're within the allowed tolerance. - return; - } - - switch (resizeMode) { - case ResizeMode.RESIZE_MODE_FIXED_WIDTH: - height = (int) (measuredWidth / videoAspectRatio); - break; - case ResizeMode.RESIZE_MODE_FIXED_HEIGHT: - width = (int) (measuredHeight * videoAspectRatio); - break; - case ResizeMode.RESIZE_MODE_FILL: - // Do nothing width and height is the same as the view - break; - case ResizeMode.RESIZE_MODE_CENTER_CROP: - width = (int) (measuredHeight * videoAspectRatio); - - // Scale video if it doesn't fill the measuredWidth - if (width < measuredWidth) { - float scaleFactor = (float) measuredWidth / width; - width = (int) (width * scaleFactor); - height = (int) (measuredHeight * scaleFactor); - } - break; - default: - if (aspectDeformation > 0) { - height = (int) (measuredWidth / videoAspectRatio); - } else { - width = (int) (measuredHeight * videoAspectRatio); - } - break; - } - super.onMeasure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY)); - } - -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.kt b/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.kt new file mode 100644 index 0000000000..834e5e0c93 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/AspectRatioFrameLayout.kt @@ -0,0 +1,97 @@ +package com.brentvatne.exoplayer + +import android.content.Context +import android.widget.FrameLayout +import com.brentvatne.common.api.ResizeMode +import kotlin.math.abs + +/** + * A {@link FrameLayout} that resizes itself to match a specified aspect ratio. + */ +class AspectRatioFrameLayout(context: Context) : FrameLayout(context) { + /** + * The {@link FrameLayout} will not resize itself if the fractional difference between its natural + * aspect ratio and the requested aspect ratio falls below this threshold. + *

+ * This tolerance allows the view to occupy the whole of the screen when the requested aspect + * ratio is very close, but not exactly equal to, the aspect ratio of the screen. This may reduce + * the number of view layers that need to be composited by the underlying system, which can help + * to reduce power consumption. + */ + companion object { + private const val MAX_ASPECT_RATIO_DEFORMATION_FRACTION = 0.01f + } + + var videoAspectRatio: Float = 0f + set(value) { + if (value != field) { + field = value + requestLayout() + } + } + + var resizeMode: Int = ResizeMode.RESIZE_MODE_FIT + set(value) { + if (value != field) { + field = value + requestLayout() + } + } + + fun invalidateAspectRatio() { + videoAspectRatio = 0f + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec) + if (videoAspectRatio == 0f) { + // Aspect ratio not set. + return + } + + val measuredWidth: Int = measuredWidth + val measuredHeight: Int = measuredHeight + var width: Int = measuredWidth + var height: Int = measuredHeight + + val viewAspectRatio: Float = measuredWidth.toFloat() / measuredHeight + val aspectDeformation: Float = videoAspectRatio / viewAspectRatio - 1 + if (abs(aspectDeformation) <= MAX_ASPECT_RATIO_DEFORMATION_FRACTION) { + // We're within the allowed tolerance. + return + } + + when (resizeMode) { + ResizeMode.RESIZE_MODE_FIXED_WIDTH -> height = (measuredWidth / videoAspectRatio).toInt() + + ResizeMode.RESIZE_MODE_FIXED_HEIGHT -> width = ((measuredHeight * videoAspectRatio).toInt()) + + ResizeMode.RESIZE_MODE_FILL -> { + // Do nothing width and height is the same as the view + } + + ResizeMode.RESIZE_MODE_CENTER_CROP -> { + width = (measuredHeight * videoAspectRatio).toInt() + + // Scale video if it doesn't fill the measuredWidth + if (width < measuredWidth) { + val scaleFactor: Int = measuredWidth / width + width *= scaleFactor + height = measuredHeight * scaleFactor + } + } + + else -> { + if (aspectDeformation > 0) { + height = (measuredWidth / videoAspectRatio).toInt() + } else { + width = (measuredHeight * videoAspectRatio).toInt() + } + } + } + super.onMeasure( + MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY) + ) + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.java b/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.java deleted file mode 100644 index 90cd4f457c..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.brentvatne.exoplayer; - -import android.annotation.SuppressLint; - -import androidx.annotation.NonNull; -import androidx.media3.common.C; - -@SuppressLint("InlinedApi") -public enum AudioOutput { - SPEAKER("speaker", C.STREAM_TYPE_MUSIC), - EARPIECE("earpiece", C.STREAM_TYPE_VOICE_CALL); - - private final @C.StreamType int streamType; - private final String mName; - - AudioOutput(final String name, @C.StreamType int stream) { - mName = name; - streamType = stream; - } - - public static AudioOutput get(String name) { - for (AudioOutput d : values()) { - if (d.mName.equalsIgnoreCase(name)) - return d; - } - return SPEAKER; - } - - public int getStreamType() { - return streamType; - } - - @NonNull - @Override - public String toString() { - return getClass().getSimpleName() + "(" + this.mName + ", " + streamType + ")"; - } -} \ No newline at end of file diff --git a/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.kt b/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.kt new file mode 100644 index 0000000000..44e44bc2ef --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/AudioOutput.kt @@ -0,0 +1,25 @@ +package com.brentvatne.exoplayer + +import android.annotation.SuppressLint +import androidx.media3.common.C + +@SuppressLint("InlinedApi") +enum class AudioOutput(private val outputName: String, @C.StreamType val streamType: Int) { + + SPEAKER("speaker", C.STREAM_TYPE_MUSIC), + EARPIECE("earpiece", C.STREAM_TYPE_VOICE_CALL); + + companion object { + @JvmStatic + fun get(name: String): AudioOutput { + for (entry in values()) { + if (entry.outputName.equals(name, ignoreCase = true)) { + return entry + } + } + return SPEAKER + } + } + + override fun toString(): String = "${javaClass.simpleName}($outputName, $streamType)" +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java deleted file mode 100644 index 5a0378960f..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.brentvatne.exoplayer; - -import android.net.Uri; - -import androidx.annotation.NonNull; -import androidx.media3.common.util.Util; -import androidx.media3.datasource.AssetDataSource; -import androidx.media3.datasource.DataSource; -import androidx.media3.datasource.DataSpec; -import androidx.media3.datasource.DefaultDataSource; -import androidx.media3.datasource.HttpDataSource; -import androidx.media3.datasource.okhttp.OkHttpDataSource; -import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter; - -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.network.CookieJarContainer; -import com.facebook.react.modules.network.ForwardingCookieHandler; -import com.facebook.react.modules.network.OkHttpClientProvider; - -import java.util.Map; - -import okhttp3.Call; -import okhttp3.JavaNetCookieJar; -import okhttp3.OkHttpClient; - -public class DataSourceUtil { - - private DataSourceUtil() { - } - - private static DataSource.Factory defaultDataSourceFactory = null; - private static HttpDataSource.Factory defaultHttpDataSourceFactory = null; - private static String userAgent = null; - - public static void setUserAgent(String userAgent) { - DataSourceUtil.userAgent = userAgent; - } - - public static String getUserAgent(ReactContext context) { - if (userAgent == null) { - userAgent = Util.getUserAgent(context, context.getPackageName()); - } - return userAgent; - } - - public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { - defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders); - } - return defaultDataSourceFactory; - } - - public static HttpDataSource.Factory getDefaultHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - if (defaultHttpDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) { - defaultHttpDataSourceFactory = buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders); - } - return defaultHttpDataSourceFactory; - } - - private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - return new DefaultDataSource.Factory(context, buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders)); - } - - private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map requestHeaders) { - OkHttpClient client = OkHttpClientProvider.getOkHttpClient(); - CookieJarContainer container = (CookieJarContainer) client.cookieJar(); - ForwardingCookieHandler handler = new ForwardingCookieHandler(context); - container.setCookieJar(new JavaNetCookieJar(handler)); - OkHttpDataSource.Factory okHttpDataSourceFactory = new OkHttpDataSource.Factory((Call.Factory) client) - .setTransferListener(bandwidthMeter); - - if (requestHeaders != null) { - okHttpDataSourceFactory.setDefaultRequestProperties(requestHeaders); - if (!requestHeaders.containsKey("User-Agent")) { - okHttpDataSourceFactory.setUserAgent(getUserAgent(context)); - } - } else { - okHttpDataSourceFactory.setUserAgent(getUserAgent(context)); - } - - return okHttpDataSourceFactory; - } - - public static DataSource.Factory buildAssetDataSourceFactory(ReactContext context, Uri srcUri) throws AssetDataSource.AssetDataSourceException { - DataSpec dataSpec = new DataSpec(srcUri); - final AssetDataSource rawResourceDataSource = new AssetDataSource(context); - rawResourceDataSource.open(dataSpec); - return new DataSource.Factory() { - @NonNull - @Override - public DataSource createDataSource() { - return rawResourceDataSource; - } - }; - } -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.kt b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.kt new file mode 100644 index 0000000000..96a7887da5 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.kt @@ -0,0 +1,88 @@ +package com.brentvatne.exoplayer + +import android.net.Uri +import androidx.media3.common.util.Util +import androidx.media3.datasource.AssetDataSource +import androidx.media3.datasource.DataSource +import androidx.media3.datasource.DataSpec +import androidx.media3.datasource.DefaultDataSource +import androidx.media3.datasource.HttpDataSource +import androidx.media3.datasource.okhttp.OkHttpDataSource +import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter +import com.facebook.react.bridge.ReactContext +import com.facebook.react.modules.network.CookieJarContainer +import com.facebook.react.modules.network.ForwardingCookieHandler +import com.facebook.react.modules.network.OkHttpClientProvider +import okhttp3.Call +import okhttp3.JavaNetCookieJar + +object DataSourceUtil { + private var defaultDataSourceFactory: DataSource.Factory? = null + private var defaultHttpDataSourceFactory: HttpDataSource.Factory? = null + private var userAgent: String? = null + + private fun getUserAgent(context: ReactContext): String { + if (userAgent == null) { + userAgent = Util.getUserAgent(context, context.packageName) + } + return userAgent as String + } + + @JvmStatic + fun getDefaultDataSourceFactory(context: ReactContext, bandwidthMeter: DefaultBandwidthMeter?, requestHeaders: Map?): DataSource.Factory { + if (defaultDataSourceFactory == null || !requestHeaders.isNullOrEmpty()) { + defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders) + } + return defaultDataSourceFactory as DataSource.Factory + } + + @JvmStatic + fun getDefaultHttpDataSourceFactory( + context: ReactContext, + bandwidthMeter: DefaultBandwidthMeter?, + requestHeaders: Map? + ): HttpDataSource.Factory { + if (defaultHttpDataSourceFactory == null || !requestHeaders.isNullOrEmpty()) { + defaultHttpDataSourceFactory = buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders) + } + return defaultHttpDataSourceFactory as HttpDataSource.Factory + } + + private fun buildDataSourceFactory( + context: ReactContext, + bandwidthMeter: DefaultBandwidthMeter?, + requestHeaders: Map? + ): DataSource.Factory = DefaultDataSource.Factory(context, buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders)) + + private fun buildHttpDataSourceFactory( + context: ReactContext, + bandwidthMeter: DefaultBandwidthMeter?, + requestHeaders: Map? + ): HttpDataSource.Factory { + val client = OkHttpClientProvider.getOkHttpClient() + val container = client.cookieJar as CookieJarContainer + val handler = ForwardingCookieHandler(context) + container.setCookieJar(JavaNetCookieJar(handler)) + val okHttpDataSourceFactory = OkHttpDataSource.Factory(client as Call.Factory) + .setTransferListener(bandwidthMeter) + + if (requestHeaders != null) { + okHttpDataSourceFactory.setDefaultRequestProperties(requestHeaders) + if (!requestHeaders.containsKey("User-Agent")) { + okHttpDataSourceFactory.setUserAgent(getUserAgent(context)) + } + } else { + okHttpDataSourceFactory.setUserAgent(getUserAgent(context)) + } + + return okHttpDataSourceFactory + } + + @JvmStatic + fun buildAssetDataSourceFactory(context: ReactContext?, srcUri: Uri?): DataSource.Factory { + val dataSpec = DataSpec(srcUri!!) + val rawResourceDataSource = AssetDataSource(context!!) + rawResourceDataSource.open(dataSpec) + return DataSource.Factory { rawResourceDataSource } + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java b/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java deleted file mode 100644 index 2a9b640e11..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.java +++ /dev/null @@ -1,38 +0,0 @@ -package com.brentvatne.exoplayer; - -import android.content.Context; - -import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter; -import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; -import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; - -public class DefaultReactExoplayerConfig implements ReactExoplayerConfig { - - private final DefaultBandwidthMeter bandwidthMeter; - private boolean disableDisconnectError = false; - - public DefaultReactExoplayerConfig(Context context) { - this.bandwidthMeter = new DefaultBandwidthMeter.Builder(context).build(); - } - - public LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount) { - if (this.disableDisconnectError) { - // Use custom error handling policy to prevent throwing an error when losing network connection - return new ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount); - } - return new DefaultLoadErrorHandlingPolicy(minLoadRetryCount); - } - - public void setDisableDisconnectError(boolean disableDisconnectError) { - this.disableDisconnectError = disableDisconnectError; - } - - public boolean getDisableDisconnectError() { - return this.disableDisconnectError; - } - - @Override - public DefaultBandwidthMeter getBandwidthMeter() { - return bandwidthMeter; - } -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.kt b/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.kt new file mode 100644 index 0000000000..12c0ddf8e9 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/DefaultReactExoplayerConfig.kt @@ -0,0 +1,21 @@ +package com.brentvatne.exoplayer + +import android.content.Context +import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter +import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy +import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy + +class DefaultReactExoplayerConfig(context: Context) : ReactExoplayerConfig { + + private var bandWidthMeter: DefaultBandwidthMeter = DefaultBandwidthMeter.Builder(context).build() + override var disableDisconnectError: Boolean = false + override val bandwidthMeter: DefaultBandwidthMeter + get() = bandWidthMeter + + override fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy = + if (disableDisconnectError) { + ReactExoplayerLoadErrorHandlingPolicy(minLoadRetryCount) + } else { + DefaultLoadErrorHandlingPolicy(minLoadRetryCount) + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java index f05cfbe2e3..256392e641 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java @@ -1,5 +1,6 @@ package com.brentvatne.exoplayer; +import android.annotation.SuppressLint; import static androidx.media3.common.text.Cue.DIMEN_UNSET; import static androidx.media3.common.text.Cue.LINE_TYPE_NUMBER; import static androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE; @@ -30,15 +31,26 @@ import androidx.media3.ui.CaptionStyleCompat; import androidx.media3.ui.SubtitleView; +import android.util.TypedValue; +import android.view.Gravity; +import android.view.SurfaceView; +import android.view.TextureView; +import android.view.View; +import android.view.ViewGroup; +import android.widget.FrameLayout; + import com.brentvatne.common.api.ResizeMode; import com.brentvatne.common.api.SubtitleStyle; +import com.brentvatne.common.api.ViewType; +import com.brentvatne.common.toolbox.DebugLog; import com.google.common.collect.ImmutableList; import java.util.ArrayList; import java.util.List; +@SuppressLint("ViewConstructor") public final class ExoPlayerView extends FrameLayout implements AdViewProvider { - + private final static String TAG = "ExoPlayerView"; private View surfaceView; private final View shutterView; private final SubtitleView subtitleLayout; @@ -49,22 +61,13 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { private final ViewGroup.LayoutParams layoutParams; private final FrameLayout adOverlayFrameLayout; - private boolean useTextureView = true; - private boolean useSecureView = false; + private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE; private boolean hideShutterView = false; private boolean subtitleLinesRespected = false; public ExoPlayerView(Context context) { - this(context, null); - } - - public ExoPlayerView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public ExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); + super(context, null, 0); this.context = context; @@ -90,7 +93,7 @@ public ExoPlayerView(Context context, AttributeSet attrs, int defStyleAttr) { subtitleLayout.setUserDefaultStyle(); subtitleLayout.setUserDefaultTextSize(); - updateSurfaceView(); + updateSurfaceView(viewType); adOverlayFrameLayout = new FrameLayout(context); @@ -159,28 +162,36 @@ public void setShutterColor(Integer color) { shutterView.setBackgroundColor(color); } - private void updateSurfaceView() { - View view; - if (!useTextureView || useSecureView) { - view = new SurfaceView(context); - if (useSecureView) { - ((SurfaceView)view).setSecure(true); + public void updateSurfaceView(@ViewType.ViewType int viewType) { + this.viewType = viewType; + boolean viewNeedRefresh = false; + if (viewType == ViewType.VIEW_TYPE_SURFACE || viewType == ViewType.VIEW_TYPE_SURFACE_SECURE) { + if (!(surfaceView instanceof SurfaceView)) { + surfaceView = new SurfaceView(context); + viewNeedRefresh = true; + } + ((SurfaceView)surfaceView).setSecure(viewType == ViewType.VIEW_TYPE_SURFACE_SECURE); + } else if (viewType == ViewType.VIEW_TYPE_TEXTURE) { + if (!(surfaceView instanceof TextureView)) { + surfaceView = new TextureView(context); + viewNeedRefresh = true; } - } else { - view = new TextureView(context); // Support opacity properly: - ((TextureView) view).setOpaque(false); + ((TextureView) surfaceView).setOpaque(false); + } else { + DebugLog.wtf(TAG, "wtf is this texture " + viewType); } - view.setLayoutParams(layoutParams); + if (viewNeedRefresh) { + surfaceView.setLayoutParams(layoutParams); - surfaceView = view; - if (layout.getChildAt(0) != null) { - layout.removeViewAt(0); - } - layout.addView(surfaceView, 0, layoutParams); + if (layout.getChildAt(0) != null) { + layout.removeViewAt(0); + } + layout.addView(surfaceView, 0, layoutParams); - if (this.player != null) { - setVideoView(); + if (this.player != null) { + setVideoView(); + } } } @@ -230,26 +241,12 @@ public void setPlayer(ExoPlayer player) { * @param resizeMode The resize mode. */ public void setResizeMode(@ResizeMode.Mode int resizeMode) { - if (layout.getResizeMode() != resizeMode) { + if (layout != null && layout.getResizeMode() != resizeMode) { layout.setResizeMode(resizeMode); post(measureAndLayout); } } - public void setUseTextureView(boolean useTextureView) { - if (useTextureView != this.useTextureView) { - this.useTextureView = useTextureView; - updateSurfaceView(); - } - } - - public void useSecureView(boolean useSecureView) { - if (useSecureView != this.useSecureView) { - this.useSecureView = useSecureView; - updateSurfaceView(); - } - } - public void setHideShutterView(boolean hideShutterView) { this.hideShutterView = hideShutterView; updateShutterViewVisibility(); @@ -272,8 +269,16 @@ private void updateForCurrentTrackSelections(Tracks tracks) { // get the first track of the group to identify aspect ratio Format format = group.getTrackFormat(0); - // update aspect ratio ! - layout.setAspectRatio(format.height == 0 ? 1 : (format.width * format.pixelWidthHeightRatio) / format.height); + // There are weird cases when video height and width did not change with rotation so we need change aspect ration to fix it + switch (format.rotationDegrees) { + // update aspect ratio ! + case 90, 270 -> { + layout.setVideoAspectRatio(format.width == 0 ? 1 : (format.height * format.pixelWidthHeightRatio) / format.width); + } + default -> { + layout.setVideoAspectRatio(format.height == 0 ? 1 : (format.width * format.pixelWidthHeightRatio) / format.height); + } + } return; } } @@ -302,13 +307,13 @@ public void onCues(@NonNull CueGroup cueGroup) { @Override public void onVideoSizeChanged(VideoSize videoSize) { - boolean isInitialRatio = layout.getAspectRatio() == 0; + boolean isInitialRatio = layout.getVideoAspectRatio() == 0; if (videoSize.height == 0 || videoSize.width == 0) { // When changing video track we receive an ghost state with height / width = 0 // No need to resize the view in that case return; } - layout.setAspectRatio((videoSize.width * videoSize.pixelWidthHeightRatio) / videoSize.height); + layout.setVideoAspectRatio((videoSize.width * videoSize.pixelWidthHeightRatio) / videoSize.height); // React native workaround for measuring and layout on initial load. if (isInitialRatio) { diff --git a/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.java deleted file mode 100644 index b5d170a06b..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.java +++ /dev/null @@ -1,136 +0,0 @@ -package com.brentvatne.exoplayer; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.Context; -import android.os.Handler; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageButton; - -import androidx.activity.OnBackPressedCallback; -import androidx.media3.ui.LegacyPlayerControlView; - -import com.brentvatne.common.toolbox.DebugLog; - -import java.lang.ref.WeakReference; - -@SuppressLint("PrivateResource") -public class FullScreenPlayerView extends Dialog { - private final LegacyPlayerControlView playerControlView; - private final ExoPlayerView exoPlayerView; - private final ReactExoplayerView reactExoplayerView; - private ViewGroup parent; - private final FrameLayout containerView; - private final OnBackPressedCallback onBackPressedCallback; - private final Handler mKeepScreenOnHandler; - private final Runnable mKeepScreenOnUpdater; - - private static class KeepScreenOnUpdater implements Runnable { - private final static long UPDATE_KEEP_SCREEN_ON_FLAG_MS = 200; - private final WeakReference mFullscreenPlayer; - - KeepScreenOnUpdater(FullScreenPlayerView player) { - mFullscreenPlayer = new WeakReference<>(player); - } - - @Override - public void run() { - try { - FullScreenPlayerView fullscreenVideoPlayer = mFullscreenPlayer.get(); - if (fullscreenVideoPlayer != null) { - final Window window = fullscreenVideoPlayer.getWindow(); - if (window != null) { - boolean isPlaying = fullscreenVideoPlayer.exoPlayerView.isPlaying(); - if (isPlaying) { - window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } else { - window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - } - fullscreenVideoPlayer.mKeepScreenOnHandler.postDelayed(this, UPDATE_KEEP_SCREEN_ON_FLAG_MS); - } - } catch (Exception ex) { - DebugLog.e("ExoPlayer Exception", "Failed to flag FLAG_KEEP_SCREEN_ON on fullscreeen."); - DebugLog.e("ExoPlayer Exception", ex.toString()); - } - } - } - - public FullScreenPlayerView(Context context, ExoPlayerView exoPlayerView, ReactExoplayerView reactExoplayerView, LegacyPlayerControlView playerControlView, OnBackPressedCallback onBackPressedCallback) { - super(context, android.R.style.Theme_Black_NoTitleBar_Fullscreen); - this.playerControlView = playerControlView; - this.exoPlayerView = exoPlayerView; - this.reactExoplayerView = reactExoplayerView; - this.onBackPressedCallback = onBackPressedCallback; - containerView = new FrameLayout(context); - setContentView(containerView, generateDefaultLayoutParams()); - - mKeepScreenOnUpdater = new KeepScreenOnUpdater(this); - mKeepScreenOnHandler = new Handler(); - } - - @Override - public void onBackPressed() { - super.onBackPressed(); - onBackPressedCallback.handleOnBackPressed(); - } - - @Override - protected void onStart() { - parent = (FrameLayout)(exoPlayerView.getParent()); - - parent.removeView(exoPlayerView); - containerView.addView(exoPlayerView, generateDefaultLayoutParams()); - - if (playerControlView != null) { - ImageButton imageButton = playerControlView.findViewById(com.brentvatne.react.R.id.exo_fullscreen); - imageButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_exit); - imageButton.setContentDescription(getContext().getString(androidx.media3.ui.R.string.exo_controls_fullscreen_exit_description)); - parent.removeView(playerControlView); - containerView.addView(playerControlView, generateDefaultLayoutParams()); - } - - super.onStart(); - } - - @Override - protected void onStop() { - mKeepScreenOnHandler.removeCallbacks(mKeepScreenOnUpdater); - containerView.removeView(exoPlayerView); - parent.addView(exoPlayerView, generateDefaultLayoutParams()); - - if (playerControlView != null) { - ImageButton imageButton = playerControlView.findViewById(com.brentvatne.react.R.id.exo_fullscreen); - imageButton.setImageResource(androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter); - imageButton.setContentDescription(getContext().getString(androidx.media3.ui.R.string.exo_controls_fullscreen_enter_description)); - containerView.removeView(playerControlView); - parent.addView(playerControlView, generateDefaultLayoutParams()); - } - - parent.requestLayout(); - parent = null; - - super.onStop(); - } - - @Override - public void onAttachedToWindow() { - super.onAttachedToWindow(); - - if (reactExoplayerView.getPreventsDisplaySleepDuringVideoPlayback()) { - mKeepScreenOnHandler.post(mKeepScreenOnUpdater); - } - } - - private FrameLayout.LayoutParams generateDefaultLayoutParams() { - FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( - FrameLayout.LayoutParams.MATCH_PARENT, - FrameLayout.LayoutParams.MATCH_PARENT - ); - layoutParams.setMargins(0, 0, 0, 0); - return layoutParams; - } -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.kt b/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.kt new file mode 100644 index 0000000000..00f9397524 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/FullScreenPlayerView.kt @@ -0,0 +1,130 @@ +package com.brentvatne.exoplayer + +import android.annotation.SuppressLint +import android.app.Dialog +import android.content.Context +import android.os.Handler +import android.os.Looper +import android.view.ViewGroup +import android.view.WindowManager +import android.widget.FrameLayout +import android.widget.ImageButton +import androidx.activity.OnBackPressedCallback +import androidx.media3.ui.LegacyPlayerControlView +import com.brentvatne.common.toolbox.DebugLog +import java.lang.ref.WeakReference + +@SuppressLint("PrivateResource") +class FullScreenPlayerView( + context: Context, + private val exoPlayerView: ExoPlayerView, + private val reactExoplayerView: ReactExoplayerView, + private val playerControlView: LegacyPlayerControlView?, + private val onBackPressedCallback: OnBackPressedCallback +) : Dialog(context, android.R.style.Theme_Black_NoTitleBar_Fullscreen) { + + private var parent: ViewGroup? = null + private val containerView = FrameLayout(context) + private val mKeepScreenOnHandler = Handler(Looper.getMainLooper()) + private val mKeepScreenOnUpdater = KeepScreenOnUpdater(this) + + private class KeepScreenOnUpdater(fullScreenPlayerView: FullScreenPlayerView) : Runnable { + private val mFullscreenPlayer = WeakReference(fullScreenPlayerView) + + override fun run() { + try { + val fullscreenVideoPlayer = mFullscreenPlayer.get() + if (fullscreenVideoPlayer != null) { + val window = fullscreenVideoPlayer.window + if (window != null) { + val isPlaying = fullscreenVideoPlayer.exoPlayerView.isPlaying + if (isPlaying) { + window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } else { + window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + } + } + fullscreenVideoPlayer.mKeepScreenOnHandler.postDelayed(this, UPDATE_KEEP_SCREEN_ON_FLAG_MS) + } + } catch (ex: Exception) { + DebugLog.e("ExoPlayer Exception", "Failed to flag FLAG_KEEP_SCREEN_ON on fullscreen.") + DebugLog.e("ExoPlayer Exception", ex.toString()) + } + } + + companion object { + private const val UPDATE_KEEP_SCREEN_ON_FLAG_MS = 200L + } + } + + init { + setContentView(containerView, generateDefaultLayoutParams()) + } + override fun onBackPressed() { + super.onBackPressed() + onBackPressedCallback.handleOnBackPressed() + } + + override fun onStart() { + super.onStart() + parent = exoPlayerView.parent as ViewGroup? + parent?.removeView(exoPlayerView) + containerView.addView(exoPlayerView, generateDefaultLayoutParams()) + playerControlView?.let { + updateFullscreenButton(playerControlView, true) + parent?.removeView(it) + containerView.addView(it, generateDefaultLayoutParams()) + } + } + + override fun onStop() { + super.onStop() + mKeepScreenOnHandler.removeCallbacks(mKeepScreenOnUpdater) + containerView.removeView(exoPlayerView) + parent?.addView(exoPlayerView, generateDefaultLayoutParams()) + playerControlView?.let { + updateFullscreenButton(playerControlView, false) + containerView.removeView(it) + parent?.addView(it, generateDefaultLayoutParams()) + } + parent?.requestLayout() + parent = null + } + + private fun getFullscreenIconResource(isFullscreen: Boolean): Int = + if (isFullscreen) { + androidx.media3.ui.R.drawable.exo_icon_fullscreen_exit + } else { + androidx.media3.ui.R.drawable.exo_icon_fullscreen_enter + } + + private fun updateFullscreenButton(playerControlView: LegacyPlayerControlView, isFullscreen: Boolean) { + val imageButton = playerControlView.findViewById(com.brentvatne.react.R.id.exo_fullscreen) + imageButton?.let { + val imgResource = getFullscreenIconResource(isFullscreen) + val desc = if (isFullscreen) { + context.getString(androidx.media3.ui.R.string.exo_controls_fullscreen_exit_description) + } else { + context.getString(androidx.media3.ui.R.string.exo_controls_fullscreen_enter_description) + } + imageButton.setImageResource(imgResource) + imageButton.contentDescription = desc + } + } + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + if (reactExoplayerView.preventsDisplaySleepDuringVideoPlayback) { + mKeepScreenOnHandler.post(mKeepScreenOnUpdater) + } + } + + private fun generateDefaultLayoutParams(): FrameLayout.LayoutParams { + val layoutParams = FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT + ) + layoutParams.setMargins(0, 0, 0, 0) + return layoutParams + } +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java deleted file mode 100644 index 1abb04089c..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.brentvatne.exoplayer; - -import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter; -import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy; - -/** - * Extension points to configure the Exoplayer instance - */ -public interface ReactExoplayerConfig { - LoadErrorHandlingPolicy buildLoadErrorHandlingPolicy(int minLoadRetryCount); - - void setDisableDisconnectError(boolean disableDisconnectError); - boolean getDisableDisconnectError(); - - DefaultBandwidthMeter getBandwidthMeter(); -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.kt b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.kt new file mode 100644 index 0000000000..6f5e65ba23 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerConfig.kt @@ -0,0 +1,10 @@ +package com.brentvatne.exoplayer + +import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter +import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy + +interface ReactExoplayerConfig { + fun buildLoadErrorHandlingPolicy(minLoadRetryCount: Int): LoadErrorHandlingPolicy + var disableDisconnectError: Boolean + val bandwidthMeter: DefaultBandwidthMeter +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java deleted file mode 100644 index d1793b0bbb..0000000000 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.brentvatne.exoplayer; - -import androidx.media3.common.C; -import androidx.media3.datasource.HttpDataSource.HttpDataSourceException; -import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; - -public final class ReactExoplayerLoadErrorHandlingPolicy extends DefaultLoadErrorHandlingPolicy { - private final int minLoadRetryCount; - - public ReactExoplayerLoadErrorHandlingPolicy(int minLoadRetryCount) { - super(minLoadRetryCount); - this.minLoadRetryCount = minLoadRetryCount; - } - - @Override - public long getRetryDelayMsFor(LoadErrorInfo loadErrorInfo) { - String errorMessage = loadErrorInfo.exception.getMessage(); - - if ( - loadErrorInfo.exception instanceof HttpDataSourceException && - errorMessage != null && (errorMessage.equals("Unable to connect") || errorMessage.equals("Software caused connection abort")) - ) { - // Capture the error we get when there is no network connectivity and keep retrying it - return 1000; // Retry every second - } else if(loadErrorInfo.errorCount < this.minLoadRetryCount) { - return Math.min((loadErrorInfo.errorCount - 1) * 1000, 5000); // Default timeout handling - } else { - return C.TIME_UNSET; // Done retrying and will return the error immediately - } - } - - @Override - public int getMinimumLoadableRetryCount(int dataType) { - return Integer.MAX_VALUE; - } -} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.kt b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.kt new file mode 100644 index 0000000000..8b4cb77d20 --- /dev/null +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerLoadErrorHandlingPolicy.kt @@ -0,0 +1,27 @@ +package com.brentvatne.exoplayer + +import androidx.media3.common.C +import androidx.media3.datasource.HttpDataSource.HttpDataSourceException +import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy +import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy.LoadErrorInfo +import kotlin.math.min + +class ReactExoplayerLoadErrorHandlingPolicy(private val minLoadRetryCount: Int) : DefaultLoadErrorHandlingPolicy(minLoadRetryCount) { + override fun getRetryDelayMsFor(loadErrorInfo: LoadErrorInfo): Long { + val errorMessage: String? = loadErrorInfo.exception.message + + return if (loadErrorInfo.exception is HttpDataSourceException && + errorMessage != null && + (errorMessage == "Unable to connect" || errorMessage == "Software caused connection abort") + ) { + // Capture the error we get when there is no network connectivity and keep retrying it + 1000 // Retry every second + } else if (loadErrorInfo.errorCount < minLoadRetryCount) { + min(((loadErrorInfo.errorCount - 1) * 1000L), 5000L) // Default timeout handling + } else { + C.TIME_UNSET // Done retrying and will return the error immediately + } + } + + override fun getMinimumLoadableRetryCount(dataType: Int): Int = Int.MAX_VALUE +} diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 5836e866c3..7f81f426a3 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -6,7 +6,6 @@ import static androidx.media3.common.C.CONTENT_TYPE_RTSP; import static androidx.media3.common.C.CONTENT_TYPE_SS; import static androidx.media3.common.C.TIME_END_OF_SOURCE; -import static com.brentvatne.exoplayer.DataSourceUtil.buildAssetDataSourceFactory; import android.annotation.SuppressLint; import android.app.Activity; @@ -108,6 +107,7 @@ import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.react.BuildConfig; import com.brentvatne.react.R; +import com.brentvatne.react.ReactNativeVideoManager; import com.brentvatne.receiver.AudioBecomingNoisyReceiver; import com.brentvatne.receiver.BecomingNoisyListener; import com.facebook.react.bridge.Dynamic; @@ -126,6 +126,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.ExecutorService; @@ -149,7 +150,7 @@ public class ReactExoplayerView extends FrameLayout implements private static final CookieManager DEFAULT_COOKIE_MANAGER = new CookieManager(); private static final int SHOW_PROGRESS = 1; - private final VideoEventEmitter eventEmitter; + protected final VideoEventEmitter eventEmitter; private final ReactExoplayerConfig config; private final DefaultBandwidthMeter bandwidthMeter; private LegacyPlayerControlView playerControlView; @@ -190,11 +191,18 @@ public class ReactExoplayerView extends FrameLayout implements private BufferConfig bufferConfig = new BufferConfig(); private int maxBitRate = 0; private boolean hasDrmFailed = false; - private Handler mainHandler; + private final Handler mainHandler; private Runnable mainRunnable; private boolean useCache = false; private ControlsConfig controlsConfig = new ControlsConfig(); + /* + * When user is seeking first called is on onPositionDiscontinuity -> DISCONTINUITY_REASON_SEEK + * Then we set if to false when playback is back in onIsPlayingChanged -> true + */ + private boolean isSeeking = false; + private long seekPosition = -1; + @Nullable private TrackSelectionArray lastSeenTrackSelectionArray; @@ -216,7 +224,6 @@ public class ReactExoplayerView extends FrameLayout implements private float mProgressUpdateInterval = 250.0f; private boolean playInBackground = false; private boolean mReportBandwidth = false; - private DRMProps drmProps; private boolean controls; private Uri adTagUrl; @@ -237,6 +244,9 @@ public class ReactExoplayerView extends FrameLayout implements private long lastDuration = -1; private boolean viewHasDropped = false; + + private String instanceId = String.valueOf(UUID.randomUUID()); + private void updateProgress() { if (player != null) { if (playerControlView != null && isPlayingAd() && controls) { @@ -255,7 +265,7 @@ private void updateProgress() { lastPos = pos; lastBufferDuration = bufferedDuration; lastDuration = duration; - eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration(), getPositionInFirstPeriodMsForCurrentWindow(pos)); + eventEmitter.onVideoProgress.invoke(pos, bufferedDuration, player.getDuration(), getPositionInFirstPeriodMsForCurrentWindow(pos)); } } } @@ -286,10 +296,10 @@ public double getPositionInFirstPeriodMsForCurrentWindow(long currentPosition) { public ReactExoplayerView(ThemedReactContext context, ReactExoplayerConfig config) { super(context); this.themedReactContext = context; - this.eventEmitter = new VideoEventEmitter(context); + this.eventEmitter = new VideoEventEmitter(); this.config = config; this.bandwidthMeter = config.getBandwidthMeter(); - + mainHandler = new Handler(); createViews(); audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); @@ -302,12 +312,6 @@ private boolean isPlayingAd() { return player != null && player.isPlayingAd(); } - @Override - public void setId(int id) { - super.setId(id); - eventEmitter.setViewId(id); - } - private void createViews() { setCookiePolicy(CookiesPolicy.SYSTEM_DEFAULT); @@ -316,12 +320,9 @@ private void createViews() { LayoutParams.MATCH_PARENT); exoPlayerView = new ExoPlayerView(getContext()); exoPlayerView.setLayoutParams(layoutParams); - addView(exoPlayerView, 0, layoutParams); exoPlayerView.setFocusable(this.focusable); - - mainHandler = new Handler(); } // LifecycleEventListener implementation @@ -365,13 +366,13 @@ public void cleanUpResources() { public void onBandwidthSample(int elapsedMs, long bytes, long bitrate) { if (mReportBandwidth) { if (player == null) { - eventEmitter.bandwidthReport(bitrate, 0, 0, "-1"); + eventEmitter.onVideoBandwidthUpdate.invoke(bitrate, 0, 0, "-1"); } else { Format videoFormat = player.getVideoFormat(); int width = videoFormat != null ? videoFormat.width : 0; int height = videoFormat != null ? videoFormat.height : 0; String trackId = videoFormat != null ? videoFormat.id : "-1"; - eventEmitter.bandwidthReport(bitrate, height, width, trackId); + eventEmitter.onVideoBandwidthUpdate.invoke(bitrate, height, width, trackId); } } } @@ -400,7 +401,7 @@ private void initializePlayerControl() { playerControlView.addVisibilityListener(new LegacyPlayerControlView.VisibilityListener() { @Override public void onVisibilityChange(int visibility) { - eventEmitter.controlsVisibilityChanged(visibility == View.VISIBLE); + eventEmitter.onControlsVisibilityChange.invoke(visibility == View.VISIBLE); } }); } @@ -448,7 +449,7 @@ public void handleOnBackPressed() { //Handling the pauseButton click event ImageButton pauseButton = playerControlView.findViewById(R.id.exo_pause); pauseButton.setOnClickListener((View v) -> - setPausedModifier(true) + setPausedModifier(true) ); //Handling the fullScreenButton click event @@ -566,6 +567,10 @@ private void refreshDebugState() { } } + public void setViewType(int viewType) { + exoPlayerView.updateSurfaceView(viewType); + } + private class RNVLoadControl extends DefaultLoadControl { private final int availableHeapInBytes; private final Runtime runtime; @@ -655,7 +660,7 @@ private void initializePlayer() { } if (activity == null) { DebugLog.e(TAG, "Failed to initialize Player!, null activity"); - eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001"); + eventEmitter.onVideoError.invoke("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001"); return; } @@ -672,7 +677,7 @@ private void initializePlayer() { DebugLog.e(TAG, "Failed to initialize Player! 1"); DebugLog.e(TAG, ex.toString()); ex.printStackTrace(); - self.eventEmitter.error(ex.toString(), ex, "1001"); + eventEmitter.onVideoError.invoke(ex.toString(), ex, "1001"); } }); }); @@ -684,7 +689,7 @@ private void initializePlayer() { DebugLog.e(TAG, "Failed to initialize Player! 2"); DebugLog.e(TAG, ex.toString()); ex.printStackTrace(); - eventEmitter.error(ex.toString(), ex, "1001"); + eventEmitter.onVideoError.invoke(ex.toString(), ex, "1001"); } }; mainHandler.postDelayed(mainRunnable, 1); @@ -740,6 +745,7 @@ private void initializePlayerCore(ReactExoplayerView self) { .setLoadControl(loadControl) .setMediaSourceFactory(mediaSourceFactory) .build(); + ReactNativeVideoManager.Companion.getInstance().onInstanceCreated(instanceId, player); refreshDebugState(); player.addListener(self); player.setVolume(muted ? 0.f : audioVolume * 1); @@ -761,19 +767,22 @@ private void initializePlayerCore(ReactExoplayerView self) { } } - private DrmSessionManager initializePlayerDrm(ReactExoplayerView self) { + private DrmSessionManager initializePlayerDrm() { DrmSessionManager drmSessionManager = null; - if (self.drmProps != null) { - try { - drmSessionManager = self.buildDrmSessionManager(self.drmProps.getDrmUUID(), - self.drmProps.getDrmLicenseServer(), - self.drmProps.getDrmLicenseHeader()); - } catch (UnsupportedDrmException e) { - int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported - : (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME - ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown); - eventEmitter.error(getResources().getString(errorStringId), e, "3003"); - return null; + DRMProps drmProps = source.getDrmProps(); + // need to realign UUID in DRM Props from source + if (drmProps != null && drmProps.getDrmType() != null) { + UUID uuid = Util.getDrmUuid(drmProps.getDrmType()); + if (uuid != null) { + try { + DebugLog.w(TAG, "drm buildDrmSessionManager"); + drmSessionManager = buildDrmSessionManager(uuid, drmProps); + } catch (UnsupportedDrmException e) { + int errorStringId = Util.SDK_INT < 18 ? R.string.error_drm_not_supported + : (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME + ? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown); + eventEmitter.onVideoError.invoke(getResources().getString(errorStringId), e, "3003"); + } } } return drmSessionManager; @@ -783,14 +792,14 @@ private void initializePlayerSource() { if (source.getUri() == null) { return; } - DrmSessionManager drmSessionManager = initializePlayerDrm(this); - if (drmSessionManager == null && drmProps != null && drmProps.getDrmUUID() != null) { - // Failed to intialize DRM session manager - cannot continue + /// init DRM + DrmSessionManager drmSessionManager = initializePlayerDrm(); + if (drmSessionManager == null && source.getDrmProps() != null && source.getDrmProps().getDrmType() != null) { + // Failed to initialize DRM session manager - cannot continue DebugLog.e(TAG, "Failed to initialize DRM Session Manager Framework!"); - eventEmitter.error("Failed to initialize DRM Session Manager Framework!", new Exception("DRM Session Manager Framework failure!"), "3003"); return; } - + // init source to manage ads and external text tracks ArrayList mediaSourceList = buildTextSources(); MediaSource videoSource = buildMediaSource(source.getUri(), source.getExtension(), drmSessionManager, source.getCropStartMs(), source.getCropEndMs()); MediaSource mediaSourceWithAds = null; @@ -848,7 +857,7 @@ private void initializePlayerSource() { reLayoutControls(); - eventEmitter.loadStart(); + eventEmitter.onVideoLoadStart.invoke(); loadVideoStarted = true; finishPlayerInitialization(); @@ -925,21 +934,21 @@ private void cleanupPlaybackService() { } } - private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException { - return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, 0); + private DrmSessionManager buildDrmSessionManager(UUID uuid, DRMProps drmProps) throws UnsupportedDrmException { + return buildDrmSessionManager(uuid, drmProps, 0); } - private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray, int retryCount) throws UnsupportedDrmException { + private DrmSessionManager buildDrmSessionManager(UUID uuid, DRMProps drmProps, int retryCount) throws UnsupportedDrmException { if (Util.SDK_INT < 18) { return null; } try { - HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(licenseUrl, + HttpMediaDrmCallback drmCallback = new HttpMediaDrmCallback(drmProps.getDrmLicenseServer(), buildHttpDataSourceFactory(false)); - if (keyRequestPropertiesArray != null) { - for (int i = 0; i < keyRequestPropertiesArray.length - 1; i += 2) { - drmCallback.setKeyRequestProperty(keyRequestPropertiesArray[i], keyRequestPropertiesArray[i + 1]); - } + + String[] keyRequestPropertiesArray = drmProps.getDrmLicenseHeader(); + for (int i = 0; i < keyRequestPropertiesArray.length - 1; i += 2) { + drmCallback.setKeyRequestProperty(keyRequestPropertiesArray[i], keyRequestPropertiesArray[i + 1]); } FrameworkMediaDrm mediaDrm = FrameworkMediaDrm.newInstance(uuid); if (hasDrmFailed) { @@ -949,7 +958,7 @@ private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, S return new DefaultDrmSessionManager.Builder() .setUuidAndExoMediaDrmProvider(uuid, (_uuid) -> mediaDrm) .setKeyRequestParameters(null) - .setMultiSession(false) + .setMultiSession(drmProps.getMultiDrm()) .build(drmCallback); } catch (UnsupportedDrmException ex) { // Unsupported DRM exceptions are handled by the calling method @@ -957,10 +966,10 @@ private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, S } catch (Exception ex) { if (retryCount < 3) { // Attempt retry 3 times in case where the OS Media DRM Framework fails for whatever reason - return buildDrmSessionManager(uuid, licenseUrl, keyRequestPropertiesArray, ++retryCount); + return buildDrmSessionManager(uuid, drmProps, ++retryCount); } // Handle the unknow exception and emit to JS - eventEmitter.error(ex.toString(), ex, "3006"); + eventEmitter.onVideoError.invoke(ex.toString(), ex, "3006"); return null; } } @@ -1041,7 +1050,7 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessi case CONTENT_TYPE_OTHER: if ("asset".equals(uri.getScheme())) { try { - DataSource.Factory assetDataSourceFactory = buildAssetDataSourceFactory(themedReactContext, uri); + DataSource.Factory assetDataSourceFactory = DataSourceUtil.buildAssetDataSourceFactory(themedReactContext, uri); mediaSourceFactory = new ProgressiveMediaSource.Factory(assetDataSourceFactory); } catch (Exception e) { throw new IllegalStateException("cannot open input file" + uri); @@ -1134,6 +1143,7 @@ private void releasePlayer() { player.removeListener(this); trackSelector = null; + ReactNativeVideoManager.Companion.getInstance().onInstanceRemoved(instanceId, player); player = null; } @@ -1167,7 +1177,7 @@ public void onAudioFocusChange(int focusChange) { switch (focusChange) { case AudioManager.AUDIOFOCUS_LOSS: view.hasAudioFocus = false; - view.eventEmitter.audioFocusChanged(false); + view.eventEmitter.onAudioFocusChanged.invoke(false); // FIXME this pause can cause issue if content doesn't have pause capability (can happen on live channel) if (activity != null) { activity.runOnUiThread(view::pausePlayback); @@ -1175,11 +1185,11 @@ public void onAudioFocusChange(int focusChange) { view.audioManager.abandonAudioFocus(this); break; case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT: - view.eventEmitter.audioFocusChanged(false); + view.eventEmitter.onAudioFocusChanged.invoke(false); break; case AudioManager.AUDIOFOCUS_GAIN: view.hasAudioFocus = true; - view.eventEmitter.audioFocusChanged(true); + view.eventEmitter.onAudioFocusChanged.invoke(true); break; default: break; @@ -1190,14 +1200,14 @@ public void onAudioFocusChange(int focusChange) { // Lower the volume if (!view.muted) { activity.runOnUiThread(() -> - view.player.setVolume(view.audioVolume * 0.8f) + view.player.setVolume(view.audioVolume * 0.8f) ); } } else if (focusChange == AudioManager.AUDIOFOCUS_GAIN) { // Raise it back to normal if (!view.muted) { activity.runOnUiThread(() -> - view.player.setVolume(view.audioVolume * 1) + view.player.setVolume(view.audioVolume * 1) ); } } @@ -1257,9 +1267,6 @@ private void stopPlayback() { } private void onStopPlayback() { - if (isFullscreen) { - setFullscreen(false); - } audioManager.abandonAudioFocus(audioFocusChangeListener); } @@ -1300,7 +1307,7 @@ private HttpDataSource.Factory buildHttpDataSourceFactory(boolean useBandwidthMe // AudioBecomingNoisyListener implementation @Override public void onAudioBecomingNoisy() { - eventEmitter.audioBecomingNoisy(); + eventEmitter.onVideoAudioBecomingNoisy.invoke(); } // Player.Listener implementation @@ -1315,11 +1322,11 @@ public void onEvents(@NonNull Player player, Player.Events events) { int playbackState = player.getPlaybackState(); boolean playWhenReady = player.getPlayWhenReady(); String text = "onStateChanged: playWhenReady=" + playWhenReady + ", playbackState="; - eventEmitter.playbackRateChange(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f); + eventEmitter.onPlaybackRateChange.invoke(playWhenReady && playbackState == ExoPlayer.STATE_READY ? 1.0f : 0.0f); switch (playbackState) { case Player.STATE_IDLE: text += "idle"; - eventEmitter.idle(); + eventEmitter.onVideoIdle.invoke(); clearProgressMessageHandler(); if (!player.getPlayWhenReady()) { setKeepScreenOn(false); @@ -1333,7 +1340,7 @@ public void onEvents(@NonNull Player player, Player.Events events) { break; case Player.STATE_READY: text += "ready"; - eventEmitter.ready(); + eventEmitter.onReadyForDisplay.invoke(); onBuffering(false); clearProgressMessageHandler(); // ensure there is no other message startProgressHandler(); @@ -1347,7 +1354,7 @@ public void onEvents(@NonNull Player player, Player.Events events) { case Player.STATE_ENDED: text += "ended"; updateProgress(); - eventEmitter.end(); + eventEmitter.onVideoEnd.invoke(); onStopPlayback(); setKeepScreenOn(false); break; @@ -1385,7 +1392,7 @@ private void videoLoaded() { String trackId = videoFormat != null ? videoFormat.id : "-1"; MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo(); - eventEmitter.load( + eventEmitter.onVideoLoad.invoke( player.getDuration(), player.getCurrentPosition(), width, @@ -1404,14 +1411,20 @@ private void onBuffering(boolean buffering) { return; } + if (isPaused && isSeeking && !buffering) { + eventEmitter.onVideoSeek.invoke(player.getCurrentPosition(), seekPosition); + isSeeking = false; + } + isBuffering = buffering; - eventEmitter.buffering(buffering); + eventEmitter.onVideoBuffer.invoke(buffering); } @Override public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @NonNull Player.PositionInfo newPosition, @Player.DiscontinuityReason int reason) { if (reason == Player.DISCONTINUITY_REASON_SEEK) { - eventEmitter.seek(player.getCurrentPosition(), newPosition.positionMs % 1000); // time are in seconds /°\ + isSeeking = true; + seekPosition = newPosition.positionMs; } if (playerNeedsSource) { @@ -1424,7 +1437,7 @@ public void onPositionDiscontinuity(@NonNull Player.PositionInfo oldPosition, @N // so we need to explicitly detect it. if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION && player.getRepeatMode() == Player.REPEAT_MODE_ONE) { updateProgress(); - eventEmitter.end(); + eventEmitter.onVideoEnd.invoke(); } } @@ -1443,17 +1456,17 @@ public void onTracksChanged(@NonNull Tracks tracks) { Object manifest = player.getCurrentManifest(); MappedTrackInfo info = trackSelector.getCurrentMappedTrackInfo(); - eventEmitter.audioTracks( + eventEmitter.onAudioTracks.invoke( TracksUtil.getAudioTracks(info), TracksUtil.getSelectedAudioTrack(info, currentTrackSelections), manifest ); - eventEmitter.videoTracks( + eventEmitter.onVideoTracks.invoke( TracksUtil.getVideoTracks(info), TracksUtil.getSelectedVideoTrack(info, currentTrackSelections), manifest ); - eventEmitter.textTracks( + eventEmitter.onTextTracks.invoke( TracksUtil.getTextTracks(info), TracksUtil.getSelectedTextTrack(info, currentTrackSelections) ); @@ -1462,17 +1475,25 @@ public void onTracksChanged(@NonNull Tracks tracks) { @Override public void onPlaybackParametersChanged(PlaybackParameters params) { - eventEmitter.playbackRateChange(params.speed); + eventEmitter.onPlaybackRateChange.invoke(params.speed); } @Override public void onVolumeChanged(float volume) { - eventEmitter.volumeChange(volume); + eventEmitter.onVolumeChange.invoke(volume); } @Override public void onIsPlayingChanged(boolean isPlaying) { - eventEmitter.playbackStateChanged(isPlaying); + if (isPlaying && isSeeking) { + eventEmitter.onVideoSeek.invoke(player.getCurrentPosition(), seekPosition); + } + + eventEmitter.onVideoPlaybackStateChanged.invoke(isPlaying, isSeeking); + + if (isPlaying) { + isSeeking = false; + } } @Override @@ -1498,7 +1519,7 @@ public void onPlayerError(@NonNull PlaybackException e) { default: break; } - eventEmitter.error(errorString, e, errorCode); + eventEmitter.onVideoError.invoke(errorString, e, errorCode); playerNeedsSource = true; if (isBehindLiveWindow(e)) { clearResumePosition(); @@ -1537,13 +1558,13 @@ public void onMetadata(@NonNull Metadata metadata) { DebugLog.d(TAG, "unhandled metadata " + entry); } } - eventEmitter.timedMetadata(metadataArray); + eventEmitter.onTimedMetadata.invoke(metadataArray); } public void onCues(CueGroup cueGroup) { if (!cueGroup.cues.isEmpty() && cueGroup.cues.get(0).text != null) { String subtitleText = cueGroup.cues.get(0).text.toString(); - eventEmitter.textTrackDataChanged(subtitleText); + eventEmitter.onTextTrackDataChanged.invoke(subtitleText); } } @@ -1600,7 +1621,9 @@ private void reloadSource() { } public void setResizeModeModifier(@ResizeMode.Mode int resizeMode) { - exoPlayerView.setResizeMode(resizeMode); + if (exoPlayerView != null) { + exoPlayerView.setResizeMode(resizeMode); + } } private void applyModifiers() { @@ -1801,7 +1824,7 @@ public void setFullscreen(boolean fullscreen) { Window window = activity.getWindow(); WindowInsetsControllerCompat controller = new WindowInsetsControllerCompat(window, window.getDecorView()); if (isFullscreen) { - eventEmitter.fullscreenWillPresent(); + eventEmitter.onVideoFullscreenPlayerWillPresent.invoke(); if (fullScreenPlayerView != null) { fullScreenPlayerView.show(); } @@ -1809,10 +1832,10 @@ public void setFullscreen(boolean fullscreen) { WindowCompat.setDecorFitsSystemWindows(window, false); controller.hide(WindowInsetsCompat.Type.systemBars()); controller.setSystemBarsBehavior(WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE); - eventEmitter.fullscreenDidPresent(); + eventEmitter.onVideoFullscreenPlayerDidPresent.invoke(); }); } else { - eventEmitter.fullscreenWillDismiss(); + eventEmitter.onVideoFullscreenPlayerWillDismiss.invoke(); if (fullScreenPlayerView != null) { fullScreenPlayerView.dismiss(); reLayoutControls(); @@ -1821,21 +1844,13 @@ public void setFullscreen(boolean fullscreen) { UiThreadUtil.runOnUiThread(() -> { WindowCompat.setDecorFitsSystemWindows(window, true); controller.show(WindowInsetsCompat.Type.systemBars()); - eventEmitter.fullscreenDidDismiss(); + eventEmitter.onVideoFullscreenPlayerDidDismiss.invoke(); }); } // need to be done at the end to avoid hiding fullscreen control button when fullScreenPlayerView is shown updateFullScreenButtonVisibility(); } - public void setUseTextureView(boolean useTextureView) { - exoPlayerView.setUseTextureView(useTextureView); - } - - public void useSecureView(boolean useSecureView) { - exoPlayerView.useSecureView(useSecureView); - } - public void setHideShutterView(boolean hideShutterView) { exoPlayerView.setHideShutterView(hideShutterView); } @@ -1855,13 +1870,6 @@ public void setBufferConfig(BufferConfig config) { initializePlayer(); } - public void setDrm(DRMProps drmProps) { - this.drmProps = drmProps; - if (drmProps != null && drmProps.getDrmType() != null) { - this.drmProps.setDrmUUID(Util.getDrmUuid(drmProps.getDrmType())); - } - } - @Override public void onDrmKeysLoaded(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) { DebugLog.d("DRM Info", "onDrmKeysLoaded"); @@ -1880,7 +1888,7 @@ public void onDrmSessionReleased(int windowIndex, MediaSource.MediaPeriodId medi @Override public void onDrmSessionManagerError(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId, @NonNull Exception e) { DebugLog.d("DRM Info", "onDrmSessionManagerError"); - eventEmitter.error("onDrmSessionManagerError", e, "3002"); + eventEmitter.onVideoError.invoke("onDrmSessionManagerError", e, "3002"); } @Override @@ -1926,16 +1934,21 @@ public void setShutterColor(Integer color) { @Override public void onAdEvent(AdEvent adEvent) { if (adEvent.getAdData() != null) { - eventEmitter.receiveAdEvent(adEvent.getType().name(), adEvent.getAdData()); + eventEmitter.onReceiveAdEvent.invoke(adEvent.getType().name(), adEvent.getAdData()); } else { - eventEmitter.receiveAdEvent(adEvent.getType().name()); + eventEmitter.onReceiveAdEvent.invoke(adEvent.getType().name(), null); } } @Override public void onAdError(AdErrorEvent adErrorEvent) { AdError error = adErrorEvent.getError(); - eventEmitter.receiveAdErrorEvent(error.getMessage(), String.valueOf(error.getErrorCode()), String.valueOf(error.getErrorType())); + Map errMap = Map.of( + "message", error.getMessage(), + "code", String.valueOf(error.getErrorCode()), + "type", String.valueOf(error.getErrorType()) + ); + eventEmitter.onReceiveAdEvent.invoke("ERROR", errMap); } public void setControlsStyles(ControlsConfig controlsStyles) { diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index b84c698086..172019cdb0 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -11,7 +11,6 @@ import android.util.Log; import androidx.annotation.NonNull; -import androidx.media3.common.util.Util; import com.brentvatne.common.api.BufferConfig; import com.brentvatne.common.api.BufferingStrategy; @@ -21,13 +20,14 @@ import com.brentvatne.common.api.SideLoadedTextTrackList; import com.brentvatne.common.api.Source; import com.brentvatne.common.api.SubtitleStyle; -import com.brentvatne.common.react.VideoEventEmitter; +import com.brentvatne.common.api.ViewType; +import com.brentvatne.common.react.EventTypes; import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.common.toolbox.ReactBridgeUtils; import com.facebook.react.bridge.Dynamic; +import com.brentvatne.react.ReactNativeVideoManager; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ViewGroupManager; import com.facebook.react.uimanager.annotations.ReactProp; @@ -35,7 +35,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.Map; -import java.util.UUID; import javax.annotation.Nullable; @@ -45,8 +44,6 @@ public class ReactExoplayerViewManager extends ViewGroupManager getExportedCustomDirectEventTypeConstants() { - MapBuilder.Builder builder = MapBuilder.builder(); - for (String event : VideoEventEmitter.Events) { - builder.put(event, MapBuilder.of("registrationName", event)); - } - return builder.build(); + return EventTypes.Companion.toMap(); } - @ReactProp(name = PROP_DRM) - public void setDRM(final ReactExoplayerView videoView, @Nullable ReadableMap drm) { - DRMProps drmProps = DRMProps.parse(drm); - videoView.setDrm(drmProps); - videoView.setUseTextureView(false); + @Override + public void addEventEmitters(@NonNull ThemedReactContext reactContext, @NonNull ReactExoplayerView view) { + super.addEventEmitters(reactContext, view); + view.eventEmitter.addEventEmitters(reactContext, view); } @ReactProp(name = PROP_SRC) @@ -218,7 +210,7 @@ public void setSelectedTextTrack(final ReactExoplayerView videoView, } @ReactProp(name = PROP_TEXT_TRACKS) - public void setPropTextTracks(final ReactExoplayerView videoView, + public void setTextTracks(final ReactExoplayerView videoView, @Nullable ReadableArray textTracks) { SideLoadedTextTrackList sideLoadedTextTracks = SideLoadedTextTrackList.Companion.parse(textTracks); videoView.setTextTracks(sideLoadedTextTracks); @@ -260,12 +252,12 @@ public void setRate(final ReactExoplayerView videoView, final float rate) { } @ReactProp(name = PROP_MAXIMUM_BIT_RATE) - public void setMaxBitRate(final ReactExoplayerView videoView, final int maxBitRate) { - videoView.setMaxBitRateModifier(maxBitRate); + public void setMaxBitRate(final ReactExoplayerView videoView, final float maxBitRate) { + videoView.setMaxBitRateModifier((int)maxBitRate); } @ReactProp(name = PROP_MIN_LOAD_RETRY_COUNT) - public void minLoadRetryCount(final ReactExoplayerView videoView, final int minLoadRetryCount) { + public void setMinLoadRetryCount(final ReactExoplayerView videoView, final int minLoadRetryCount) { videoView.setMinLoadRetryCountModifier(minLoadRetryCount); } @@ -300,14 +292,9 @@ public void setFullscreen(final ReactExoplayerView videoView, final boolean full videoView.setFullscreen(fullscreen); } - @ReactProp(name = PROP_USE_TEXTURE_VIEW, defaultBoolean = true) - public void setUseTextureView(final ReactExoplayerView videoView, final boolean useTextureView) { - videoView.setUseTextureView(useTextureView); - } - - @ReactProp(name = PROP_SECURE_VIEW, defaultBoolean = true) - public void useSecureView(final ReactExoplayerView videoView, final boolean useSecureView) { - videoView.useSecureView(useSecureView); + @ReactProp(name = PROP_VIEW_TYPE, defaultInt = ViewType.VIEW_TYPE_SURFACE) + public void setViewType(final ReactExoplayerView videoView, final int viewType) { + videoView.setViewType(viewType); } @ReactProp(name = PROP_HIDE_SHUTTER_VIEW, defaultBoolean = false) @@ -330,12 +317,11 @@ public void setSubtitleLinesRespected(final ReactExoplayerView videoView, final videoView.setSubtitleLinesRespected(linesRespected); } - @ReactProp(name = PROP_SHUTTER_COLOR, customType = "Color") - public void setShutterColor(final ReactExoplayerView videoView, final Integer color) { - videoView.setShutterColor(color == null ? Color.BLACK : color); + @ReactProp(name = PROP_SHUTTER_COLOR, defaultInt = 0) + public void setShutterColor(final ReactExoplayerView videoView, final int color) { + videoView.setShutterColor(color == 0 ? Color.BLACK : color); } - @ReactProp(name = PROP_BUFFER_CONFIG) public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) { BufferConfig config = BufferConfig.parse(bufferConfig); diff --git a/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt b/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt index 1a0da5becb..6cf6f7d2c2 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt +++ b/android/src/main/java/com/brentvatne/exoplayer/VideoPlaybackService.kt @@ -58,7 +58,7 @@ class VideoPlaybackService : MediaSessionService() { val mediaSession = MediaSession.Builder(this, player) .setId("RNVideoPlaybackService_" + player.hashCode()) .setCallback(VideoPlaybackCallback()) - .setCustomLayout(immutableListOf(seekBackwardBtn, seekForwardBtn)) + .setCustomLayout(immutableListOf(seekForwardBtn, seekBackwardBtn)) .build() mediaSessionsList[player] = mediaSession diff --git a/android/src/main/java/com/brentvatne/react/RNVPlugin.kt b/android/src/main/java/com/brentvatne/react/RNVPlugin.kt new file mode 100644 index 0000000000..2cdf676608 --- /dev/null +++ b/android/src/main/java/com/brentvatne/react/RNVPlugin.kt @@ -0,0 +1,22 @@ +package com.brentvatne.react + +/** + * Plugin interface definition + */ +interface RNVPlugin { + /** + * Function called when a new player is created + * @param id: a random string identifying the player + * @param player: the instantiated player reference + */ + fun onInstanceCreated(id: String, player: Any) + + /** + * Function called when a player should be destroyed + * when this callback is called, the plugin shall free all + * resources and release all reference to Player object + * @param id: a random string identifying the player + * @param player: the player to release + */ + fun onInstanceRemoved(id: String, player: Any) +} diff --git a/android/src/main/java/com/brentvatne/react/ReactNativeVideoManager.kt b/android/src/main/java/com/brentvatne/react/ReactNativeVideoManager.kt new file mode 100644 index 0000000000..d279264302 --- /dev/null +++ b/android/src/main/java/com/brentvatne/react/ReactNativeVideoManager.kt @@ -0,0 +1,71 @@ +package com.brentvatne.react + +import com.brentvatne.common.toolbox.DebugLog +import com.brentvatne.exoplayer.ReactExoplayerViewManager + +/** + * ReactNativeVideoManager is a singleton class which allows to manipulate / the global state of the app + * It handles the list of

Android @@ -67,6 +69,8 @@ buildscript { ### Enable custom feature in gradle file +**If you are using Expo you can use [expo plugin](other/expo.md) for it** + You can disable or enable the following features by setting the following variables in your `android/build.gradle` file: - `useExoplayerIMA` - Enable Google IMA SDK (Ads support) - `useExoplayerRtsp` - Enable RTSP support diff --git a/docs/pages/other/_meta.json b/docs/pages/other/_meta.json index 2280f45834..0cd936a999 100644 --- a/docs/pages/other/_meta.json +++ b/docs/pages/other/_meta.json @@ -2,5 +2,7 @@ "caching": "Caching", "misc": "Misc", "debug": "Debugging", - "new-arch": "New Architecture" + "new-arch": "New Architecture", + "expo": "Expo", + "plugin": "Plugin (experimental)" } \ No newline at end of file diff --git a/docs/pages/other/debug.md b/docs/pages/other/debug.md index cd8605ae78..74c8bfd146 100644 --- a/docs/pages/other/debug.md +++ b/docs/pages/other/debug.md @@ -1,6 +1,6 @@ # Debugging -This page describe usefull tips for debugging and investigating issue in the package or in your application. +This page describe useful tips for debugging and investigating issue in the package or in your application. ## Using the sample app This repository contains multiple a sample implementation in example folder. @@ -56,6 +56,41 @@ With these tool you should be able to analyze what is going on with network. You Then try to compare exchanges with previous tests you made. +## Debug media3: build from media3 source + +If you need to use a specific exoplayer version or patch default behavior, you may want to build from media3 source code. + +Building from media3 source is possible. You need to add 2 or 3 things in your app: + +### Configure player path + +You need to add following lines in settings.gradle to configure your media3 source path: + +```gradle +gradle.ext.androidxMediaModulePrefix = 'media-' +apply from: file("../../../../media3/core_settings.gradle") +```` + +Of course, you should replace with media3 source path. Be carefull, you need to use the same version (or version with compatible api) that the package support. + +### Enable building from source +In your build.gradle file, add following setting: + +```gradle +buildscript { + ext { + ... + buildFromMedia3Source = true + ... + } +} +``` + +### Desugaring +to be able to link you may also need to enable coreLibraryDesugaringEnabled in your app. + +See: https://developer.android.com/studio/write/java8-support?hl=fr#library-desugaring for more informations. + ## It's still not working You can try to open a ticket now ! diff --git a/docs/pages/other/expo.md b/docs/pages/other/expo.md new file mode 100644 index 0000000000..fdb41a9e72 --- /dev/null +++ b/docs/pages/other/expo.md @@ -0,0 +1,40 @@ +# Expo + +## Expo plugin +From version `6.3.1`, we have added support for expo plugin. You can configure `react-native-video` properties in `app.json` (or `app.config.json` or `app.config.js`) file. +It's useful when you are using `expo` managed workflow (expo prebuild) as it will automatically configure `react-native-video` properties in native part of the expo project. + +```json +// app.json +{ + { + "name": "my app", + "plugins": [ + [ + "react-native-video", + { + // ... + "enableNotificationControls": true, + "androidExtensions": { + "useExoplayerRtsp": false, + "useExoplayerSmoothStreaming": false, + "useExoplayerHls": false, + "useExoplayerDash": false, + } + // ... + } + ] + ] +} +} +``` + +## Expo Plugin Properties + +| Property | Type | Default | Description | +| --- | --- | --- | --- | +| enableNotificationControls | boolean | false | Add required changes on android to use notification controls for video player | +| enableBackgroundAudio | boolean | false | Add required changes to play video in background on iOS | +| enableADSExtension | boolean | false | Add required changes to use ads extension for video player | +| enableCacheExtension | boolean | false | Add required changes to use cache extension for video player on iOS | +| androidExtensions | object | {} | You can enable/disable extensions as per your requirement - this allow to reduce library size on android | \ No newline at end of file diff --git a/docs/pages/other/plugin.md b/docs/pages/other/plugin.md new file mode 100644 index 0000000000..dad1cf7c5b --- /dev/null +++ b/docs/pages/other/plugin.md @@ -0,0 +1,125 @@ +# Plugin (experimental) + +Since Version 6.4.0, it is possible to create plugins for analytics management and maybe much more. +A sample plugin is available in the repository in: example/react-native-video-plugin-sample. (important FIXME, put sample link) + +## Concept + +Most of the analytics system which tracks player information (bitrate, errors, ...) can be integrated directly with Exoplayer or AVPlayer handles. + +This plugin system allows none intrusive integration of analytics in the react-native-package. It shall be done in native language (kotlin/swift). + +The idea behind this system is to be able to plug an analytics package to react native video without doing any code change (ideally). + +Following documentation will show on how to create a new plugin for react native video + +## Warning and consideration +This is an experiental API, it is subject to change. The api with player is very simple but should be flexible enough to implement analytics system. If you need some metadata, you should implement setter in the new package you are creating. + +As api is flexible, it makes possible to missuse the system. It is necessary to consider the player handle as read-only. If you modify player behavior, we cannot garanty the good behavior of react-native-video package. + +## General + +First you need to create a new react native package: +````shell +npx create-react-native-library@latest react-native-video-custom-analytics +```` + +Both android and iOS implementation expose an interface `RNVPlugin`. +Your `react-native-video-custom-analytics` shall implement this interface and register itself as a plugin for react native video. + +## Android +There is no special requierement for gradle file. +You need two mandatory action to be able to receive player handle + +### 1/ Create the plugin + +First you should instanciate a class which extends `RNVPlugin`. + +The proposed integration implement `RNVPlugin` directly inside the Module file (`VideoPluginSampleModule`). + +The `RNVPlugin` interface only defines 2 functions, see description here under. + +```kotlin + /** + * Function called when a new player is created + * @param id: a random string identifying the player + * @param player: the instantiated player reference + */ + fun onInstanceCreated(id: String, player: Any) + /** + * Function called when a player should be destroyed + * when this callback is called, the plugin shall free all + * resources and release all reference to Player object + * @param id: a random string identifying the player + * @param player: the player to release + */ + fun onInstanceRemoved(id: String, player: Any) + ```` + +### 2/ register the plugin + +To register this allocated class in the main react native video package you should call following function: + +```kotlin +ReactNativeVideoManager.getInstance().registerPlugin(plugin) +``` +The proposed integration register the instanciated class in `createNativeModules` entry point. + +Your native module can now track Player updates directly from Player reference and report to backend. + +## ios + +### 1/ podspec integration + +Your new module shall be able to access to react-native-video package, then we must declare it as a dependency of the new module you are creating. + +```podfile + s.dependency "react-native-video" +```` + +### 2/ Create the plugin + +First you should instanciate a class which extends `RNVPlugin`. + +The proposed integration implement `RNVPlugin` directly inside the entry point of the module file (`VideoPluginSample`). + +The `RNVPlugin` interface only defines 2 functions, see description here under. + +```swift + /** + * Function called when a new player is created + * @param player: the instantiated player reference + */ + func onInstanceCreated(player: Any) + /** + * Function called when a player should be destroyed + * when this callback is called, the plugin shall free all + * resources and release all reference to Player object + * @param player: the player to release + */ + func onInstanceRemoved(player: Any) +``` + +### 3/ Register the plugin + +To register this allocated class in the main react native video package you should register it by calling this function: + +```swift +ReactNativeVideoManager.shared.registerPlugin(plugin: plugin) +``` + +The proposed integration register the instanciated class in file `VideoPluginSample` in the init function: + +```swift +import react_native_video + +... + +override init() { + super.init() + ReactNativeVideoManager.shared.registerPlugin(plugin: self) +} +``` + +Your native module can now track Player updates directly from Player reference and report to backend. diff --git a/docs/pages/projects.md b/docs/pages/projects.md index f12f3d20aa..60de5c2c77 100644 --- a/docs/pages/projects.md +++ b/docs/pages/projects.md @@ -8,4 +8,4 @@ If you have a project which can be useful for other users, feel free to open a P - [react-native-corner-video](https://github.com/Lg0gs/react-native-corner-video): A floating video player ## Other tools - - [react-native-music-control](https://github.com/tanguyantoine/react-native-music-control): A toolbox to control player over media session + - [react-native-track-player](https://github.com/doublesymmetry/react-native-track-player): A toolbox to control player over media session diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx index 25e2f9b910..076d07d8bc 100644 --- a/docs/theme.config.jsx +++ b/docs/theme.config.jsx @@ -13,7 +13,7 @@ export default { /> @@ -23,7 +23,7 @@ export default { /> @@ -48,7 +48,7 @@ export default { footer: { text: ( - Built with love ❤️ by React Native Community + Built with ❤️ by React Native Community ), }, diff --git a/examples/FabricExample/.eslintrc.js b/examples/FabricExample/.eslintrc.js index dcf0be0865..9dd57a791b 100644 --- a/examples/FabricExample/.eslintrc.js +++ b/examples/FabricExample/.eslintrc.js @@ -1,6 +1,6 @@ module.exports = { root: true, - extends: '@react-native-community', + extends: '@react-native', parser: '@typescript-eslint/parser', plugins: ['@typescript-eslint'], overrides: [ diff --git a/examples/FabricExample/.gitignore b/examples/FabricExample/.gitignore index 2423126f72..613b9bdc1e 100644 --- a/examples/FabricExample/.gitignore +++ b/examples/FabricExample/.gitignore @@ -62,3 +62,6 @@ buck-out/ # Ruby / CocoaPods /ios/Pods/ /vendor/bundle/ + +# testing +/coverage \ No newline at end of file diff --git a/examples/FabricExample/Gemfile b/examples/FabricExample/Gemfile index 5efda89f45..6a7d5c7a49 100644 --- a/examples/FabricExample/Gemfile +++ b/examples/FabricExample/Gemfile @@ -1,6 +1,7 @@ source 'https://rubygems.org' # You may use http://rbenv.org/ or https://rvm.io/ to install and use this version -ruby '2.7.5' +ruby ">= 2.6.10" -gem 'cocoapods', '~> 1.11', '>= 1.11.2' +gem 'cocoapods', '~> 1.13' +gem 'activesupport', '>= 6.1.7.3', '< 7.1.0' diff --git a/examples/FabricExample/Gemfile.lock b/examples/FabricExample/Gemfile.lock index be0b95a462..ab5cb31048 100644 --- a/examples/FabricExample/Gemfile.lock +++ b/examples/FabricExample/Gemfile.lock @@ -1,26 +1,30 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.6) + CFPropertyList (3.0.7) + base64 + nkf rexml - activesupport (7.0.4.3) + activesupport (6.1.7.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.4) - public_suffix (>= 2.0.2, < 6.0) + zeitwerk (~> 2.3) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) atomos (0.1.3) + base64 (0.2.0) claide (1.1.0) - cocoapods (1.12.0) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.12.0) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.6.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0) @@ -32,8 +36,8 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.12.0) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -44,7 +48,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -57,39 +61,44 @@ GEM escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - ffi (1.15.5) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) httpclient (2.8.3) i18n (1.12.0) concurrent-ruby (~> 1.0) - json (2.6.3) + json (2.7.2) minitest (5.18.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) netrc (0.11.0) + nkf (0.2.0) public_suffix (4.0.7) - rexml (3.2.5) + rexml (3.2.9) + strscan ruby-macho (2.5.1) - typhoeus (1.4.0) + strscan (3.1.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) - xcodeproj (1.22.0) + xcodeproj (1.24.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) + zeitwerk (2.6.16) PLATFORMS ruby DEPENDENCIES - cocoapods (~> 1.11, >= 1.11.2) + activesupport (>= 6.1.7.3, < 7.1.0) + cocoapods (~> 1.13) RUBY VERSION ruby 2.7.5p203 diff --git a/examples/FabricExample/__tests__/App-test.tsx b/examples/FabricExample/__tests__/App-test.tsx index 178476699b..9eac6fbc87 100644 --- a/examples/FabricExample/__tests__/App-test.tsx +++ b/examples/FabricExample/__tests__/App-test.tsx @@ -6,6 +6,9 @@ import 'react-native'; import React from 'react'; import App from '../App'; +// Note: import explicitly to use the types shipped with jest. +import {it} from '@jest/globals'; + // Note: test renderer must be required after react-native. import renderer from 'react-test-renderer'; diff --git a/examples/FabricExample/_node-version b/examples/FabricExample/_node-version deleted file mode 100644 index b6a7d89c68..0000000000 --- a/examples/FabricExample/_node-version +++ /dev/null @@ -1 +0,0 @@ -16 diff --git a/examples/FabricExample/android/app/build.gradle b/examples/FabricExample/android/app/build.gradle index 1266df3d88..6da4d1a8b9 100644 --- a/examples/FabricExample/android/app/build.gradle +++ b/examples/FabricExample/android/app/build.gradle @@ -1,4 +1,5 @@ apply plugin: "com.android.application" +apply plugin: "org.jetbrains.kotlin.android" apply plugin: "com.facebook.react" import com.android.build.OutputFile @@ -13,8 +14,8 @@ react { // root = file("../") // The folder where the react-native NPM package is. Default is ../node_modules/react-native // reactNativeDir = file("../node-modules/react-native") - // The folder where the react-native Codegen package is. Default is ../node_modules/react-native-codegen - // codegenDir = file("../node-modules/react-native-codegen") + // The folder where the react-native Codegen package is. Default is ../node_modules/@react-native/codegen + // codegenDir = file("../node_modules/@react-native/codegen") // The cli.js file which is the React Native CLI entrypoint. Default is ../node_modules/react-native/cli.js // cliFile = file("../node_modules/react-native/cli.js") @@ -52,14 +53,6 @@ react { // hermesFlags = ["-O", "-output-source-map"] } -/** - * Set this to true to create four separate APKs instead of one, - * one for each native architecture. This is useful if you don't - * use App Bundles (https://developer.android.com/guide/app-bundle/) - * and want to have separate APKs to upload to the Play Store. - */ -def enableSeparateBuildPerCPUArchitecture = false - /** * Set this to true to Run Proguard on Release builds to minify the Java bytecode. */ @@ -78,20 +71,11 @@ def enableProguardInReleaseBuilds = false */ def jscFlavor = 'org.webkit:android-jsc:+' -/** - * Private function to get the list of Native Architectures you want to build. - * This reads the value from reactNativeArchitectures in your gradle.properties - * file and works together with the --active-arch-only flag of react-native run-android. - */ -def reactNativeArchitectures() { - def value = project.getProperties().get("reactNativeArchitectures") - return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"] -} - android { ndkVersion rootProject.ext.ndkVersion - compileSdkVersion rootProject.ext.compileSdkVersion + buildToolsVersion rootProject.ext.buildToolsVersion + compileSdk rootProject.ext.compileSdkVersion namespace "net.video.fabricexample" defaultConfig { @@ -102,14 +86,6 @@ android { versionName "1.0" } - splits { - abi { - reset() - enable enableSeparateBuildPerCPUArchitecture - universalApk false // If true, also generate a universal APK - include (*reactNativeArchitectures()) - } - } signingConfigs { debug { storeFile file('debug.keystore') @@ -130,36 +106,13 @@ android { proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" } } - - // applicationVariants are e.g. debug, release - applicationVariants.all { variant -> - variant.outputs.each { output -> - // For each separate APK per architecture, set a unique version code as described here: - // https://developer.android.com/studio/build/configure-apk-splits.html - // Example: versionCode 1 will generate 1001 for armeabi-v7a, 1002 for x86, etc. - def versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4] - def abi = output.getFilter(OutputFile.ABI) - if (abi != null) { // null for the universal-debug, universal-release variants - output.versionCodeOverride = - defaultConfig.versionCode * 1000 + versionCodes.get(abi) - } - - } - } } dependencies { // The version of react-native is set by the React Native Gradle Plugin implementation("com.facebook.react:react-android") + implementation("com.facebook.react:flipper-integration") - implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.0.0") - - debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") - debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { - exclude group:'com.squareup.okhttp3', module:'okhttp' - } - - debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") if (hermesEnabled.toBoolean()) { implementation("com.facebook.react:hermes-android") } else { diff --git a/examples/FabricExample/android/app/src/debug/AndroidManifest.xml b/examples/FabricExample/android/app/src/debug/AndroidManifest.xml index 4b185bc159..ced5aabf9c 100644 --- a/examples/FabricExample/android/app/src/debug/AndroidManifest.xml +++ b/examples/FabricExample/android/app/src/debug/AndroidManifest.xml @@ -7,7 +7,5 @@ - - + tools:ignore="GoogleAppIndexingWarning"/> diff --git a/examples/FabricExample/android/app/src/debug/java/net/video/fabricexample/ReactNativeFlipper.java b/examples/FabricExample/android/app/src/debug/java/net/video/fabricexample/ReactNativeFlipper.java deleted file mode 100644 index 426e7d70c9..0000000000 --- a/examples/FabricExample/android/app/src/debug/java/net/video/fabricexample/ReactNativeFlipper.java +++ /dev/null @@ -1,73 +0,0 @@ -/** - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - *

This source code is licensed under the MIT license found in the LICENSE file in the root - * directory of this source tree. - */ -package net.video.fabricexample; - -import android.content.Context; -import com.facebook.flipper.android.AndroidFlipperClient; -import com.facebook.flipper.android.utils.FlipperUtils; -import com.facebook.flipper.core.FlipperClient; -import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin; -import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin; -import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin; -import com.facebook.flipper.plugins.inspector.DescriptorMapping; -import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin; -import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor; -import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; -import com.facebook.flipper.plugins.react.ReactFlipperPlugin; -import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; -import com.facebook.react.ReactInstanceEventListener; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.modules.network.NetworkingModule; -import okhttp3.OkHttpClient; - -public class ReactNativeFlipper { - public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) { - if (FlipperUtils.shouldEnableFlipper(context)) { - final FlipperClient client = AndroidFlipperClient.getInstance(context); - - client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults())); - client.addPlugin(new ReactFlipperPlugin()); - client.addPlugin(new DatabasesFlipperPlugin(context)); - client.addPlugin(new SharedPreferencesFlipperPlugin(context)); - client.addPlugin(CrashReporterPlugin.getInstance()); - - NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin(); - NetworkingModule.setCustomClientBuilder( - new NetworkingModule.CustomClientBuilder() { - @Override - public void apply(OkHttpClient.Builder builder) { - builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin)); - } - }); - client.addPlugin(networkFlipperPlugin); - client.start(); - - // Fresco Plugin needs to ensure that ImagePipelineFactory is initialized - // Hence we run if after all native modules have been initialized - ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); - if (reactContext == null) { - reactInstanceManager.addReactInstanceEventListener( - new ReactInstanceEventListener() { - @Override - public void onReactContextInitialized(ReactContext reactContext) { - reactInstanceManager.removeReactInstanceEventListener(this); - reactContext.runOnNativeModulesQueueThread( - new Runnable() { - @Override - public void run() { - client.addPlugin(new FrescoFlipperPlugin()); - } - }); - } - }); - } else { - client.addPlugin(new FrescoFlipperPlugin()); - } - } - } -} diff --git a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.java b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.java deleted file mode 100644 index ee26067a11..0000000000 --- a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.video.fabricexample; - -import android.os.Bundle; -import android.view.View; -import android.view.WindowManager; - -import com.facebook.react.ReactActivity; -import com.facebook.react.ReactActivityDelegate; -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; -import com.facebook.react.defaults.DefaultReactActivityDelegate; - -public class MainActivity extends ReactActivity { - - private static final boolean TEST_TRANSLUCENT_STATUS_BAR = true; - private static final boolean TEST_TRANSLUCENT_NAVBAR = true; - - /** - * Returns the name of the main component registered from JavaScript. This is used to schedule - * rendering of the component. - */ - @Override - protected String getMainComponentName() { - return "FabricExample"; - } - - /** - * Returns the instance of the {@link ReactActivityDelegate}. Here we use a util class {@link - * DefaultReactActivityDelegate} which allows you to easily enable Fabric and Concurrent React - * (aka React 18) with two boolean flags. - */ - @Override - protected ReactActivityDelegate createReactActivityDelegate() { - return new DefaultReactActivityDelegate( - this, - getMainComponentName(), - // If you opted-in for the New Architecture, we enable the Fabric Renderer. - DefaultNewArchitectureEntryPoint.getFabricEnabled(), // fabricEnabled - // If you opted-in for the New Architecture, we enable Concurrent React (i.e. React 18). - DefaultNewArchitectureEntryPoint.getConcurrentReactEnabled() // concurrentRootEnabled - ); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - if (TEST_TRANSLUCENT_STATUS_BAR) { - getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - if (TEST_TRANSLUCENT_NAVBAR) { - getWindow().setFlags( - WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, - WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION); - } - } -} \ No newline at end of file diff --git a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.kt b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.kt new file mode 100644 index 0000000000..d88d6bb960 --- /dev/null +++ b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainActivity.kt @@ -0,0 +1,22 @@ +package net.video.fabricexample + +import com.facebook.react.ReactActivity +import com.facebook.react.ReactActivityDelegate +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled +import com.facebook.react.defaults.DefaultReactActivityDelegate + +class MainActivity : ReactActivity() { + + /** + * Returns the name of the main component registered from JavaScript. This is used to schedule + * rendering of the component. + */ + override fun getMainComponentName(): String = "FabricExample" + + /** + * Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate] + * which allows you to enable New Architecture with a single boolean flags [fabricEnabled] + */ + override fun createReactActivityDelegate(): ReactActivityDelegate = + DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled) +} \ No newline at end of file diff --git a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.java b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.java deleted file mode 100644 index b2d41535fe..0000000000 --- a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.java +++ /dev/null @@ -1,62 +0,0 @@ -package net.video.fabricexample; - -import android.app.Application; -import com.facebook.react.PackageList; -import com.facebook.react.ReactApplication; -import com.facebook.react.ReactNativeHost; -import com.facebook.react.ReactPackage; -import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; -import com.facebook.react.defaults.DefaultReactNativeHost; -import com.facebook.soloader.SoLoader; -import java.util.List; - -public class MainApplication extends Application implements ReactApplication { - - private final ReactNativeHost mReactNativeHost = - new DefaultReactNativeHost(this) { - @Override - public boolean getUseDeveloperSupport() { - return BuildConfig.DEBUG; - } - - @Override - protected List getPackages() { - @SuppressWarnings("UnnecessaryLocalVariable") - List packages = new PackageList(this).getPackages(); - // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); - return packages; - } - - @Override - protected String getJSMainModuleName() { - return "index"; - } - - @Override - protected boolean isNewArchEnabled() { - return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED; - } - - @Override - protected Boolean isHermesEnabled() { - return BuildConfig.IS_HERMES_ENABLED; - } - }; - - @Override - public ReactNativeHost getReactNativeHost() { - return mReactNativeHost; - } - - @Override - public void onCreate() { - super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); - if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { - // If you opted-in for the New Architecture, we load the native entry point for this app. - DefaultNewArchitectureEntryPoint.load(); - } - ReactNativeFlipper.initializeFlipper(this, getReactNativeHost().getReactInstanceManager()); - } -} diff --git a/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.kt b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.kt new file mode 100644 index 0000000000..d6909c945b --- /dev/null +++ b/examples/FabricExample/android/app/src/main/java/net/video/fabricexample/MainApplication.kt @@ -0,0 +1,45 @@ +package net.video.fabricexample + +import android.app.Application +import com.facebook.react.PackageList +import com.facebook.react.ReactApplication +import com.facebook.react.ReactHost +import com.facebook.react.ReactNativeHost +import com.facebook.react.ReactPackage +import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.load +import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost +import com.facebook.react.defaults.DefaultReactNativeHost +import com.facebook.react.flipper.ReactNativeFlipper +import com.facebook.soloader.SoLoader + +class MainApplication : Application(), ReactApplication { + + override val reactNativeHost: ReactNativeHost = + object : DefaultReactNativeHost(this) { + override fun getPackages(): List = + PackageList(this).packages.apply { + // Packages that cannot be autolinked yet can be added manually here, for example: + // add(MyReactNativePackage()) + } + + override fun getJSMainModuleName(): String = "index" + + override fun getUseDeveloperSupport(): Boolean = BuildConfig.DEBUG + + override val isNewArchEnabled: Boolean = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED + override val isHermesEnabled: Boolean = BuildConfig.IS_HERMES_ENABLED + } + + override val reactHost: ReactHost + get() = getDefaultReactHost(this.applicationContext, reactNativeHost) + + override fun onCreate() { + super.onCreate() + SoLoader.init(this, false) + if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) { + // If you opted-in for the New Architecture, we load the native entry point for this app. + load() + } + ReactNativeFlipper.initializeFlipper(this, reactNativeHost.reactInstanceManager) + } +} diff --git a/examples/FabricExample/android/build.gradle b/examples/FabricExample/android/build.gradle index c30aa72af7..992bdc0898 100644 --- a/examples/FabricExample/android/build.gradle +++ b/examples/FabricExample/android/build.gradle @@ -2,48 +2,25 @@ buildscript { ext { - buildToolsVersion = "31.0.0" - kotlinVersion = "1.6.20" - minSdkVersion = 21 - compileSdkVersion = 31 - targetSdkVersion = 31 + buildToolsVersion = "34.0.0" + minSdkVersion = 23 + compileSdkVersion = 34 + targetSdkVersion = 34 + ndkVersion = "26.1.10909125" + kotlinVersion = "1.9.22" - // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. - ndkVersion = "23.1.7779620" + useExoplayerIMA = System.getenv("RNV_SAMPLE_ENABLE_ADS") ?: true + useExoplayerRtsp = true } repositories { google() mavenCentral() } - dependencies { - classpath("com.android.tools.build:gradle:7.3.0") +dependencies { + classpath("com.android.tools.build:gradle") classpath("com.facebook.react:react-native-gradle-plugin") - classpath("de.undercouch:gradle-download-task:5.0.1") classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" - classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion" - // NOTE: Do not place your application dependencies here; they belong - // in the individual module build.gradle files } } -allprojects { - repositories { - maven { - // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm - url("$rootDir/../node_modules/react-native/android") - } - maven { - // Android JSC is installed from npm - url("$rootDir/../node_modules/jsc-android/dist") - } - mavenCentral { - // We don't want to fetch react-native from Maven Central as there are - // older versions over there. - content { - excludeGroup "com.facebook.react" - } - } - google() - maven { url 'https://www.jitpack.io' } - } -} +apply plugin: "com.facebook.react.rootproject" \ No newline at end of file diff --git a/examples/FabricExample/android/gradle.properties b/examples/FabricExample/android/gradle.properties index 32810cc15a..a0f7834e59 100644 --- a/examples/FabricExample/android/gradle.properties +++ b/examples/FabricExample/android/gradle.properties @@ -24,9 +24,6 @@ android.useAndroidX=true # Automatically convert third-party libraries to use AndroidX android.enableJetifier=true -# Version of flipper SDK to use with React Native -FLIPPER_VERSION=0.125.0 - # Use this property to specify which architecture you want to build. # You can also override it from the CLI using # ./gradlew -PreactNativeArchitectures=x86_64 diff --git a/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.jar b/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d..7f93135c49 100644 Binary files a/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.jar and b/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.properties b/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.properties index 8fad3f5a98..d11cdd907d 100644 --- a/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.properties +++ b/examples/FabricExample/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-all.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/examples/FabricExample/android/gradlew b/examples/FabricExample/android/gradlew index 1b6c787337..547ba0c2aa 100755 --- a/examples/FabricExample/android/gradlew +++ b/examples/FabricExample/android/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,6 +198,10 @@ if "$cygwin" || "$msys" ; then done fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + # Collect all arguments for the java command; # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in @@ -205,6 +214,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. @@ -231,4 +246,4 @@ eval "set -- $( tr '\n' ' ' )" '"$@"' -exec "$JAVACMD" "$@" +exec "$JAVACMD" "$@" \ No newline at end of file diff --git a/examples/FabricExample/android/gradlew.bat b/examples/FabricExample/android/gradlew.bat index ac1b06f938..2b2bdaa139 100644 --- a/examples/FabricExample/android/gradlew.bat +++ b/examples/FabricExample/android/gradlew.bat @@ -70,6 +70,95 @@ goto fail set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* diff --git a/examples/FabricExample/android/settings.gradle b/examples/FabricExample/android/settings.gradle index e3f34c3fd8..e5a889bc8b 100644 --- a/examples/FabricExample/android/settings.gradle +++ b/examples/FabricExample/android/settings.gradle @@ -1,11 +1,11 @@ rootProject.name = 'FabricExample' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' -includeBuild('../node_modules/react-native-gradle-plugin') +includeBuild('../node_modules/@react-native/gradle-plugin') -if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { - include(":ReactAndroid") - project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') - include(":ReactAndroid:hermes-engine") - project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') -} +// if (settings.hasProperty("newArchEnabled") && settings.newArchEnabled == "true") { +// include(":ReactAndroid") +// project(":ReactAndroid").projectDir = file('../node_modules/react-native/ReactAndroid') +// include(":ReactAndroid:hermes-engine") +// project(":ReactAndroid:hermes-engine").projectDir = file('../node_modules/react-native/ReactAndroid/hermes-engine') +// } diff --git a/examples/FabricExample/babel.config.js b/examples/FabricExample/babel.config.js index 51c969cf73..bd1f13f222 100644 --- a/examples/FabricExample/babel.config.js +++ b/examples/FabricExample/babel.config.js @@ -2,7 +2,7 @@ const path = require('path'); const pak = require('../../package.json'); module.exports = { - presets: ['module:metro-react-native-babel-preset'], + presets: ['module:@react-native/babel-preset'], plugins: [ [ 'module-resolver', diff --git a/examples/FabricExample/ios/FabricExample.xcodeproj/project.pbxproj b/examples/FabricExample/ios/FabricExample.xcodeproj/project.pbxproj index 8ef48fc2d8..26875e8c76 100644 --- a/examples/FabricExample/ios/FabricExample.xcodeproj/project.pbxproj +++ b/examples/FabricExample/ios/FabricExample.xcodeproj/project.pbxproj @@ -437,7 +437,7 @@ "$(inherited)", ); INFOPLIST_FILE = FabricExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -461,7 +461,7 @@ BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; INFOPLIST_FILE = FabricExampleTests/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -535,7 +535,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -580,7 +580,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -592,18 +592,25 @@ ); MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRN_FABRIC_ENABLED", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", + "-DRN_FABRIC_ENABLED", ); OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; }; name = Debug; }; @@ -612,7 +619,7 @@ buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; - CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_CXX_LANGUAGE_STANDARD = "c++20"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; @@ -653,7 +660,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 12.4; + IPHONEOS_DEPLOYMENT_TARGET = 13.4; LD_RUNPATH_SEARCH_PATHS = ( /usr/lib/swift, "$(inherited)", @@ -664,18 +671,25 @@ "\"$(inherited)\"", ); MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "$(inherited)", + "-DRN_FABRIC_ENABLED", + ); OTHER_CPLUSPLUSFLAGS = ( "$(OTHER_CFLAGS)", "-DFOLLY_NO_CONFIG", "-DFOLLY_MOBILE=1", "-DFOLLY_USE_LIBCPP=1", + "-DRN_FABRIC_ENABLED", ); OTHER_LDFLAGS = ( "$(inherited)", - " ", + "-Wl", + "-ld_classic", ); REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native"; SDKROOT = iphoneos; + USE_HERMES = true; VALIDATE_PRODUCT = YES; }; name = Release; diff --git a/examples/FabricExample/ios/FabricExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/examples/FabricExample/ios/FabricExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/examples/FabricExample/ios/FabricExample.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/examples/FabricExample/ios/FabricExample/AppDelegate.h b/examples/FabricExample/ios/FabricExample/AppDelegate.h index ef1de86a2a..5d2808256c 100644 --- a/examples/FabricExample/ios/FabricExample/AppDelegate.h +++ b/examples/FabricExample/ios/FabricExample/AppDelegate.h @@ -1,8 +1,6 @@ -#import +#import #import -@interface AppDelegate : UIResponder - -@property (nonatomic, strong) UIWindow *window; +@interface AppDelegate : RCTAppDelegate @end diff --git a/examples/FabricExample/ios/FabricExample/AppDelegate.mm b/examples/FabricExample/ios/FabricExample/AppDelegate.mm index 42eee33f92..a429e31e21 100644 --- a/examples/FabricExample/ios/FabricExample/AppDelegate.mm +++ b/examples/FabricExample/ios/FabricExample/AppDelegate.mm @@ -1,88 +1,25 @@ #import "AppDelegate.h" -#import #import -#import - -#import - -#if RCT_NEW_ARCH_ENABLED -#import -#import -#import -#import -#import -#import - -#import - -static NSString *const kRNConcurrentRoot = @"concurrentRoot"; - -@interface AppDelegate () { - RCTTurboModuleManager *_turboModuleManager; - RCTSurfacePresenterBridgeAdapter *_bridgeAdapter; - std::shared_ptr _reactNativeConfig; - facebook::react::ContextContainer::Shared _contextContainer; -} -@end -#endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { - RCTAppSetupPrepareApp(application, true); - - RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; - -#if RCT_NEW_ARCH_ENABLED - _contextContainer = std::make_shared(); - _reactNativeConfig = std::make_shared(); - _contextContainer->insert("ReactNativeConfig", _reactNativeConfig); - _bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer]; - bridge.surfacePresenter = _bridgeAdapter.surfacePresenter; -#endif + self.moduleName = @"FabricExample"; + // You can add your custom initial props in the dictionary below. + // They will be passed down to the ViewController used by React Native. + self.initialProps = @{}; - NSDictionary *initProps = [self prepareInitialProps]; - UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"FabricExample", initProps, true); - - if (@available(iOS 13.0, *)) { - rootView.backgroundColor = [UIColor systemBackgroundColor]; - } else { - rootView.backgroundColor = [UIColor whiteColor]; - } - - self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; - UIViewController *rootViewController = [UIViewController new]; - rootViewController.view = rootView; - self.window.rootViewController = rootViewController; - [self.window makeKeyAndVisible]; - return YES; -} - -/// This method controls whether the `concurrentRoot`feature of React18 is turned on or off. -/// -/// @see: https://reactjs.org/blog/2022/03/29/react-v18.html -/// @note: This requires to be rendering on Fabric (i.e. on the New Architecture). -/// @return: `true` if the `concurrentRoot` feture is enabled. Otherwise, it returns `false`. -- (BOOL)concurrentRootEnabled -{ - // Switch this bool to turn on and off the concurrent root - return true; + return [super application:application didFinishLaunchingWithOptions:launchOptions]; } -- (NSDictionary *)prepareInitialProps +- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { - NSMutableDictionary *initProps = [NSMutableDictionary new]; - -#ifdef RCT_NEW_ARCH_ENABLED - initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]); -#endif - - return initProps; + return [self getBundleURL]; } -- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge +- (NSURL *)getBundleURL { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"]; @@ -91,43 +28,4 @@ - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge #endif } -#if RCT_NEW_ARCH_ENABLED - -#pragma mark - RCTCxxBridgeDelegate - -- (std::unique_ptr)jsExecutorFactoryForBridge:(RCTBridge *)bridge -{ - _turboModuleManager = [[RCTTurboModuleManager alloc] initWithBridge:bridge - delegate:self - jsInvoker:bridge.jsCallInvoker]; - return RCTAppSetupDefaultJsExecutorFactory(bridge, _turboModuleManager); -} - -#pragma mark RCTTurboModuleManagerDelegate - -- (Class)getModuleClassFromName:(const char *)name -{ - return RCTCoreModulesClassProvider(name); -} - -- (std::shared_ptr)getTurboModule:(const std::string &)name - jsInvoker:(std::shared_ptr)jsInvoker -{ - return nullptr; -} - -- (std::shared_ptr)getTurboModule:(const std::string &)name - initParams: - (const facebook::react::ObjCTurboModule::InitParams &)params -{ - return nullptr; -} - -- (id)getModuleInstanceFromClass:(Class)moduleClass -{ - return RCTAppSetupDefaultModuleFromClass(moduleClass); -} - -#endif - @end diff --git a/examples/FabricExample/ios/FabricExample/Info.plist b/examples/FabricExample/ios/FabricExample/Info.plist index 860ea180cb..b0cb3daca6 100644 --- a/examples/FabricExample/ios/FabricExample/Info.plist +++ b/examples/FabricExample/ios/FabricExample/Info.plist @@ -26,17 +26,13 @@ NSAppTransportSecurity - NSExceptionDomains - - localhost - - NSExceptionAllowsInsecureHTTPLoads - - - + NSAllowsArbitraryLoads + + NSAllowsLocalNetworking + NSLocationWhenInUseUsageDescription - + UILaunchStoryboardName LaunchScreen UIRequiredDeviceCapabilities diff --git a/examples/FabricExample/ios/Podfile b/examples/FabricExample/ios/Podfile index d39c16451c..eeaebf83d5 100644 --- a/examples/FabricExample/ios/Podfile +++ b/examples/FabricExample/ios/Podfile @@ -1,28 +1,25 @@ ENV['RCT_NEW_ARCH_ENABLED'] = "1" -require_relative '../node_modules/react-native/scripts/react_native_pods' -require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' -platform :ios, '12.4' +# Resolve react_native_pods.rb with node to allow for hoisting +require Pod::Executable.execute_command('node', ['-p', + 'require.resolve( + "react-native/scripts/react_native_pods.rb", + {paths: [process.argv[1]]}, + )', __dir__]).strip + +platform :ios, '13.4' install! 'cocoapods', :deterministic_uuids => false target 'FabricExample' do config = use_native_modules! - # Flags change depending on the env values. - flags = get_default_flags() - use_react_native!( :path => config[:reactNativePath], - # Hermes is now enabled by default. Disable by setting this flag to false. - # Upcoming versions of React Native may rely on get_default_flags(), but - # we make it explicit here to aid in the React Native upgrade process. - :hermes_enabled => true, - :fabric_enabled => flags[:fabric_enabled], # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. - :flipper_configuration => FlipperConfiguration.enabled, + # :flipper_configuration => FlipperConfiguration.enabled, # An absolute path to your application root. :app_path => "#{Pod::Config.instance.installation_root}/.." ) @@ -35,10 +32,8 @@ target 'FabricExample' do post_install do |installer| react_native_post_install( installer, - # Set `mac_catalyst_enabled` to `true` in order to apply patches - # necessary for Mac Catalyst builds + config[:reactNativePath], :mac_catalyst_enabled => false ) - __apply_Xcode_12_5_M1_post_install_workaround(installer) end end diff --git a/examples/FabricExample/ios/Podfile.lock b/examples/FabricExample/ios/Podfile.lock index cd35a33b95..f32f0f0d55 100644 --- a/examples/FabricExample/ios/Podfile.lock +++ b/examples/FabricExample/ios/Podfile.lock @@ -1,797 +1,1187 @@ PODS: - - boost (1.76.0) - - CocoaAsyncSocket (7.6.5) + - boost (1.83.0) - DoubleConversion (1.1.6) - - FBLazyVector (0.71.15) - - FBReactNativeSpec (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-Core (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - Flipper (0.125.0): - - Flipper-Folly (~> 2.6) - - Flipper-RSocket (~> 1.4) - - Flipper-Boost-iOSX (1.76.0.1.11) - - Flipper-DoubleConversion (3.2.0.1) - - Flipper-Fmt (7.1.7) - - Flipper-Folly (2.6.10): - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt (= 7.1.7) - - Flipper-Glog - - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - - Flipper-Glog (0.5.0.5) - - Flipper-PeerTalk (0.0.4) - - Flipper-RSocket (1.4.3): - - Flipper-Folly (~> 2.6) - - FlipperKit (0.125.0): - - FlipperKit/Core (= 0.125.0) - - FlipperKit/Core (0.125.0): - - Flipper (~> 0.125.0) - - FlipperKit/CppBridge - - FlipperKit/FBCxxFollyDynamicConvert - - FlipperKit/FBDefines - - FlipperKit/FKPortForwarding - - SocketRocket (~> 0.6.0) - - FlipperKit/CppBridge (0.125.0): - - Flipper (~> 0.125.0) - - FlipperKit/FBCxxFollyDynamicConvert (0.125.0): - - Flipper-Folly (~> 2.6) - - FlipperKit/FBDefines (0.125.0) - - FlipperKit/FKPortForwarding (0.125.0): - - CocoaAsyncSocket (~> 7.6) - - Flipper-PeerTalk (~> 0.0.4) - - FlipperKit/FlipperKitHighlightOverlay (0.125.0) - - FlipperKit/FlipperKitLayoutHelpers (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutTextSearchable - - FlipperKit/FlipperKitLayoutIOSDescriptors (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitHighlightOverlay - - FlipperKit/FlipperKitLayoutHelpers - - FlipperKit/FlipperKitLayoutIOSDescriptors - - FlipperKit/FlipperKitLayoutTextSearchable - - YogaKit (~> 1.18) - - FlipperKit/FlipperKitLayoutTextSearchable (0.125.0) - - FlipperKit/FlipperKitNetworkPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitReactPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitUserDefaultsPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/SKIOSNetworkPlugin (0.125.0): - - FlipperKit/Core - - FlipperKit/FlipperKitNetworkPlugin + - FBLazyVector (0.73.2) - fmt (6.2.1) - glog (0.3.5) - - hermes-engine (0.71.15): - - hermes-engine/Pre-built (= 0.71.15) - - hermes-engine/Pre-built (0.71.15) + - hermes-engine (0.73.2): + - hermes-engine/Pre-built (= 0.73.2) + - hermes-engine/Pre-built (0.73.2) - libevent (2.1.12) - - OpenSSL-Universal (1.1.1100) - - PromisesObjC (2.2.0) - - PromisesSwift (2.2.0): - - PromisesObjC (= 2.2.0) - - RCT-Folly (2021.07.22.00): + - RCT-Folly (2022.05.16.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Default (= 2021.07.22.00) - - RCT-Folly/Default (2021.07.22.00): + - RCT-Folly/Default (= 2022.05.16.00) + - RCT-Folly/Default (2022.05.16.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Fabric (2021.07.22.00): + - RCT-Folly/Fabric (2022.05.16.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - - RCT-Folly/Futures (2021.07.22.00): + - RCT-Folly/Futures (2022.05.16.00): - boost - DoubleConversion - fmt (~> 6.2.1) - glog - libevent - - RCTRequired (0.71.15) - - RCTTypeSafety (0.71.15): - - FBLazyVector (= 0.71.15) - - RCTRequired (= 0.71.15) - - React-Core (= 0.71.15) - - React (0.71.15): - - React-Core (= 0.71.15) - - React-Core/DevSupport (= 0.71.15) - - React-Core/RCTWebSocket (= 0.71.15) - - React-RCTActionSheet (= 0.71.15) - - React-RCTAnimation (= 0.71.15) - - React-RCTBlob (= 0.71.15) - - React-RCTImage (= 0.71.15) - - React-RCTLinking (= 0.71.15) - - React-RCTNetwork (= 0.71.15) - - React-RCTSettings (= 0.71.15) - - React-RCTText (= 0.71.15) - - React-RCTVibration (= 0.71.15) - - React-callinvoker (0.71.15) - - React-Codegen (0.71.15): - - FBReactNativeSpec + - RCTRequired (0.73.2) + - RCTTypeSafety (0.73.2): + - FBLazyVector (= 0.73.2) + - RCTRequired (= 0.73.2) + - React-Core (= 0.73.2) + - React (0.73.2): + - React-Core (= 0.73.2) + - React-Core/DevSupport (= 0.73.2) + - React-Core/RCTWebSocket (= 0.73.2) + - React-RCTActionSheet (= 0.73.2) + - React-RCTAnimation (= 0.73.2) + - React-RCTBlob (= 0.73.2) + - React-RCTImage (= 0.73.2) + - React-RCTLinking (= 0.73.2) + - React-RCTNetwork (= 0.73.2) + - React-RCTSettings (= 0.73.2) + - React-RCTText (= 0.73.2) + - React-RCTVibration (= 0.73.2) + - React-callinvoker (0.73.2) + - React-Codegen (0.73.2): + - DoubleConversion + - glog - hermes-engine - RCT-Folly - RCTRequired - RCTTypeSafety - React-Core + - React-debug + - React-Fabric + - React-FabricImage - React-graphics - React-jsi - React-jsiexecutor - - React-rncore + - React-NativeModulesApple + - React-rendererdebug + - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-Core (0.71.15): + - React-Core (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.15) - - React-cxxreact (= 0.71.15) + - RCT-Folly (= 2022.05.16.00) + - React-Core/Default (= 0.73.2) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/CoreModulesHeaders (0.71.15): + - React-Core/CoreModulesHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/Default (0.71.15): + - React-Core/Default (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.71.15) + - RCT-Folly (= 2022.05.16.00) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/DevSupport (0.71.15): + - React-Core/DevSupport (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.15) - - React-Core/RCTWebSocket (= 0.71.15) - - React-cxxreact (= 0.71.15) + - RCT-Folly (= 2022.05.16.00) + - React-Core/Default (= 0.73.2) + - React-Core/RCTWebSocket (= 0.73.2) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-jsinspector (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-jsinspector (= 0.73.2) + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTActionSheetHeaders (0.71.15): + - React-Core/RCTActionSheetHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTAnimationHeaders (0.71.15): + - React-Core/RCTAnimationHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTBlobHeaders (0.71.15): + - React-Core/RCTBlobHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTImageHeaders (0.71.15): + - React-Core/RCTImageHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTLinkingHeaders (0.71.15): + - React-Core/RCTLinkingHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTNetworkHeaders (0.71.15): + - React-Core/RCTNetworkHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTSettingsHeaders (0.71.15): + - React-Core/RCTSettingsHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTTextHeaders (0.71.15): + - React-Core/RCTTextHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTVibrationHeaders (0.71.15): + - React-Core/RCTVibrationHeaders (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) + - RCT-Folly (= 2022.05.16.00) - React-Core/Default - - React-cxxreact (= 0.71.15) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-Core/RCTWebSocket (0.71.15): + - React-Core/RCTWebSocket (0.73.2): - glog - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Core/Default (= 0.71.15) - - React-cxxreact (= 0.71.15) + - RCT-Folly (= 2022.05.16.00) + - React-Core/Default (= 0.73.2) + - React-cxxreact - React-hermes - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-perflogger (= 0.71.15) + - React-jsi + - React-jsiexecutor + - React-perflogger + - React-runtimescheduler + - React-utils + - SocketRocket (= 0.6.1) - Yoga - - React-CoreModules (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.15) - - React-Codegen (= 0.71.15) - - React-Core/CoreModulesHeaders (= 0.71.15) - - React-jsi (= 0.71.15) + - React-CoreModules (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - RCTTypeSafety (= 0.73.2) + - React-Codegen + - React-Core/CoreModulesHeaders (= 0.73.2) + - React-jsi (= 0.73.2) + - React-NativeModulesApple - React-RCTBlob - - React-RCTImage (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-cxxreact (0.71.15): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsinspector (= 0.71.15) - - React-logger (= 0.71.15) - - React-perflogger (= 0.71.15) - - React-runtimeexecutor (= 0.71.15) - - React-Fabric (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-Fabric/animations (= 0.71.15) - - React-Fabric/attributedstring (= 0.71.15) - - React-Fabric/butter (= 0.71.15) - - React-Fabric/componentregistry (= 0.71.15) - - React-Fabric/componentregistrynative (= 0.71.15) - - React-Fabric/components (= 0.71.15) - - React-Fabric/config (= 0.71.15) - - React-Fabric/core (= 0.71.15) - - React-Fabric/debug_core (= 0.71.15) - - React-Fabric/debug_renderer (= 0.71.15) - - React-Fabric/imagemanager (= 0.71.15) - - React-Fabric/leakchecker (= 0.71.15) - - React-Fabric/mapbuffer (= 0.71.15) - - React-Fabric/mounting (= 0.71.15) - - React-Fabric/runtimescheduler (= 0.71.15) - - React-Fabric/scheduler (= 0.71.15) - - React-Fabric/telemetry (= 0.71.15) - - React-Fabric/templateprocessor (= 0.71.15) - - React-Fabric/textlayoutmanager (= 0.71.15) - - React-Fabric/uimanager (= 0.71.15) - - React-Fabric/utils (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/animations (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/attributedstring (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/butter (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/componentregistry (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/componentregistrynative (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-Fabric/components/activityindicator (= 0.71.15) - - React-Fabric/components/image (= 0.71.15) - - React-Fabric/components/inputaccessory (= 0.71.15) - - React-Fabric/components/legacyviewmanagerinterop (= 0.71.15) - - React-Fabric/components/modal (= 0.71.15) - - React-Fabric/components/root (= 0.71.15) - - React-Fabric/components/safeareaview (= 0.71.15) - - React-Fabric/components/scrollview (= 0.71.15) - - React-Fabric/components/slider (= 0.71.15) - - React-Fabric/components/text (= 0.71.15) - - React-Fabric/components/textinput (= 0.71.15) - - React-Fabric/components/unimplementedview (= 0.71.15) - - React-Fabric/components/view (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/activityindicator (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/image (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/inputaccessory (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/legacyviewmanagerinterop (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/modal (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/root (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/safeareaview (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/scrollview (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/slider (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/text (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/textinput (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/unimplementedview (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/components/view (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) + - React-RCTImage (= 0.73.2) + - ReactCommon + - SocketRocket (= 0.6.1) + - React-cxxreact (0.73.2): + - boost (= 1.83.0) + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-callinvoker (= 0.73.2) + - React-debug (= 0.73.2) + - React-jsi (= 0.73.2) + - React-jsinspector (= 0.73.2) + - React-logger (= 0.73.2) + - React-perflogger (= 0.73.2) + - React-runtimeexecutor (= 0.73.2) + - React-debug (0.73.2) + - React-Fabric (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/animations (= 0.73.2) + - React-Fabric/attributedstring (= 0.73.2) + - React-Fabric/componentregistry (= 0.73.2) + - React-Fabric/componentregistrynative (= 0.73.2) + - React-Fabric/components (= 0.73.2) + - React-Fabric/core (= 0.73.2) + - React-Fabric/imagemanager (= 0.73.2) + - React-Fabric/leakchecker (= 0.73.2) + - React-Fabric/mounting (= 0.73.2) + - React-Fabric/scheduler (= 0.73.2) + - React-Fabric/telemetry (= 0.73.2) + - React-Fabric/templateprocessor (= 0.73.2) + - React-Fabric/textlayoutmanager (= 0.73.2) + - React-Fabric/uimanager (= 0.73.2) + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/animations (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/attributedstring (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistry (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/componentregistrynative (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-Fabric/components/inputaccessory (= 0.73.2) + - React-Fabric/components/legacyviewmanagerinterop (= 0.73.2) + - React-Fabric/components/modal (= 0.73.2) + - React-Fabric/components/rncore (= 0.73.2) + - React-Fabric/components/root (= 0.73.2) + - React-Fabric/components/safeareaview (= 0.73.2) + - React-Fabric/components/scrollview (= 0.73.2) + - React-Fabric/components/text (= 0.73.2) + - React-Fabric/components/textinput (= 0.73.2) + - React-Fabric/components/unimplementedview (= 0.73.2) + - React-Fabric/components/view (= 0.73.2) + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/inputaccessory (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/legacyviewmanagerinterop (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/modal (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/rncore (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/root (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/safeareaview (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/scrollview (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/text (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/textinput (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/unimplementedview (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/components/view (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core - Yoga - - React-Fabric/config (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/core (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/debug_core (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/debug_renderer (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/imagemanager (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - React-RCTImage (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/leakchecker (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/mapbuffer (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/mounting (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/runtimescheduler (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/scheduler (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/telemetry (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/templateprocessor (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/textlayoutmanager (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) + - React-Fabric/core (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/imagemanager (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/leakchecker (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/mounting (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/scheduler (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/telemetry (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/templateprocessor (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/textlayoutmanager (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug - React-Fabric/uimanager - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/uimanager (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-Fabric/utils (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - RCTRequired (= 0.71.15) - - RCTTypeSafety (= 0.71.15) - - React-graphics (= 0.71.15) - - React-jsi (= 0.71.15) - - React-jsiexecutor (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-graphics (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - React-Core/Default (= 0.71.15) - - React-hermes (0.71.15): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - RCT-Folly/Futures (= 2021.07.22.00) - - React-cxxreact (= 0.71.15) - - React-jsi - - React-jsiexecutor (= 0.71.15) - - React-jsinspector (= 0.71.15) - - React-perflogger (= 0.71.15) - - React-jsi (0.71.15): - - boost (= 1.76.0) - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-jsiexecutor (0.71.15): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-cxxreact (= 0.71.15) - - React-jsi (= 0.71.15) - - React-perflogger (= 0.71.15) - - React-jsinspector (0.71.15) - - React-logger (0.71.15): - - glog - - react-native-video (6.0.0-beta.4): - - React-Core - - react-native-video/Video (= 6.0.0-beta.4) - - react-native-video/Video (6.0.0-beta.4): - - PromisesSwift - - React-Core - - React-perflogger (0.71.15) - - React-RCTActionSheet (0.71.15): - - React-Core/RCTActionSheetHeaders (= 0.71.15) - - React-RCTAnimation (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.15) - - React-Codegen (= 0.71.15) - - React-Core/RCTAnimationHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTAppDelegate (0.71.15): + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-Fabric/uimanager (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Core + - React-cxxreact + - React-debug + - React-graphics + - React-jsi + - React-jsiexecutor + - React-logger + - React-rendererdebug + - React-runtimescheduler + - React-utils + - ReactCommon/turbomodule/core + - React-FabricImage (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - RCTRequired (= 0.73.2) + - RCTTypeSafety (= 0.73.2) + - React-Fabric + - React-graphics + - React-ImageManager + - React-jsi + - React-jsiexecutor (= 0.73.2) + - React-logger + - React-rendererdebug + - React-utils + - ReactCommon + - Yoga + - React-graphics (0.73.2): + - glog + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-Core/Default (= 0.73.2) + - React-utils + - React-hermes (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCT-Folly/Futures (= 2022.05.16.00) + - React-cxxreact (= 0.73.2) + - React-jsi + - React-jsiexecutor (= 0.73.2) + - React-jsinspector (= 0.73.2) + - React-perflogger (= 0.73.2) + - React-ImageManager (0.73.2): + - glog + - RCT-Folly/Fabric + - React-Core/Default + - React-debug + - React-Fabric + - React-graphics + - React-rendererdebug + - React-utils + - React-jserrorhandler (0.73.2): + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-debug + - React-jsi + - React-Mapbuffer + - React-jsi (0.73.2): + - boost (= 1.83.0) + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-jsiexecutor (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-cxxreact (= 0.73.2) + - React-jsi (= 0.73.2) + - React-perflogger (= 0.73.2) + - React-jsinspector (0.73.2) + - React-jsitracing (0.73.2): + - React-jsi + - React-logger (0.73.2): + - glog + - React-Mapbuffer (0.73.2): + - glog + - React-debug + - react-native-video (6.3.0): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - react-native-video/Video (= 6.3.0) + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-video/Fabric (6.3.0): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - react-native-video/Video (6.3.0): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - react-native-video/Fabric + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - React-nativeconfig (0.73.2) + - React-NativeModulesApple (0.73.2): + - glog + - hermes-engine + - React-callinvoker + - React-Core + - React-cxxreact + - React-jsi + - React-runtimeexecutor + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - React-perflogger (0.73.2) + - React-RCTActionSheet (0.73.2): + - React-Core/RCTActionSheetHeaders (= 0.73.2) + - React-RCTAnimation (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - RCTTypeSafety + - React-Codegen + - React-Core/RCTAnimationHeaders + - React-jsi + - React-NativeModulesApple + - ReactCommon + - React-RCTAppDelegate (0.73.2): - RCT-Folly - RCTRequired - RCTTypeSafety - React-Core + - React-CoreModules + - React-debug + - React-Fabric - React-graphics + - React-hermes + - React-nativeconfig + - React-NativeModulesApple - React-RCTFabric + - React-RCTImage + - React-RCTNetwork + - React-rendererdebug + - React-RuntimeApple + - React-RuntimeCore + - React-RuntimeHermes + - React-runtimescheduler + - React-utils + - ReactCommon + - React-RCTBlob (0.73.2): + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-Codegen + - React-Core/RCTBlobHeaders + - React-Core/RCTWebSocket + - React-jsi + - React-NativeModulesApple + - React-RCTNetwork + - ReactCommon + - React-RCTFabric (0.73.2): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-Core + - React-debug + - React-Fabric + - React-FabricImage + - React-graphics + - React-ImageManager + - React-jsi + - React-nativeconfig + - React-RCTImage + - React-RCTText + - React-rendererdebug + - React-runtimescheduler + - React-utils + - Yoga + - React-RCTImage (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - RCTTypeSafety + - React-Codegen + - React-Core/RCTImageHeaders + - React-jsi + - React-NativeModulesApple + - React-RCTNetwork + - ReactCommon + - React-RCTLinking (0.73.2): + - React-Codegen + - React-Core/RCTLinkingHeaders (= 0.73.2) + - React-jsi (= 0.73.2) + - React-NativeModulesApple + - ReactCommon + - ReactCommon/turbomodule/core (= 0.73.2) + - React-RCTNetwork (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - RCTTypeSafety + - React-Codegen + - React-Core/RCTNetworkHeaders + - React-jsi + - React-NativeModulesApple + - ReactCommon + - React-RCTSettings (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - RCTTypeSafety + - React-Codegen + - React-Core/RCTSettingsHeaders + - React-jsi + - React-NativeModulesApple + - ReactCommon + - React-RCTText (0.73.2): + - React-Core/RCTTextHeaders (= 0.73.2) + - Yoga + - React-RCTVibration (0.73.2): + - RCT-Folly (= 2022.05.16.00) + - React-Codegen + - React-Core/RCTVibrationHeaders + - React-jsi + - React-NativeModulesApple + - ReactCommon + - React-rendererdebug (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - RCT-Folly (= 2022.05.16.00) + - React-debug + - React-rncore (0.73.2) + - React-RuntimeApple (0.73.2): + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-callinvoker + - React-Core/Default + - React-CoreModules + - React-cxxreact + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-Mapbuffer + - React-NativeModulesApple + - React-RCTFabric + - React-RuntimeCore + - React-runtimeexecutor + - React-RuntimeHermes + - React-utils + - React-RuntimeCore (0.73.2): + - glog + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-cxxreact + - React-jserrorhandler + - React-jsi + - React-jsiexecutor + - React-runtimeexecutor + - React-runtimescheduler + - React-runtimeexecutor (0.73.2): + - React-jsi (= 0.73.2) + - React-RuntimeHermes (0.73.2): + - hermes-engine + - RCT-Folly/Fabric (= 2022.05.16.00) + - React-jsi + - React-jsitracing + - React-nativeconfig + - React-utils + - React-runtimescheduler (0.73.2): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-callinvoker + - React-cxxreact + - React-debug + - React-jsi + - React-rendererdebug + - React-runtimeexecutor + - React-utils + - React-utils (0.73.2): + - glog + - RCT-Folly (= 2022.05.16.00) + - React-debug + - ReactCommon (0.73.2): + - React-logger (= 0.73.2) + - ReactCommon/turbomodule (= 0.73.2) + - ReactCommon/turbomodule (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-callinvoker (= 0.73.2) + - React-cxxreact (= 0.73.2) + - React-jsi (= 0.73.2) + - React-logger (= 0.73.2) + - React-perflogger (= 0.73.2) + - ReactCommon/turbomodule/bridging (= 0.73.2) + - ReactCommon/turbomodule/core (= 0.73.2) + - ReactCommon/turbomodule/bridging (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-callinvoker (= 0.73.2) + - React-cxxreact (= 0.73.2) + - React-jsi (= 0.73.2) + - React-logger (= 0.73.2) + - React-perflogger (= 0.73.2) + - ReactCommon/turbomodule/core (0.73.2): + - DoubleConversion + - fmt (~> 6.2.1) + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - React-callinvoker (= 0.73.2) + - React-cxxreact (= 0.73.2) + - React-jsi (= 0.73.2) + - React-logger (= 0.73.2) + - React-perflogger (= 0.73.2) + - RNCPicker (2.7.5): + - glog + - hermes-engine + - RCT-Folly (= 2022.05.16.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-RCTBlob (0.71.15): - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.71.15) - - React-Core/RCTBlobHeaders (= 0.71.15) - - React-Core/RCTWebSocket (= 0.71.15) - - React-jsi (= 0.71.15) - - React-RCTNetwork (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTFabric (0.71.15): - - RCT-Folly/Fabric (= 2021.07.22.00) - - React-Core (= 0.71.15) - - React-Fabric (= 0.71.15) - - React-RCTImage (= 0.71.15) - - React-RCTImage (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.15) - - React-Codegen (= 0.71.15) - - React-Core/RCTImageHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - React-RCTNetwork (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTLinking (0.71.15): - - React-Codegen (= 0.71.15) - - React-Core/RCTLinkingHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTNetwork (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.15) - - React-Codegen (= 0.71.15) - - React-Core/RCTNetworkHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTSettings (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - RCTTypeSafety (= 0.71.15) - - React-Codegen (= 0.71.15) - - React-Core/RCTSettingsHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-RCTText (0.71.15): - - React-Core/RCTTextHeaders (= 0.71.15) - - React-RCTVibration (0.71.15): - - RCT-Folly (= 2021.07.22.00) - - React-Codegen (= 0.71.15) - - React-Core/RCTVibrationHeaders (= 0.71.15) - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/core (= 0.71.15) - - React-rncore (0.71.15) - - React-runtimeexecutor (0.71.15): - - React-jsi (= 0.71.15) - - ReactCommon/turbomodule/bridging (0.71.15): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.15) - - React-Core (= 0.71.15) - - React-cxxreact (= 0.71.15) - - React-jsi (= 0.71.15) - - React-logger (= 0.71.15) - - React-perflogger (= 0.71.15) - - ReactCommon/turbomodule/core (0.71.15): - - DoubleConversion - - glog - - hermes-engine - - RCT-Folly (= 2021.07.22.00) - - React-callinvoker (= 0.71.15) - - React-Core (= 0.71.15) - - React-cxxreact (= 0.71.15) - - React-jsi (= 0.71.15) - - React-logger (= 0.71.15) - - React-perflogger (= 0.71.15) - - SocketRocket (0.6.0) + - Yoga + - SocketRocket (0.6.1) - Yoga (1.14.0) - - YogaKit (1.18.1): - - Yoga (~> 1.14) DEPENDENCIES: - boost (from `../node_modules/react-native/third-party-podspecs/boost.podspec`) - DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`) - FBLazyVector (from `../node_modules/react-native/Libraries/FBLazyVector`) - - FBReactNativeSpec (from `../node_modules/react-native/React/FBReactNativeSpec`) - - Flipper (= 0.125.0) - - Flipper-Boost-iOSX (= 1.76.0.1.11) - - Flipper-DoubleConversion (= 3.2.0.1) - - Flipper-Fmt (= 7.1.7) - - Flipper-Folly (= 2.6.10) - - Flipper-Glog (= 0.5.0.5) - - Flipper-PeerTalk (= 0.0.4) - - Flipper-RSocket (= 1.4.3) - - FlipperKit (= 0.125.0) - - FlipperKit/Core (= 0.125.0) - - FlipperKit/CppBridge (= 0.125.0) - - FlipperKit/FBCxxFollyDynamicConvert (= 0.125.0) - - FlipperKit/FBDefines (= 0.125.0) - - FlipperKit/FKPortForwarding (= 0.125.0) - - FlipperKit/FlipperKitHighlightOverlay (= 0.125.0) - - FlipperKit/FlipperKitLayoutPlugin (= 0.125.0) - - FlipperKit/FlipperKitLayoutTextSearchable (= 0.125.0) - - FlipperKit/FlipperKitNetworkPlugin (= 0.125.0) - - FlipperKit/FlipperKitReactPlugin (= 0.125.0) - - FlipperKit/FlipperKitUserDefaultsPlugin (= 0.125.0) - - FlipperKit/SKIOSNetworkPlugin (= 0.125.0) - glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`) - hermes-engine (from `../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec`) - libevent (~> 2.1.12) - - OpenSSL-Universal (= 1.1.1100) - RCT-Folly (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCT-Folly/Fabric (from `../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec`) - RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`) @@ -800,18 +1190,25 @@ DEPENDENCIES: - React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`) - React-Codegen (from `build/generated/ios`) - React-Core (from `../node_modules/react-native/`) - - React-Core/DevSupport (from `../node_modules/react-native/`) - React-Core/RCTWebSocket (from `../node_modules/react-native/`) - React-CoreModules (from `../node_modules/react-native/React/CoreModules`) - React-cxxreact (from `../node_modules/react-native/ReactCommon/cxxreact`) + - React-debug (from `../node_modules/react-native/ReactCommon/react/debug`) - React-Fabric (from `../node_modules/react-native/ReactCommon`) + - React-FabricImage (from `../node_modules/react-native/ReactCommon`) - React-graphics (from `../node_modules/react-native/ReactCommon/react/renderer/graphics`) - React-hermes (from `../node_modules/react-native/ReactCommon/hermes`) + - React-ImageManager (from `../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios`) + - React-jserrorhandler (from `../node_modules/react-native/ReactCommon/jserrorhandler`) - React-jsi (from `../node_modules/react-native/ReactCommon/jsi`) - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) + - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector-modern`) + - React-jsitracing (from `../node_modules/react-native/ReactCommon/hermes/executor/`) - React-logger (from `../node_modules/react-native/ReactCommon/logger`) + - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - react-native-video (from `../../..`) + - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) + - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -824,30 +1221,23 @@ DEPENDENCIES: - React-RCTSettings (from `../node_modules/react-native/Libraries/Settings`) - React-RCTText (from `../node_modules/react-native/Libraries/Text`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) + - React-rendererdebug (from `../node_modules/react-native/ReactCommon/react/renderer/debug`) - React-rncore (from `../node_modules/react-native/ReactCommon`) + - React-RuntimeApple (from `../node_modules/react-native/ReactCommon/react/runtime/platform/ios`) + - React-RuntimeCore (from `../node_modules/react-native/ReactCommon/react/runtime`) - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) + - React-RuntimeHermes (from `../node_modules/react-native/ReactCommon/react/runtime`) + - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) + - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - "RNCPicker (from `../node_modules/@react-native-picker/picker`)" - Yoga (from `../node_modules/react-native/ReactCommon/yoga`) SPEC REPOS: trunk: - - CocoaAsyncSocket - - Flipper - - Flipper-Boost-iOSX - - Flipper-DoubleConversion - - Flipper-Fmt - - Flipper-Folly - - Flipper-Glog - - Flipper-PeerTalk - - Flipper-RSocket - - FlipperKit - fmt - libevent - - OpenSSL-Universal - - PromisesObjC - - PromisesSwift - SocketRocket - - YogaKit EXTERNAL SOURCES: boost: @@ -856,12 +1246,11 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec" FBLazyVector: :path: "../node_modules/react-native/Libraries/FBLazyVector" - FBReactNativeSpec: - :path: "../node_modules/react-native/React/FBReactNativeSpec" glog: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2023-11-17-RNv0.73.0-21043a3fc062be445e56a2c10ecd8be028dd9cc5 RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTRequired: @@ -880,22 +1269,38 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/React/CoreModules" React-cxxreact: :path: "../node_modules/react-native/ReactCommon/cxxreact" + React-debug: + :path: "../node_modules/react-native/ReactCommon/react/debug" React-Fabric: :path: "../node_modules/react-native/ReactCommon" + React-FabricImage: + :path: "../node_modules/react-native/ReactCommon" React-graphics: :path: "../node_modules/react-native/ReactCommon/react/renderer/graphics" React-hermes: :path: "../node_modules/react-native/ReactCommon/hermes" + React-ImageManager: + :path: "../node_modules/react-native/ReactCommon/react/renderer/imagemanager/platform/ios" + React-jserrorhandler: + :path: "../node_modules/react-native/ReactCommon/jserrorhandler" React-jsi: :path: "../node_modules/react-native/ReactCommon/jsi" React-jsiexecutor: :path: "../node_modules/react-native/ReactCommon/jsiexecutor" React-jsinspector: - :path: "../node_modules/react-native/ReactCommon/jsinspector" + :path: "../node_modules/react-native/ReactCommon/jsinspector-modern" + React-jsitracing: + :path: "../node_modules/react-native/ReactCommon/hermes/executor/" React-logger: :path: "../node_modules/react-native/ReactCommon/logger" + React-Mapbuffer: + :path: "../node_modules/react-native/ReactCommon" react-native-video: :path: "../../.." + React-nativeconfig: + :path: "../node_modules/react-native/ReactCommon" + React-NativeModulesApple: + :path: "../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios" React-perflogger: :path: "../node_modules/react-native/ReactCommon/reactperflogger" React-RCTActionSheet: @@ -920,73 +1325,87 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/Libraries/Text" React-RCTVibration: :path: "../node_modules/react-native/Libraries/Vibration" + React-rendererdebug: + :path: "../node_modules/react-native/ReactCommon/react/renderer/debug" React-rncore: :path: "../node_modules/react-native/ReactCommon" + React-RuntimeApple: + :path: "../node_modules/react-native/ReactCommon/react/runtime/platform/ios" + React-RuntimeCore: + :path: "../node_modules/react-native/ReactCommon/react/runtime" React-runtimeexecutor: :path: "../node_modules/react-native/ReactCommon/runtimeexecutor" + React-RuntimeHermes: + :path: "../node_modules/react-native/ReactCommon/react/runtime" + React-runtimescheduler: + :path: "../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler" + React-utils: + :path: "../node_modules/react-native/ReactCommon/react/utils" ReactCommon: :path: "../node_modules/react-native/ReactCommon" + RNCPicker: + :path: "../node_modules/@react-native-picker/picker" Yoga: :path: "../node_modules/react-native/ReactCommon/yoga" SPEC CHECKSUMS: - boost: 7dcd2de282d72e344012f7d6564d024930a6a440 - CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 - DoubleConversion: 5189b271737e1565bdce30deb4a08d647e3f5f54 - FBLazyVector: d06bbe89e3a89ee90c4deab1c84bf306ffa5ed37 - FBReactNativeSpec: 6fecc43741c2aed59c2bc6ba2c2f486014e03521 - Flipper: 26fc4b7382499f1281eb8cb921e5c3ad6de91fe0 - Flipper-Boost-iOSX: fd1e2b8cbef7e662a122412d7ac5f5bea715403c - Flipper-DoubleConversion: 2dc99b02f658daf147069aad9dbd29d8feb06d30 - Flipper-Fmt: 60cbdd92fc254826e61d669a5d87ef7015396a9b - Flipper-Folly: 584845625005ff068a6ebf41f857f468decd26b3 - Flipper-Glog: 70c50ce58ddaf67dc35180db05f191692570f446 - Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 - Flipper-RSocket: d9d9ade67cbecf6ac10730304bf5607266dd2541 - FlipperKit: cbdee19bdd4e7f05472a66ce290f1b729ba3cb86 + boost: d3f49c53809116a5d38da093a8aa78bf551aed09 + DoubleConversion: fea03f2699887d960129cc54bba7e52542b6f953 + FBLazyVector: fbc4957d9aa695250b55d879c1d86f79d7e69ab4 fmt: ff9d55029c625d3757ed641535fd4a75fedc7ce9 - glog: 04b94705f318337d7ead9e6d17c019bd9b1f6b1b - hermes-engine: 04437e4291ede4af0c76c25e7efd0eacb8fd25e5 + glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 + hermes-engine: b361c9ef5ef3cda53f66e195599b47e1f84ffa35 libevent: 4049cae6c81cdb3654a443be001fb9bdceff7913 - OpenSSL-Universal: ebc357f1e6bc71fa463ccb2fe676756aff50e88c - PromisesObjC: 09985d6d70fbe7878040aa746d78236e6946d2ef - PromisesSwift: cf9eb58666a43bbe007302226e510b16c1e10959 - RCT-Folly: 424b8c9a7a0b9ab2886ffe9c3b041ef628fd4fb1 - RCTRequired: 4ce9da4fa2f8a134f62c70e4ab9d971b9d640f41 - RCTTypeSafety: decfec2884f0c523f799600d2b6105cdc15e13db - React: ca22a0b3f199b6acac95416ef7eb96cc84a55103 - React-callinvoker: 366d4449bc2901e89da3f30c6d203c491d060350 - React-Codegen: 6fe71a7e025aa51e73b66ebb092d59a2a7701bae - React-Core: 169395096d2c22872e22cd74e3694a4b041cce76 - React-CoreModules: 8c2a970d9fd778e6016b9297f2c2dddbe78b04ec - React-cxxreact: e61b3e92887bb8fc241326b83d667953ff732923 - React-Fabric: f4ddd27dc414581018db9cbdd362c80e77b08eca - React-graphics: 516c3bb35198e4a2531fd52ab6cfc681dad71874 - React-hermes: 476b93736605b457d1bc390336656c94460205b7 - React-jsi: 9fe8766963aa3aea90bbd477ea63255eb847d404 - React-jsiexecutor: e0cde8d57cee18097b3d2b1bf6404ad25dd8d33b - React-jsinspector: 4ade58a6a355d97a53f847543b14f4cb5033cb70 - React-logger: 56699550750c013096a11dce3bc996e7dd583835 - react-native-video: 6078b448c21630b0a2937436527ad54fd2a1fdd8 - React-perflogger: 0cc42978a483a47f3696171dac2e7033936fc82d - React-RCTActionSheet: ea922b476d24f6d40b8e02ac3228412bd3637468 - React-RCTAnimation: 7be2c148398eaa5beac950b2b5ec7102389ec3ad - React-RCTAppDelegate: dc57448e65541509565b59518e8a81e30ae69bd7 - React-RCTBlob: c1e1e53b334f36b3311c3206036c99f4e5406cdf - React-RCTFabric: 42e8e9067f73fdb2e9d12f0b09003cd49d3da139 - React-RCTImage: 4a2cd71dd8c1954cfab50e244b269d47bdcc76da - React-RCTLinking: c8ff9fe7f5741afc05894c7da4a0d2bd1458f247 - React-RCTNetwork: 93c329744baa8c04057a5a29b790618e0c2a6a68 - React-RCTSettings: bcd09cd3ee26967bdfbc8af174404b8ffabfbc3c - React-RCTText: c525eb78cfe9489f130fa69004ff081a5ae33e06 - React-RCTVibration: a97783e3645ddf852e34da2e015656e309f3a083 - React-rncore: 0fc98082b749bad91dbb7a4bca9cb53386477c81 - React-runtimeexecutor: 8f2ddd9db7874ec7de84f5c55d73aeaaf82908e2 - ReactCommon: 309d965cb51f058d07dea65bc04dcf462911f0a4 - SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608 - Yoga: 68c9c592c3e80ec37ff28db20eedb13d84aae5df - YogaKit: f782866e155069a2cca2517aafea43200b01fd5a + RCT-Folly: 7169b2b1c44399c76a47b5deaaba715eeeb476c0 + RCTRequired: 9b1e7e262745fb671e33c51c1078d093bd30e322 + RCTTypeSafety: a759e3b086eccf3e2cbf2493d22f28e082f958e6 + React: 805f5dd55bbdb92c36b4914c64aaae4c97d358dc + React-callinvoker: 6a697867607c990c2c2c085296ee32cfb5e47c01 + React-Codegen: f3cb992539e5c21675f087e536d64b1f2a448655 + React-Core: 49f66fecc7695464e9b7bc7dc7cd9473d2c60584 + React-CoreModules: 710e7c557a1a8180bd1645f5b4bf79f4bd3f5417 + React-cxxreact: 345857b5e4be000c0527df78be3b41a0677a20ce + React-debug: f1637bce73342b2f6eee4982508fdfb088667a87 + React-Fabric: 4dfcff8f14d8e5a7a60b11b7862dad2a9d99c65b + React-FabricImage: 4a9e9510b7f28bbde6a743b18c0cb941a142e938 + React-graphics: dd5af9d8b1b45171fd6933e19fed522f373bcb10 + React-hermes: a52d183a5cf8ccb7020ce3df4275b89d01e6b53e + React-ImageManager: c5b7db131eff71443d7f3a8d686fd841d18befd3 + React-jserrorhandler: 97a6a12e2344c3c4fdd7ba1edefb005215c732f8 + React-jsi: a182068133f80918cd0eec77875abaf943a0b6be + React-jsiexecutor: dacd00ce8a18fc00a0ae6c25e3015a6437e5d2e8 + React-jsinspector: 03644c063fc3621c9a4e8bf263a8150909129618 + React-jsitracing: 7c77101b38fcc8fa7f198de7e1d834350a85af90 + React-logger: 66b168e2b2bee57bd8ce9e69f739d805732a5570 + React-Mapbuffer: 9ee041e1d7be96da6d76a251f92e72b711c651d6 + react-native-video: 033a57e0fffd1a8fa5cbe8ae3a01b71029032f62 + React-nativeconfig: d753fbbc8cecc8ae413d615599ac378bbf6999bb + React-NativeModulesApple: 964f4eeab1b4325e8b6a799cf4444c3fd4eb0a9c + React-perflogger: 29efe63b7ef5fbaaa50ef6eaa92482f98a24b97e + React-RCTActionSheet: 69134c62aefd362027b20da01cd5d14ffd39db3f + React-RCTAnimation: 3b5a57087c7a5e727855b803d643ac1d445488f5 + React-RCTAppDelegate: cb1a9a8447ddad006f934988016390f4df472e74 + React-RCTBlob: 26ea660f2be1e6de62f2d2ad9a9c7b9bfabb786f + React-RCTFabric: bb6dbbff2f80b9489f8b2f1d2554aa040aa2e3cd + React-RCTImage: 27b27f4663df9e776d0549ed2f3536213e793f1b + React-RCTLinking: 962880ce9d0e2ea83fd182953538fc4ed757d4da + React-RCTNetwork: 73a756b44d4ad584bae13a5f1484e3ce12accac8 + React-RCTSettings: 6d7f8d807f05de3d01cfb182d14e5f400716faac + React-RCTText: 73006e95ca359595c2510c1c0114027c85a6ddd3 + React-RCTVibration: 599f427f9cbdd9c4bf38959ca020e8fef0717211 + React-rendererdebug: f2946e0a1c3b906e71555a7c4a39aa6a6c0e639b + React-rncore: 6e3139cf51cea08068f008da426821d1deaa24b9 + React-RuntimeApple: 08c29690996ed935e35054965bcfb70ebea67318 + React-RuntimeCore: 5b73f40b46d78a825cf71714e1e5044d389702d6 + React-runtimeexecutor: 2d1f64f58193f00a3ad71d3f89c2bfbfe11cf5a5 + React-RuntimeHermes: 01dcb5a4e9073496f6f981a8648843771e3f6516 + React-runtimescheduler: df8945a656356ff10f58f65a70820478bfcf33ad + React-utils: f5bc61e7ea3325c0732ae2d755f4441940163b85 + ReactCommon: 45b5d4f784e869c44a6f5a8fad5b114ca8f78c53 + RNCPicker: 6ce7e81292cec4ddf1a5eeaeec00c31206e9e134 + SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17 + Yoga: e64aa65de36c0832d04e8c7bd614396c77a80047 -PODFILE CHECKSUM: 780eb8fa466e7a1ad2e9200598bc65585b637433 +PODFILE CHECKSUM: cf04724bfafa2ca6f6877a9a65072610a4b6ed7c -COCOAPODS: 1.12.0 +COCOAPODS: 1.15.2 diff --git a/examples/FabricExample/jest.config.js b/examples/FabricExample/jest.config.js new file mode 100644 index 0000000000..8130feaddf --- /dev/null +++ b/examples/FabricExample/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + preset: 'react-native', +}; \ No newline at end of file diff --git a/examples/FabricExample/metro.config.js b/examples/FabricExample/metro.config.js index 46475fb308..b5f681a802 100644 --- a/examples/FabricExample/metro.config.js +++ b/examples/FabricExample/metro.config.js @@ -2,6 +2,7 @@ const path = require('path'); const escape = require('escape-string-regexp'); const exclusionList = require('metro-config/src/defaults/exclusionList'); const pak = require('../../package.json'); +const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config'); const root = path.resolve(__dirname, '../../'); @@ -9,7 +10,7 @@ const modules = Object.keys({ ...pak.peerDependencies, }); -module.exports = { +const config = { projectRoot: __dirname, watchFolders: [root], @@ -37,4 +38,6 @@ module.exports = { }, }), }, -}; +} + +module.exports = mergeConfig(getDefaultConfig(__dirname), config); diff --git a/examples/FabricExample/package.json b/examples/FabricExample/package.json index bbb234ad45..2fdbd92d70 100644 --- a/examples/FabricExample/package.json +++ b/examples/FabricExample/package.json @@ -11,27 +11,33 @@ "pod-install": "bundle exec npx pod-install --project-directory=ios --verbose" }, "dependencies": { + "@react-native-picker/picker": "2.7.5", "react": "18.1.0", - "react-native": "^0.71.6" + "react-native": "0.73.2" }, "devDependencies": { "@babel/core": "^7.12.9", "@babel/runtime": "^7.12.5", "@react-native-community/eslint-config": "^2.0.0", + "@react-native/babel-preset": "0.73.19", + "@react-native/eslint-config": "0.73.2", + "@react-native/metro-config": "0.73.3", + "@react-native/typescript-config": "0.73.1", "@tsconfig/react-native": "^2.0.2", "@types/jest": "^26.0.23", - "@types/react": "^18.0.21", + "@types/react": "^18.2.6", "@types/react-native": "^0.70.6", "@types/react-test-renderer": "^18.0.0", "@typescript-eslint/eslint-plugin": "^5.37.0", "@typescript-eslint/parser": "^5.37.0", - "babel-jest": "^26.6.3", + "babel-jest": "^29.6.3", "babel-plugin-module-resolver": "^5.0.0", "eslint": "^7.32.0", - "jest": "^26.6.3", + "jest": "^29.6.3", "metro-react-native-babel-preset": "0.72.3", + "prettier": "2.8.8", "react-test-renderer": "18.1.0", - "typescript": "^4.8.3" + "typescript": "5.0.4" }, "jest": { "preset": "react-native", @@ -43,5 +49,8 @@ "json", "node" ] + }, + "engines": { + "node": ">=18" } } diff --git a/examples/FabricExample/src/MultiValueControl.tsx b/examples/FabricExample/src/MultiValueControl.tsx new file mode 100644 index 0000000000..bf58f3a96a --- /dev/null +++ b/examples/FabricExample/src/MultiValueControl.tsx @@ -0,0 +1,75 @@ +import React, {FunctionComponent} from 'react'; + +import { + StyleSheet, + Text, + TextStyle, + TouchableOpacity, + View, +} from 'react-native'; +import {ResizeMode} from 'react-native-video'; + +export type MultiValueControlPropType = number | string | ResizeMode; + +/* + * MultiValueControl displays a list clickable text view + */ + +interface MultiValueControlType { + // a list a string or number to be displayed + values: Array; + // The selected value in values + selected?: T; + // callback to press onPress + onPress: (arg: MultiValueControlPropType) => void; +} + +const MultiValueControl: FunctionComponent< + MultiValueControlType +> = ({values, selected, onPress}) => { + const selectedStyle: TextStyle = StyleSheet.flatten([ + styles.option, + {fontWeight: 'bold'}, + ]); + + const unselectedStyle: TextStyle = StyleSheet.flatten([ + styles.option, + {fontWeight: 'normal'}, + ]); + + return ( + + {values.map((value: MultiValueControlPropType) => { + const _style = value === selected ? selectedStyle : unselectedStyle; + return ( + { + onPress?.(value); + }}> + {value} + + ); + })} + + ); +}; + +const styles = StyleSheet.create({ + option: { + alignSelf: 'center', + fontSize: 11, + color: 'white', + paddingLeft: 2, + paddingRight: 2, + lineHeight: 12, + }, + container: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, +}); + +export default MultiValueControl; diff --git a/examples/FabricExample/src/ToggleControl.tsx b/examples/FabricExample/src/ToggleControl.tsx new file mode 100644 index 0000000000..fd5f83a509 --- /dev/null +++ b/examples/FabricExample/src/ToggleControl.tsx @@ -0,0 +1,73 @@ +import React from 'react'; + +import { + StyleSheet, + Text, + TextStyle, + TouchableOpacity, + View, +} from 'react-native'; + +/* + * ToggleControl displays a 2 states clickable text + */ + +interface ToggleControlType { + // boolean indicating if text is selected state + isSelected?: boolean; + // value of text when selected + selectedText?: string; + // value of text when NOT selected + unselectedText?: string; + // default text if no only one text field is needed + text?: string; + // callback called when pressing the component + onPress: () => void; +} + +const ToggleControl = ({ + isSelected, + selectedText, + unselectedText, + text, + onPress, +}: ToggleControlType) => { + const selectedStyle: TextStyle = StyleSheet.flatten([ + styles.controlOption, + {fontWeight: 'bold'}, + ]); + + const unselectedStyle: TextStyle = StyleSheet.flatten([ + styles.controlOption, + {fontWeight: 'normal'}, + ]); + + const style = isSelected ? selectedStyle : unselectedStyle; + const _text = text ? text : isSelected ? selectedText : unselectedText; + return ( + + + {_text} + + + ); +}; + +const styles = StyleSheet.create({ + controlOption: { + alignSelf: 'center', + fontSize: 11, + color: 'white', + paddingLeft: 2, + paddingRight: 2, + lineHeight: 12, + }, + resizeModeControl: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, +}); + +export default ToggleControl; diff --git a/examples/FabricExample/src/VideoPlayer.tsx b/examples/FabricExample/src/VideoPlayer.tsx index 34a4776b94..ba12f40314 100644 --- a/examples/FabricExample/src/VideoPlayer.tsx +++ b/examples/FabricExample/src/VideoPlayer.tsx @@ -1,557 +1,831 @@ 'use strict'; -import React, {Component, createRef} from 'react'; + +import React, {Component} from 'react'; import { - Alert, - GestureResponderEvent, - Platform, - StyleSheet, Text, TouchableOpacity, View, + ActivityIndicator, + ToastAndroid, + Platform, + Alert, } from 'react-native'; -import Video, {FilterType, VideoRef, ResizeMode, IgnoreSilentSwitchType, MixWithOthersType} from 'react-native-video'; - -const filterTypes = [ - FilterType.NONE, - FilterType.INVERT, - FilterType.MONOCHROME, - FilterType.POSTERIZE, - FilterType.FALSE, - FilterType.MAXIMUMCOMPONENT, - FilterType.MINIMUMCOMPONENT, - FilterType.CHROME, - FilterType.FADE, - FilterType.INSTANT, - FilterType.MONO, - FilterType.NOIR, - FilterType.PROCESS, - FilterType.TONAL, - FilterType.TRANSFER, - FilterType.SEPIA, -]; - -type SkinType = 'custom' | 'native' | 'embed' - -type State = { - rate: number, - volume: number, - muted: boolean, - resizeMode: ResizeMode, - duration: number, - currentTime: number, - controls: boolean, - paused: boolean, - skin: SkinType, - ignoreSilentSwitch: IgnoreSilentSwitchType, - mixWithOthers: MixWithOthersType, - isBuffering: boolean, - filter: FilterType, - filterEnabled: boolean, +import Video, { + AudioTrack, + OnAudioTracksData, + OnLoadData, + OnProgressData, + OnTextTracksData, + OnVideoAspectRatioData, + TextTrack, + VideoDecoderProperties, + OnBufferData, + OnAudioFocusChangedData, + OnVideoErrorData, + VideoRef, + ResizeMode, + SelectedTrack, + DRMType, + OnTextTrackDataChangedData, + TextTrackType, + ISO639_1, + OnSeekData, + OnPlaybackStateChangedData, + OnPlaybackRateChangeData, + OnVideoTracksData, + VideoTrack, + SelectedVideoTrackType, + SelectedVideoTrack, + BufferingStrategyType, + ReactVideoSource, + Drm, + TextTracks, +} from 'react-native-video'; +import ToggleControl from './ToggleControl'; +import MultiValueControl, { + MultiValueControlPropType, +} from './MultiValueControl'; +import styles from './styles'; +import AudioTrackSelector from './components/AudioTracksSelector'; +import TextTrackSelector from './components/TextTracksSelector'; +import VideoTrackSelector from './components/VideoTracksSelector'; +import Seeker from './components/Seeker'; + +type AdditionnalSourceInfo = { + textTracks: TextTracks; + adTagUrl: string; + description: string; + drm: Drm; + noView: boolean; +}; + +type SampleVideoSource = ReactVideoSource | AdditionnalSourceInfo; + +interface StateType { + rate: number; + volume: number; + muted: boolean; + resizeMode: ResizeMode; + duration: number; + currentTime: number; + videoWidth: number; + videoHeight: number; + paused: boolean; + fullscreen: true; + decoration: true; + isLoading: boolean; + audioTracks: Array; + textTracks: Array; + videoTracks: Array; + selectedAudioTrack: SelectedTrack | undefined; + selectedTextTrack: SelectedTrack | undefined; + selectedVideoTrack: SelectedVideoTrack; + srcListId: number; + loop: boolean; + showRNVControls: boolean; + useCache: boolean; + poster?: string; + showNotificationControls: boolean; + isSeeking: boolean; } -class VideoPlayer extends Component<{}, State> { - controlRef: React.RefObject; - videoRef: React.RefObject; - constructor(props: any) { - super(props); - this.onLoad = this.onLoad.bind(this); - this.onProgress = this.onProgress.bind(this); - this.onBuffer = this.onBuffer.bind(this); - this.onTouchControl = this.onTouchControl.bind(this); - this.controlRef = createRef(); - this.videoRef = createRef(); - } - state: State = { +class VideoPlayer extends Component { + state: StateType = { rate: 1, volume: 1, muted: false, resizeMode: ResizeMode.CONTAIN, duration: 0.0, currentTime: 0.0, - controls: false, - paused: true, - skin: 'custom', - ignoreSilentSwitch: IgnoreSilentSwitchType.IGNORE, - mixWithOthers: MixWithOthersType.DUCK, - isBuffering: false, - filter: FilterType.NONE, - filterEnabled: true, + videoWidth: 0, + videoHeight: 0, + paused: false, + fullscreen: true, + decoration: true, + isLoading: false, + audioTracks: [], + textTracks: [], + videoTracks: [], + selectedAudioTrack: undefined, + selectedTextTrack: undefined, + selectedVideoTrack: { + type: SelectedVideoTrackType.AUTO, + }, + srcListId: 0, + loop: false, + showRNVControls: false, + useCache: false, + poster: undefined, + showNotificationControls: false, + isSeeking: false, }; - onLoad(data: any) { - console.log('On load fired!'); - console.log(data.duration); - this.setState({duration: data.duration}); - } + // internal usage change to index if you want to select tracks by index instead of lang + textTracksSelectionBy = 'index'; + + srcAllPlatformList = [ + { + description: 'local file landscape', + uri: require('./broadchurch.mp4'), + }, + { + description: 'local file landscape cropped', + uri: require('./broadchurch.mp4'), + cropStart: 3000, + cropEnd: 10000, + }, + { + description: 'local file portrait', + uri: require('./portrait.mp4'), + metadata: { + title: 'Test Title', + subtitle: 'Test Subtitle', + artist: 'Test Artist', + description: 'Test Description', + imageUri: + 'https://pbs.twimg.com/profile_images/1498641868397191170/6qW2XkuI_400x400.png', + }, + }, + { + description: '(hls|live) red bull tv', + textTracksAllowChunklessPreparation: false, + uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8', + metadata: { + title: 'Custom Title', + subtitle: 'Custom Subtitle', + artist: 'Custom Artist', + description: 'Custom Description', + imageUri: + 'https://pbs.twimg.com/profile_images/1498641868397191170/6qW2XkuI_400x400.png', + }, + }, + { + description: 'invalid URL', + uri: 'mmt://www.youtube.com', + type: 'mpd', + }, + {description: '(no url) Stopped playback', uri: undefined}, + { + description: '(no view) no View', + noView: true, + }, + { + description: 'Another live sample', + uri: 'https://live.forstreet.cl/live/livestream.m3u8', + }, + { + description: 'another bunny (can be saved)', + uri: 'https://rawgit.com/mediaelement/mediaelement-files/master/big_buck_bunny.mp4', + headers: {referer: 'www.github.com', 'User-Agent': 'react.native.video'}, + }, + { + description: 'sintel with subtitles', + uri: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8', + }, + { + description: 'sintel starts at 20sec', + uri: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8', + startPosition: 50000, + }, + { + description: 'BigBugBunny sideLoaded subtitles', + // sideloaded subtitles wont work for streaming like HLS on ios + // mp4 + uri: 'https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', + textTracks: [ + { + title: 'test', + language: 'en' as ISO639_1, + type: TextTrackType.VTT, + uri: 'https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt', + }, + ], + }, + ]; + + srcIosList = []; + + srcAndroidList = [ + { + description: 'Another live sample', + uri: 'https://live.forstreet.cl/live/livestream.m3u8', + }, + { + description: 'asset file', + uri: 'asset:///broadchurch.mp4', + }, + { + description: '(dash) sintel subtitles', + uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd', + }, + { + description: '(mp4) big buck bunny', + uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', + }, + { + description: '(mp4|subtitles) demo with sintel Subtitles', + uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', + type: 'mpd', + }, + { + description: '(mp4) big buck bunny With Ads', + adTagUrl: + 'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=', + uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', + }, + { + description: 'WV: Secure SD & HD (cbcs,MP4,H264)', + uri: 'https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd', + drm: { + type: DRMType.WIDEVINE, + licenseServer: + 'https://proxy.uat.widevine.com/proxy?provider=widevine_test', + }, + }, + { + description: 'Secure UHD (cenc)', + uri: 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd', + drm: { + type: DRMType.WIDEVINE, + licenseServer: + 'https://proxy.uat.widevine.com/proxy?provider=widevine_test', + }, + }, + { + description: 'rtsp big bug bunny', + uri: 'rtsp://rtspstream:3cfa3c36a9c00f4aa38f3cd35816b287@zephyr.rtsp.stream/movie', + type: 'rtsp', + }, + ]; + + // poster which can be displayed + samplePoster = + 'https://upload.wikimedia.org/wikipedia/commons/1/18/React_Native_Logo.png'; + + srcList: SampleVideoSource[] = this.srcAllPlatformList.concat( + Platform.OS === 'android' ? this.srcAndroidList : this.srcIosList, + ); + + video?: VideoRef; + + popupInfo = () => { + VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => { + VideoDecoderProperties.isHEVCSupported().then((hevc: string) => { + VideoDecoderProperties.isCodecSupported('video/avc', 1920, 1080).then( + (avc: string) => { + this.toast( + true, + 'Widevine level: ' + + widevineLevel + + '\n hevc: ' + + hevc + + '\n avc: ' + + avc, + ); + }, + ); + }); + }); + }; - onProgress(data: any) { + onLoad = (data: OnLoadData) => { + this.setState({duration: data.duration, loading: false}); + this.onAudioTracks(data); + this.onTextTracks(data); + this.onVideoTracks(data); + }; + + onProgress = (data: OnProgressData) => { this.setState({currentTime: data.currentTime}); - } + }; - onBuffer({isBuffering}: {isBuffering: boolean}) { - this.setState({isBuffering}); - } + onSeek = (data: OnSeekData) => { + this.setState({isSeeking: false}); + this.setState({currentTime: data.currentTime}); + }; - onTouchControl(e: GestureResponderEvent) { - if (!this.controlRef.current || !this.videoRef.current) return; - const videoCommands = this.videoRef.current; - const touchX = e.nativeEvent.pageX; - const duration = this.state.duration; + onVideoLoadStart = () => { + console.log('onVideoLoadStart'); + this.setState({isLoading: true}); + }; - this.controlRef.current.measureInWindow((x, y, width, height) => { - const relativeX = touchX - x; - const nextTime = (relativeX / width) * duration; - videoCommands.seek(nextTime); + onAudioTracks = (data: OnAudioTracksData) => { + const selectedTrack = data.audioTracks?.find((x: AudioTrack) => { + return x.selected; }); - } - - getCurrentTimePercentage() { - if (this.state.currentTime > 0 && this.state.duration !== 0) { - return this.state.currentTime / this.state.duration; + if (selectedTrack?.index) { + this.setState({ + audioTracks: data.audioTracks, + selectedAudioTrack: { + type: SelectedVideoTrackType.INDEX, + value: selectedTrack?.index, + }, + }); } else { - return 0; + this.setState({ + audioTracks: data.audioTracks, + }); } - } + }; + + onVideoTracks = (data: OnVideoTracksData) => { + console.log('onVideoTracks', data.videoTracks); + this.setState({ + videoTracks: data.videoTracks, + }); + }; - setFilter(step: number) { - let index = filterTypes.indexOf(this.state.filter) + step; + onTextTracks = (data: OnTextTracksData) => { + const selectedTrack = data.textTracks?.find((x: TextTrack) => { + return x?.selected; + }); - if (index === filterTypes.length) { - index = 0; - } else if (index === -1) { - index = filterTypes.length - 1; + if (selectedTrack?.language) { + this.setState({ + textTracks: data.textTracks, + selectedTextTrack: + this.textTracksSelectionBy === 'index' + ? { + type: 'index', + value: selectedTrack?.index, + } + : { + type: 'language', + value: selectedTrack?.language, + }, + }); + } else { + this.setState({ + textTracks: data.textTracks, + }); } + }; + onTextTrackDataChanged = (data: OnTextTrackDataChangedData) => { + console.log(`Subtitles: ${JSON.stringify(data, null, 2)}`); + }; + + onAspectRatio = (data: OnVideoAspectRatioData) => { + console.log('onAspectRadio called ' + JSON.stringify(data)); this.setState({ - filter: filterTypes[index], + videoWidth: data.width, + videoHeight: data.height, }); + }; + + onVideoBuffer = (param: OnBufferData) => { + console.log('onVideoBuffer'); + this.setState({isLoading: param.isBuffering}); + }; + + onReadyForDisplay = () => { + console.log('onReadyForDisplay'); + this.setState({isLoading: false}); + }; + + onAudioBecomingNoisy = () => { + this.setState({paused: true}); + }; + + onAudioFocusChanged = (event: OnAudioFocusChangedData) => { + this.setState({paused: !event.hasAudioFocus}); + }; + + toast = (visible: boolean, message: string) => { + if (visible) { + if (Platform.OS === 'android') { + ToastAndroid.showWithGravityAndOffset( + message, + ToastAndroid.LONG, + ToastAndroid.BOTTOM, + 25, + 50, + ); + } else { + Alert.alert(message, message); + } + } + }; + + onError = (err: OnVideoErrorData) => { + console.log(JSON.stringify(err)); + this.toast(true, 'error: ' + JSON.stringify(err)); + }; + + onEnd = () => { + if (!this.state.loop) { + this.channelUp(); + } + }; + + onPlaybackRateChange = (data: OnPlaybackRateChangeData) => { + console.log('onPlaybackRateChange', data); + }; + + onPlaybackStateChanged = (data: OnPlaybackStateChangedData) => { + console.log('onPlaybackStateChanged', data); + }; + + toggleFullscreen() { + this.setState({fullscreen: !this.state.fullscreen}); + } + toggleControls() { + this.setState({showRNVControls: !this.state.showRNVControls}); } - renderSkinControl(skin: 'custom' | 'native' | 'embed') { - const isSelected = this.state.skin == skin; - const selectControls = skin == 'native' || skin == 'embed'; - return ( - { - this.setState({ - controls: selectControls, - skin: skin, - }); - }}> - - {skin} - - - ); + toggleDecoration() { + this.setState({decoration: !this.state.decoration}); + this.video?.setFullScreen(!this.state.decoration); } - renderRateControl(rate: number) { - const isSelected = this.state.rate == rate; + toggleShowNotificationControls() { + this.setState({ + showNotificationControls: !this.state.showNotificationControls, + }); + } - return ( - { - this.setState({rate: rate}); - }}> - - {rate}x - - - ); + goToChannel(channel: number) { + this.setState({ + srcListId: channel, + duration: 0.0, + currentTime: 0.0, + videoWidth: 0, + videoHeight: 0, + isLoading: false, + audioTracks: [], + textTracks: [], + selectedAudioTrack: undefined, + selectedTextTrack: undefined, + selectedVideoTrack: { + type: SelectedVideoTrackType.AUTO, + }, + }); } - renderResizeModeControl(resizeMode: ResizeMode) { - const isSelected = this.state.resizeMode == resizeMode; + channelUp() { + console.log('channel up'); + this.goToChannel((this.state.srcListId + 1) % this.srcList.length); + } - return ( - { - this.setState({resizeMode: resizeMode}); - }}> - - {resizeMode} - - + channelDown() { + console.log('channel down'); + this.goToChannel( + (this.state.srcListId + this.srcList.length - 1) % this.srcList.length, ); } - renderVolumeControl(volume: number) { - const isSelected = this.state.volume == volume; + videoSeek(position: number) { + this.setState({isSeeking: true}); + this.video?.seek(position); + } + renderSeekBar() { return ( - { - this.setState({volume: volume}); - }}> - - {volume * 100}% - - + this.videoSeek(prop)} + isUISeeking={this.state.isSeeking} + /> ); } - renderIgnoreSilentSwitchControl(ignoreSilentSwitch: IgnoreSilentSwitchType) { - const isSelected = this.state.ignoreSilentSwitch == ignoreSilentSwitch; + IndicatorLoadingView() { + if (this.state.isLoading) { + return ( + + ); + } else { + return ; + } + } + renderTopControl() { return ( - { - this.setState({ignoreSilentSwitch: ignoreSilentSwitch}); - }}> - - {ignoreSilentSwitch} + + + {(this.srcList[this.state.srcListId] as AdditionnalSourceInfo) + ?.description || 'local file'} - + + { + this.toggleControls(); + }}> + + {this.state.showRNVControls ? 'Hide controls' : 'Show controls'} + + + + ); } - renderMixWithOthersControl(mixWithOthers: MixWithOthersType) { - const isSelected = this.state.mixWithOthers == mixWithOthers; + onRateSelected = (value: MultiValueControlPropType) => { + this.setState({rate: value}); + }; + onVolumeSelected = (value: MultiValueControlPropType) => { + this.setState({volume: value}); + }; + onResizeModeSelected = (value: MultiValueControlPropType) => { + this.setState({resizeMode: value}); + }; - return ( - { - this.setState({mixWithOthers: mixWithOthers}); - }}> - - {mixWithOthers} - - - ); - } + onSelectedAudioTrackChange = (itemValue: string) => { + console.log('on audio value change ' + itemValue); + if (itemValue === 'none') { + this.setState({ + selectedAudioTrack: SelectedVideoTrackType.DISABLED, + }); + } else { + this.setState({ + selectedAudioTrack: { + type: SelectedVideoTrackType.INDEX, + value: itemValue, + }, + }); + } + }; + + onSelectedTextTrackChange = (itemValue: string) => { + console.log('on value change ' + itemValue); + this.setState({ + selectedTextTrack: { + type: this.textTracksSelectionBy === 'index' ? 'index' : 'language', + value: itemValue, + }, + }); + }; - renderCustomSkin() { - const flexCompleted = this.getCurrentTimePercentage() * 100; - const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; + onSelectedVideoTrackChange = (itemValue: string) => { + console.log('on value change ' + itemValue); + if (itemValue === undefined || itemValue === 'auto') { + this.setState({ + selectedVideoTrack: { + type: SelectedVideoTrackType.AUTO, + }, + }); + } else { + this.setState({ + selectedVideoTrack: { + type: SelectedVideoTrackType.INDEX, + value: itemValue, + }, + }); + } + }; + renderOverlay() { return ( - - { - this.setState({paused: !this.state.paused}); - }}> - - - - - - {this.renderSkinControl('custom')} - {this.renderSkinControl('native')} - {this.renderSkinControl('embed')} + <> + {this.IndicatorLoadingView()} + + + {this.renderTopControl()} + + + {!this.state.showRNVControls ? ( + <> + + { + this.channelDown(); + }} + text="ChDown" + /> + + + { + this.channelUp(); + }} + text="ChUp" + /> - {this.state.filterEnabled ? ( - - + + {Platform.OS === 'android' ? ( + + { + this.popupInfo(); + }} + text="decoderInfo" + /> + { + this.setState({useCache: !this.state.useCache}); + }} + selectedText="enable cache" + unselectedText="disable cache" + /> + + ) : null} + { - this.setFilter(-1); - }}> - Previous Filter - - + { + this.setState({loop: !this.state.loop}); + }} + selectedText="loop enable" + unselectedText="loop disable" + /> + { - this.setFilter(1); - }}> - Next Filter - + this.toggleFullscreen(); + }} + text="fullscreen" + /> + { + this.toggleDecoration(); + }} + text="decoration" + /> + { + this.setState({ + poster: this.state.poster ? undefined : this.samplePoster, + }); + }} + selectedText="poster" + unselectedText="no poster" + /> + { + this.toggleShowNotificationControls(); + }} + selectedText="hide notification controls" + unselectedText="show notification controls" + /> - ) : null} - - - - {this.renderRateControl(0.5)} - {this.renderRateControl(1.0)} - {this.renderRateControl(2.0)} - - - - {this.renderVolumeControl(0.5)} - {this.renderVolumeControl(1)} - {this.renderVolumeControl(1.5)} - - - - {this.renderResizeModeControl(ResizeMode.COVER)} - {this.renderResizeModeControl(ResizeMode.CONTAIN)} - {this.renderResizeModeControl(ResizeMode.STRETCH)} - - - - {Platform.OS === 'ios' ? ( - <> - - {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.IGNORE)} - {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.OBEY)} - - - {this.renderMixWithOthersControl(MixWithOthersType.MIX)} - {this.renderMixWithOthersControl(MixWithOthersType.DUCK)} - - - ) : null} - - - - - + {/* shall be replaced by slider */} + + {/* shall be replaced by slider */} + - + { + this.setState({muted: !this.state.muted}); + }} + text="muted" + /> + {Platform.OS === 'ios' ? ( + { + this.video + ?.save({}) + ?.then(response => { + console.log('Downloaded URI', response); + }) + .catch(error => { + console.log('error during save ', error); + }); + }} + text="save" + /> + ) : null} + + {this.renderSeekBar()} + + + + - - - + + ) : null} + ); } - renderNativeSkin() { - const videoStyle = - this.state.skin == 'embed' - ? styles.nativeVideoControls - : styles.fullScreen; - return ( - - - - - - - {this.renderSkinControl('custom')} - {this.renderSkinControl('native')} - {this.renderSkinControl('embed')} - - {this.state.filterEnabled ? ( - - { - this.setFilter(-1); - }}> - Previous Filter - - { - this.setFilter(1); - }}> - Next Filter - - - ) : null} - - - - {this.renderRateControl(0.5)} - {this.renderRateControl(1.0)} - {this.renderRateControl(2.0)} - + renderVideoView() { + const viewStyle = this.state.fullscreen + ? styles.fullScreen + : styles.halfScreen; - - {this.renderVolumeControl(0.5)} - {this.renderVolumeControl(1)} - {this.renderVolumeControl(1.5)} - + const currentSrc = this.srcList[this.state.srcListId]; + const additionnal = currentSrc as AdditionnalSourceInfo; - - {this.renderResizeModeControl(ResizeMode.COVER)} - {this.renderResizeModeControl(ResizeMode.CONTAIN)} - {this.renderResizeModeControl(ResizeMode.STRETCH)} - - - - {Platform.OS === 'ios' ? ( - <> - - {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.IGNORE)} - {this.renderIgnoreSilentSwitchControl(IgnoreSilentSwitchType.OBEY)} - - - {this.renderMixWithOthersControl(MixWithOthersType.MIX)} - {this.renderMixWithOthersControl(MixWithOthersType.DUCK)} - - - ) : null} - - - + return ( + + ); } render() { - return this.state.controls - ? this.renderNativeSkin() - : this.renderCustomSkin(); + return ( + + {(this.srcList[this.state.srcListId] as AdditionnalSourceInfo)?.noView + ? null + : this.renderVideoView()} + {this.renderOverlay()} + + ); } } - -const styles = StyleSheet.create({ - container: { - flex: 1, - justifyContent: 'center', - alignItems: 'center', - backgroundColor: 'black', - }, - fullScreen: { - position: 'absolute', - top: 0, - left: 0, - bottom: 0, - right: 0, - }, - controls: { - backgroundColor: 'transparent', - borderRadius: 5, - position: 'absolute', - bottom: 44, - left: 4, - right: 4, - }, - progress: { - flex: 1, - flexDirection: 'row', - borderRadius: 3, - overflow: 'hidden', - }, - innerProgressCompleted: { - height: 20, - backgroundColor: '#cccccc', - }, - innerProgressRemaining: { - height: 20, - backgroundColor: '#2C2C2C', - }, - generalControls: { - flex: 1, - flexDirection: 'row', - overflow: 'hidden', - paddingBottom: 10, - }, - skinControl: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - }, - rateControl: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - }, - volumeControl: { - flex: 1, - flexDirection: 'row', - justifyContent: 'center', - }, - resizeModeControl: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - }, - ignoreSilentSwitchControl: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - }, - mixWithOthersControl: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - }, - controlOption: { - alignSelf: 'center', - fontSize: 11, - color: 'white', - paddingLeft: 2, - paddingRight: 2, - lineHeight: 12, - }, - nativeVideoControls: { - top: 184, - height: 300, - }, - trackingControls: { - flex: 1, - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - }, -}); export default VideoPlayer; diff --git a/examples/FabricExample/src/components/AudioTracksSelector.tsx b/examples/FabricExample/src/components/AudioTracksSelector.tsx new file mode 100644 index 0000000000..41c5e748c6 --- /dev/null +++ b/examples/FabricExample/src/components/AudioTracksSelector.tsx @@ -0,0 +1,53 @@ +import {Picker} from '@react-native-picker/picker'; +import {Text} from 'react-native'; +import {AudioTrack, SelectedTrack} from 'react-native-video'; +import styles from '../styles'; +import React from 'react'; + +export interface AudioTrackSelectorType { + audioTracks: Array; + selectedAudioTrack: SelectedTrack | undefined; + onValueChange: (arg0: string) => void; +} + +const AudioTrackSelector = ({ + audioTracks, + selectedAudioTrack, + onValueChange, +}: AudioTrackSelectorType) => { + return ( + <> + AudioTrack + { + if (itemValue !== 'empty') { + console.log('on audio value change ' + itemValue); + onValueChange(`${itemValue}`); + } + }}> + {audioTracks?.length <= 0 ? ( + + ) : ( + + )} + {audioTracks.map(track => { + if (!track) { + return; + } + return ( + + ); + })} + + + ); +}; + +export default AudioTrackSelector; diff --git a/examples/FabricExample/src/components/Seeker.tsx b/examples/FabricExample/src/components/Seeker.tsx new file mode 100644 index 0000000000..a74122b0c8 --- /dev/null +++ b/examples/FabricExample/src/components/Seeker.tsx @@ -0,0 +1,154 @@ +import React, {useCallback, useEffect, useState} from 'react'; +import {PanResponder, View} from 'react-native'; +import styles from '../styles'; + +interface SeekerProps { + currentTime: number; + duration: number; + isLoading: boolean; + isUISeeking: boolean; + videoSeek: (arg0: number) => void; +} + +const Seeker = ({ + currentTime, + duration, + isLoading, + isUISeeking, + videoSeek, +}: SeekerProps) => { + const [seeking, setSeeking] = useState(false); + const [seekerPosition, setSeekerPosition] = useState(0); + const [seekerWidth, setSeekerWidth] = useState(0); + + /** + * Set the position of the seekbar's components + * (both fill and handle) according to the + * position supplied. + * + * @param {float} position position in px of seeker handle} + */ + const updateSeekerPosition = useCallback( + (position = 0) => { + if (position <= 0) { + position = 0; + } else if (position >= seekerWidth) { + position = seekerWidth; + } + setSeekerPosition(position); + }, + [seekerWidth], + ); + + /** + * Return the time that the video should be at + * based on where the seeker handle is. + * + * @return {float} time in ms based on seekerPosition. + */ + const calculateTimeFromSeekerPosition = () => { + const percent = seekerPosition / seekerWidth; + return duration * percent; + }; + + /** + * Get our seekbar responder going + */ + + const seekPanResponder = PanResponder.create({ + // Ask to be the responder. + onStartShouldSetPanResponder: (_evt, _gestureState) => true, + onMoveShouldSetPanResponder: (_evt, _gestureState) => true, + + /** + * When we start the pan tell the machine that we're + * seeking. This stops it from updating the seekbar + * position in the onProgress listener. + */ + onPanResponderGrant: (evt, _gestureState) => { + const position = evt.nativeEvent.locationX; + updateSeekerPosition(position); + setSeeking(true); + }, + + /** + * When panning, update the seekbar position, duh. + */ + onPanResponderMove: (evt, _gestureState) => { + const position = evt.nativeEvent.locationX; + updateSeekerPosition(position); + }, + + /** + * On release we update the time and seek to it in the video. + * If you seek to the end of the video we fire the + * onEnd callback + */ + onPanResponderRelease: (_evt, _gestureState) => { + const time = calculateTimeFromSeekerPosition(); + if (time >= duration && !isLoading) { + // FIXME ... + // state.paused = true; + // this.onEnd(); + } else { + videoSeek(time); + setSeeking(false); + } + }, + }); + + useEffect(() => { + if (!isLoading && !seeking && !isUISeeking) { + const percent = currentTime / duration; + const position = seekerWidth * percent; + updateSeekerPosition(position); + } + }, [ + currentTime, + duration, + isLoading, + seekerWidth, + seeking, + isUISeeking, + updateSeekerPosition, + ]); + + if (!seekPanResponder) { + return null; + } + const seekerStyle = [ + styles.seekbarFill, + { + width: seekerPosition > 0 ? seekerPosition : 0, + backgroundColor: '#FFF', + }, + ]; + + const seekerPositionStyle = [ + styles.seekbarHandle, + { + left: seekerPosition > 0 ? seekerPosition : 0, + }, + ]; + + const seekerPointerStyle = [styles.seekbarCircle, {backgroundColor: '#FFF'}]; + + return ( + + setSeekerWidth(event.nativeEvent.layout.width)} + pointerEvents={'none'}> + + + + + + + ); +}; + +export default Seeker; diff --git a/examples/FabricExample/src/components/TextTracksSelector.tsx b/examples/FabricExample/src/components/TextTracksSelector.tsx new file mode 100644 index 0000000000..84faac3dad --- /dev/null +++ b/examples/FabricExample/src/components/TextTracksSelector.tsx @@ -0,0 +1,64 @@ +import {Picker} from '@react-native-picker/picker'; +import {Text} from 'react-native'; +import {TextTrack, SelectedTrack} from 'react-native-video'; +import styles from '../styles'; +import React from 'react'; + +export interface TextTrackSelectorType { + textTracks: Array; + selectedTextTrack: SelectedTrack | undefined; + onValueChange: (arg0: string) => void; + textTracksSelectionBy: string; +} + +const TextTrackSelector = ({ + textTracks, + selectedTextTrack, + onValueChange, + textTracksSelectionBy, +}: TextTrackSelectorType) => { + return ( + <> + TextTrack + { + if (itemValue !== 'empty') { + onValueChange(itemValue); + } + }}> + {textTracks?.length <= 0 ? ( + + ) : ( + + )} + {textTracks.map(track => { + if (!track) { + return; + } + if (textTracksSelectionBy === 'index') { + return ( + + ); + } else { + return ( + + ); + } + })} + + + ); +}; + +export default TextTrackSelector; diff --git a/examples/FabricExample/src/components/VideoTracksSelector.tsx b/examples/FabricExample/src/components/VideoTracksSelector.tsx new file mode 100644 index 0000000000..568953c86d --- /dev/null +++ b/examples/FabricExample/src/components/VideoTracksSelector.tsx @@ -0,0 +1,64 @@ +import {Picker} from '@react-native-picker/picker'; +import {Text} from 'react-native'; +import { + SelectedVideoTrack, + SelectedVideoTrackType, + VideoTrack, +} from 'react-native-video'; +import styles from '../styles'; +import React from 'react'; + +export interface VideoTrackSelectorType { + videoTracks: Array; + selectedVideoTrack: SelectedVideoTrack | undefined; + onValueChange: (arg0: string) => void; +} + +const VideoTrackSelector = ({ + videoTracks, + selectedVideoTrack, + onValueChange, +}: VideoTrackSelectorType) => { + return ( + <> + VideoTrack + { + if (itemValue !== 'empty') { + onValueChange(itemValue); + } + }}> + + {videoTracks?.length <= 0 || videoTracks?.length <= 0 ? ( + + ) : ( + + )} + {videoTracks?.map(track => { + if (!track) { + return; + } + return ( + + ); + })} + + + ); +}; + +export default VideoTrackSelector; diff --git a/examples/basic/src/portrait.mp4 b/examples/FabricExample/src/portrait.mp4 similarity index 100% rename from examples/basic/src/portrait.mp4 rename to examples/FabricExample/src/portrait.mp4 diff --git a/examples/FabricExample/src/styles.tsx b/examples/FabricExample/src/styles.tsx new file mode 100644 index 0000000000..0dd7239090 --- /dev/null +++ b/examples/FabricExample/src/styles.tsx @@ -0,0 +1,167 @@ +import {StyleSheet} from 'react-native'; + +const styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: 'black', + }, + halfScreen: { + position: 'absolute', + top: 50, + left: 50, + bottom: 100, + right: 100, + }, + fullScreen: { + position: 'absolute', + top: 0, + left: 0, + bottom: 0, + right: 0, + }, + bottomControls: { + backgroundColor: 'transparent', + borderRadius: 5, + position: 'absolute', + bottom: 20, + left: 20, + right: 20, + }, + leftControls: { + backgroundColor: 'transparent', + borderRadius: 5, + position: 'absolute', + top: 20, + bottom: 20, + left: 20, + }, + rightControls: { + backgroundColor: 'transparent', + borderRadius: 5, + position: 'absolute', + top: 20, + bottom: 20, + right: 20, + }, + topControls: { + backgroundColor: 'transparent', + borderRadius: 4, + position: 'absolute', + top: 20, + left: 20, + right: 20, + flex: 1, + flexDirection: 'row', + overflow: 'hidden', + paddingBottom: 10, + }, + generalControls: { + flex: 1, + flexDirection: 'row', + borderRadius: 4, + overflow: 'hidden', + paddingBottom: 10, + }, + rateControl: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + }, + volumeControl: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + }, + resizeModeControl: { + flex: 1, + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + }, + leftRightControlOption: { + alignSelf: 'center', + fontSize: 11, + color: 'white', + padding: 10, + lineHeight: 12, + }, + controlOption: { + alignSelf: 'center', + fontSize: 11, + color: 'white', + paddingLeft: 2, + paddingRight: 2, + lineHeight: 12, + }, + pickerContainer: { + width: 100, + alignSelf: 'center', + color: 'white', + borderWidth: 1, + borderColor: 'red', + }, + IndicatorStyle: { + flex: 1, + justifyContent: 'center', + }, + seekbarContainer: { + flex: 1, + flexDirection: 'row', + borderRadius: 4, + height: 30, + }, + seekbarTrack: { + backgroundColor: '#333', + height: 1, + position: 'relative', + top: 14, + width: '100%', + }, + seekbarFill: { + backgroundColor: '#FFF', + height: 1, + width: '100%', + }, + seekbarHandle: { + position: 'absolute', + marginLeft: -7, + height: 28, + width: 28, + }, + seekbarCircle: { + borderRadius: 12, + position: 'relative', + top: 8, + left: 8, + height: 12, + width: 12, + }, + picker: { + flex: 1, + color: 'white', + flexDirection: 'row', + justifyContent: 'center', + width: 100, + height: 40, + }, + pickerItem: { + color: 'white', + width: 100, + height: 40, + }, + emptyPickerItem: { + color: 'white', + marginTop: 20, + marginLeft: 20, + flex: 1, + width: 100, + height: 40, + }, + topControlsContainer: { + paddingTop: 30, + }, +}); + +export default styles; diff --git a/examples/FabricExample/tsconfig.json b/examples/FabricExample/tsconfig.json index 4ab8fc695b..a47cb9d4b0 100644 --- a/examples/FabricExample/tsconfig.json +++ b/examples/FabricExample/tsconfig.json @@ -1,6 +1,6 @@ // prettier-ignore { - "extends": "@tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */ + "extends": "@react-native/typescript-config/tsconfig.json", "compilerOptions": { /* Visit https://aka.ms/tsconfig.json to read more about this file */ "paths": { diff --git a/examples/basic/Gemfile.lock b/examples/basic/Gemfile.lock index 3f37065fb5..21441d307a 100644 --- a/examples/basic/Gemfile.lock +++ b/examples/basic/Gemfile.lock @@ -3,11 +3,12 @@ GEM specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.8) + activesupport (6.1.7.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) + zeitwerk (~> 2.3) addressable (2.8.5) public_suffix (>= 2.0.2, < 6.0) algoliasearch (1.27.5) @@ -84,10 +85,11 @@ GEM colored2 (~> 3.1) nanaimo (~> 0.3.0) rexml (~> 3.2.4) + zeitwerk (2.6.16) PLATFORMS arm64-darwin-21 - ruby + arm64-darwin-23 DEPENDENCIES activesupport (>= 6.1.7.5, < 7.1.0) @@ -97,4 +99,4 @@ RUBY VERSION ruby 2.7.5p203 BUNDLED WITH - 2.4.19 + 2.4.5 diff --git a/examples/basic/android/app/build.gradle b/examples/basic/android/app/build.gradle index bd7dbe4e9a..fa4d074be3 100644 --- a/examples/basic/android/app/build.gradle +++ b/examples/basic/android/app/build.gradle @@ -81,12 +81,20 @@ android { compileSdkVersion rootProject.ext.compileSdkVersion namespace "com.videoplayer" + + compileOptions { + // These options are necessary to be able to build fro source + coreLibraryDesugaringEnabled true + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } defaultConfig { applicationId "com.videoplayer" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion versionCode 1 versionName "1.0" + multiDexEnabled true } signingConfigs { debug { @@ -137,6 +145,7 @@ dependencies { } implementation project(':react-native-video') + implementation project(':react-native-video-plugin-sample') constraints { implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") { @@ -146,6 +155,8 @@ dependencies { because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib") } } + // coreLibraryDesugaring is mandatory to be able to build exoplayer from source + coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' } apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) diff --git a/examples/basic/android/app/src/main/java/com/videoplayer/MainApplication.kt b/examples/basic/android/app/src/main/java/com/videoplayer/MainApplication.kt index 4166c3d137..c1eeea477e 100644 --- a/examples/basic/android/app/src/main/java/com/videoplayer/MainApplication.kt +++ b/examples/basic/android/app/src/main/java/com/videoplayer/MainApplication.kt @@ -14,6 +14,7 @@ import com.facebook.react.defaults.DefaultReactHost.getDefaultReactHost import com.facebook.react.defaults.DefaultReactNativeHost import com.facebook.soloader.SoLoader import com.brentvatne.react.ReactVideoPackage +import com.videopluginsample.VideoPluginSamplePackage class MainApplication : Application(), ReactApplication { @@ -24,6 +25,7 @@ class MainApplication : Application(), ReactApplication { // Packages that cannot be autolinked yet can be added manually here, for example: // add(MyReactNativePackage()) add(ReactVideoPackage()) + add(VideoPluginSamplePackage()) } override fun getJSMainModuleName(): String = "src/index" diff --git a/examples/basic/android/build.gradle b/examples/basic/android/build.gradle index 3838f93303..924476662a 100644 --- a/examples/basic/android/build.gradle +++ b/examples/basic/android/build.gradle @@ -16,6 +16,9 @@ buildscript { // useExoplayerSmoothStreaming = false // useExoplayerDash = false // useExoplayerHls = false + + // uncomment this line to be able to build from media3 source code + // buildFromMedia3Source = true } repositories { google() diff --git a/examples/basic/android/settings.gradle b/examples/basic/android/settings.gradle index 60b7d9cbfe..e91a212225 100644 --- a/examples/basic/android/settings.gradle +++ b/examples/basic/android/settings.gradle @@ -2,9 +2,16 @@ rootProject.name = 'videoplayer' apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) include ':app' +include ':react-native-video-plugin-sample' +project (':react-native-video-plugin-sample').projectDir = new File(rootProject.projectDir, '../../react-native-video-plugin-sample/android') + include ':react-native-video' project (':react-native-video').projectDir = new File(rootProject.projectDir, '../../../android') +// uncomment these lines to be able to build from media3 source code +// gradle.ext.androidxMediaModulePrefix = 'media-' +// apply from: file("../../../../media3/core_settings.gradle") + includeBuild('../node_modules/@react-native/gradle-plugin') apply from: new File(["node", "--print", "require.resolve('expo/package.json')"].execute(null, rootDir).text.trim(), "../scripts/autolinking.gradle") diff --git a/examples/basic/ios/Podfile b/examples/basic/ios/Podfile index 08f3a493fa..f31e6f8a06 100644 --- a/examples/basic/ios/Podfile +++ b/examples/basic/ios/Podfile @@ -46,6 +46,7 @@ target 'videoplayer' do ) pod 'react-native-video', path: '../../..' + pod 'react-native-video-plugin-sample', path: '../../react-native-video-plugin-sample' target 'videoplayerTests' do inherit! :complete diff --git a/examples/basic/ios/Podfile.lock b/examples/basic/ios/Podfile.lock index 719a254965..0a46de8f6b 100644 --- a/examples/basic/ios/Podfile.lock +++ b/examples/basic/ios/Podfile.lock @@ -3,9 +3,9 @@ PODS: - DoubleConversion (1.1.6) - EXConstants (16.0.2): - ExpoModulesCore - - Expo (51.0.14): + - Expo (51.0.17): - ExpoModulesCore - - ExpoAsset (10.0.9): + - ExpoAsset (10.0.10): - ExpoModulesCore - ExpoFileSystem (17.0.1): - ExpoModulesCore @@ -20,7 +20,7 @@ PODS: - SDWebImageWebPCoder (~> 0.14.6) - ExpoKeepAwake (13.0.2): - ExpoModulesCore - - ExpoModulesCore (1.12.15): + - ExpoModulesCore (1.12.18): - DoubleConversion - glog - hermes-engine @@ -43,12 +43,12 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - FBLazyVector (0.74.2) + - FBLazyVector (0.74.3) - fmt (9.1.0) - glog (0.3.5) - - hermes-engine (0.74.2): - - hermes-engine/Pre-built (= 0.74.2) - - hermes-engine/Pre-built (0.74.2) + - hermes-engine (0.74.3): + - hermes-engine/Pre-built (= 0.74.3) + - hermes-engine/Pre-built (0.74.3) - libavif/core (0.11.1) - libavif/libdav1d (0.11.1): - libavif/core @@ -82,27 +82,27 @@ PODS: - DoubleConversion - fmt (= 9.1.0) - glog - - RCTDeprecation (0.74.2) - - RCTRequired (0.74.2) - - RCTTypeSafety (0.74.2): - - FBLazyVector (= 0.74.2) - - RCTRequired (= 0.74.2) - - React-Core (= 0.74.2) - - React (0.74.2): - - React-Core (= 0.74.2) - - React-Core/DevSupport (= 0.74.2) - - React-Core/RCTWebSocket (= 0.74.2) - - React-RCTActionSheet (= 0.74.2) - - React-RCTAnimation (= 0.74.2) - - React-RCTBlob (= 0.74.2) - - React-RCTImage (= 0.74.2) - - React-RCTLinking (= 0.74.2) - - React-RCTNetwork (= 0.74.2) - - React-RCTSettings (= 0.74.2) - - React-RCTText (= 0.74.2) - - React-RCTVibration (= 0.74.2) - - React-callinvoker (0.74.2) - - React-Codegen (0.74.2): + - RCTDeprecation (0.74.3) + - RCTRequired (0.74.3) + - RCTTypeSafety (0.74.3): + - FBLazyVector (= 0.74.3) + - RCTRequired (= 0.74.3) + - React-Core (= 0.74.3) + - React (0.74.3): + - React-Core (= 0.74.3) + - React-Core/DevSupport (= 0.74.3) + - React-Core/RCTWebSocket (= 0.74.3) + - React-RCTActionSheet (= 0.74.3) + - React-RCTAnimation (= 0.74.3) + - React-RCTBlob (= 0.74.3) + - React-RCTImage (= 0.74.3) + - React-RCTLinking (= 0.74.3) + - React-RCTNetwork (= 0.74.3) + - React-RCTSettings (= 0.74.3) + - React-RCTText (= 0.74.3) + - React-RCTVibration (= 0.74.3) + - React-callinvoker (0.74.3) + - React-Codegen (0.74.3): - DoubleConversion - glog - hermes-engine @@ -122,12 +122,12 @@ PODS: - React-utils - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-Core (0.74.2): + - React-Core (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - RCTDeprecation - - React-Core/Default (= 0.74.2) + - React-Core/Default (= 0.74.3) - React-cxxreact - React-featureflags - React-hermes @@ -139,7 +139,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/CoreModulesHeaders (0.74.2): + - React-Core/CoreModulesHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -156,7 +156,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/Default (0.74.2): + - React-Core/Default (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -172,13 +172,13 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/DevSupport (0.74.2): + - React-Core/DevSupport (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - RCTDeprecation - - React-Core/Default (= 0.74.2) - - React-Core/RCTWebSocket (= 0.74.2) + - React-Core/Default (= 0.74.3) + - React-Core/RCTWebSocket (= 0.74.3) - React-cxxreact - React-featureflags - React-hermes @@ -190,7 +190,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTActionSheetHeaders (0.74.2): + - React-Core/RCTActionSheetHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -207,7 +207,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTAnimationHeaders (0.74.2): + - React-Core/RCTAnimationHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -224,7 +224,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTBlobHeaders (0.74.2): + - React-Core/RCTBlobHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -241,7 +241,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTImageHeaders (0.74.2): + - React-Core/RCTImageHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -258,7 +258,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTLinkingHeaders (0.74.2): + - React-Core/RCTLinkingHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -275,7 +275,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTNetworkHeaders (0.74.2): + - React-Core/RCTNetworkHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -292,7 +292,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTSettingsHeaders (0.74.2): + - React-Core/RCTSettingsHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -309,7 +309,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTTextHeaders (0.74.2): + - React-Core/RCTTextHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -326,7 +326,7 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTVibrationHeaders (0.74.2): + - React-Core/RCTVibrationHeaders (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -343,12 +343,12 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-Core/RCTWebSocket (0.74.2): + - React-Core/RCTWebSocket (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - RCTDeprecation - - React-Core/Default (= 0.74.2) + - React-Core/Default (= 0.74.3) - React-cxxreact - React-featureflags - React-hermes @@ -360,36 +360,36 @@ PODS: - React-utils - SocketRocket (= 0.7.0) - Yoga - - React-CoreModules (0.74.2): + - React-CoreModules (0.74.3): - DoubleConversion - fmt (= 9.1.0) - RCT-Folly (= 2024.01.01.00) - - RCTTypeSafety (= 0.74.2) + - RCTTypeSafety (= 0.74.3) - React-Codegen - - React-Core/CoreModulesHeaders (= 0.74.2) - - React-jsi (= 0.74.2) + - React-Core/CoreModulesHeaders (= 0.74.3) + - React-jsi (= 0.74.3) - React-jsinspector - React-NativeModulesApple - React-RCTBlob - - React-RCTImage (= 0.74.2) + - React-RCTImage (= 0.74.3) - ReactCommon - SocketRocket (= 0.7.0) - - React-cxxreact (0.74.2): + - React-cxxreact (0.74.3): - boost (= 1.83.0) - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-callinvoker (= 0.74.2) - - React-debug (= 0.74.2) - - React-jsi (= 0.74.2) + - React-callinvoker (= 0.74.3) + - React-debug (= 0.74.3) + - React-jsi (= 0.74.3) - React-jsinspector - - React-logger (= 0.74.2) - - React-perflogger (= 0.74.2) - - React-runtimeexecutor (= 0.74.2) - - React-debug (0.74.2) - - React-Fabric (0.74.2): + - React-logger (= 0.74.3) + - React-perflogger (= 0.74.3) + - React-runtimeexecutor (= 0.74.3) + - React-debug (0.74.3) + - React-Fabric (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -400,20 +400,20 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/animations (= 0.74.2) - - React-Fabric/attributedstring (= 0.74.2) - - React-Fabric/componentregistry (= 0.74.2) - - React-Fabric/componentregistrynative (= 0.74.2) - - React-Fabric/components (= 0.74.2) - - React-Fabric/core (= 0.74.2) - - React-Fabric/imagemanager (= 0.74.2) - - React-Fabric/leakchecker (= 0.74.2) - - React-Fabric/mounting (= 0.74.2) - - React-Fabric/scheduler (= 0.74.2) - - React-Fabric/telemetry (= 0.74.2) - - React-Fabric/templateprocessor (= 0.74.2) - - React-Fabric/textlayoutmanager (= 0.74.2) - - React-Fabric/uimanager (= 0.74.2) + - React-Fabric/animations (= 0.74.3) + - React-Fabric/attributedstring (= 0.74.3) + - React-Fabric/componentregistry (= 0.74.3) + - React-Fabric/componentregistrynative (= 0.74.3) + - React-Fabric/components (= 0.74.3) + - React-Fabric/core (= 0.74.3) + - React-Fabric/imagemanager (= 0.74.3) + - React-Fabric/leakchecker (= 0.74.3) + - React-Fabric/mounting (= 0.74.3) + - React-Fabric/scheduler (= 0.74.3) + - React-Fabric/telemetry (= 0.74.3) + - React-Fabric/templateprocessor (= 0.74.3) + - React-Fabric/textlayoutmanager (= 0.74.3) + - React-Fabric/uimanager (= 0.74.3) - React-graphics - React-jsi - React-jsiexecutor @@ -422,7 +422,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/animations (0.74.2): + - React-Fabric/animations (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -441,7 +441,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/attributedstring (0.74.2): + - React-Fabric/attributedstring (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -460,7 +460,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/componentregistry (0.74.2): + - React-Fabric/componentregistry (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -479,7 +479,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/componentregistrynative (0.74.2): + - React-Fabric/componentregistrynative (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -498,7 +498,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components (0.74.2): + - React-Fabric/components (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -509,17 +509,17 @@ PODS: - React-Core - React-cxxreact - React-debug - - React-Fabric/components/inputaccessory (= 0.74.2) - - React-Fabric/components/legacyviewmanagerinterop (= 0.74.2) - - React-Fabric/components/modal (= 0.74.2) - - React-Fabric/components/rncore (= 0.74.2) - - React-Fabric/components/root (= 0.74.2) - - React-Fabric/components/safeareaview (= 0.74.2) - - React-Fabric/components/scrollview (= 0.74.2) - - React-Fabric/components/text (= 0.74.2) - - React-Fabric/components/textinput (= 0.74.2) - - React-Fabric/components/unimplementedview (= 0.74.2) - - React-Fabric/components/view (= 0.74.2) + - React-Fabric/components/inputaccessory (= 0.74.3) + - React-Fabric/components/legacyviewmanagerinterop (= 0.74.3) + - React-Fabric/components/modal (= 0.74.3) + - React-Fabric/components/rncore (= 0.74.3) + - React-Fabric/components/root (= 0.74.3) + - React-Fabric/components/safeareaview (= 0.74.3) + - React-Fabric/components/scrollview (= 0.74.3) + - React-Fabric/components/text (= 0.74.3) + - React-Fabric/components/textinput (= 0.74.3) + - React-Fabric/components/unimplementedview (= 0.74.3) + - React-Fabric/components/view (= 0.74.3) - React-graphics - React-jsi - React-jsiexecutor @@ -528,7 +528,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/inputaccessory (0.74.2): + - React-Fabric/components/inputaccessory (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -547,7 +547,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/legacyviewmanagerinterop (0.74.2): + - React-Fabric/components/legacyviewmanagerinterop (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -566,7 +566,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/modal (0.74.2): + - React-Fabric/components/modal (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -585,7 +585,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/rncore (0.74.2): + - React-Fabric/components/rncore (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -604,7 +604,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/root (0.74.2): + - React-Fabric/components/root (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -623,7 +623,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/safeareaview (0.74.2): + - React-Fabric/components/safeareaview (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -642,7 +642,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/scrollview (0.74.2): + - React-Fabric/components/scrollview (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -661,7 +661,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/text (0.74.2): + - React-Fabric/components/text (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -680,7 +680,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/textinput (0.74.2): + - React-Fabric/components/textinput (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -699,7 +699,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/unimplementedview (0.74.2): + - React-Fabric/components/unimplementedview (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -718,7 +718,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/components/view (0.74.2): + - React-Fabric/components/view (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -738,7 +738,7 @@ PODS: - React-utils - ReactCommon/turbomodule/core - Yoga - - React-Fabric/core (0.74.2): + - React-Fabric/core (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -757,7 +757,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/imagemanager (0.74.2): + - React-Fabric/imagemanager (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -776,7 +776,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/leakchecker (0.74.2): + - React-Fabric/leakchecker (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -795,7 +795,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/mounting (0.74.2): + - React-Fabric/mounting (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -814,7 +814,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/scheduler (0.74.2): + - React-Fabric/scheduler (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -833,7 +833,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/telemetry (0.74.2): + - React-Fabric/telemetry (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -852,7 +852,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/templateprocessor (0.74.2): + - React-Fabric/templateprocessor (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -871,7 +871,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/textlayoutmanager (0.74.2): + - React-Fabric/textlayoutmanager (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -891,7 +891,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-Fabric/uimanager (0.74.2): + - React-Fabric/uimanager (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog @@ -910,45 +910,45 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon/turbomodule/core - - React-FabricImage (0.74.2): + - React-FabricImage (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly/Fabric (= 2024.01.01.00) - - RCTRequired (= 0.74.2) - - RCTTypeSafety (= 0.74.2) + - RCTRequired (= 0.74.3) + - RCTTypeSafety (= 0.74.3) - React-Fabric - React-graphics - React-ImageManager - React-jsi - - React-jsiexecutor (= 0.74.2) + - React-jsiexecutor (= 0.74.3) - React-logger - React-rendererdebug - React-utils - ReactCommon - Yoga - - React-featureflags (0.74.2) - - React-graphics (0.74.2): + - React-featureflags (0.74.3) + - React-graphics (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - RCT-Folly/Fabric (= 2024.01.01.00) - - React-Core/Default (= 0.74.2) + - React-Core/Default (= 0.74.3) - React-utils - - React-hermes (0.74.2): + - React-hermes (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-cxxreact (= 0.74.2) + - React-cxxreact (= 0.74.3) - React-jsi - - React-jsiexecutor (= 0.74.2) + - React-jsiexecutor (= 0.74.3) - React-jsinspector - - React-perflogger (= 0.74.2) + - React-perflogger (= 0.74.3) - React-runtimeexecutor - - React-ImageManager (0.74.2): + - React-ImageManager (0.74.3): - glog - RCT-Folly/Fabric - React-Core/Default @@ -957,44 +957,44 @@ PODS: - React-graphics - React-rendererdebug - React-utils - - React-jserrorhandler (0.74.2): + - React-jserrorhandler (0.74.3): - RCT-Folly/Fabric (= 2024.01.01.00) - React-debug - React-jsi - React-Mapbuffer - - React-jsi (0.74.2): + - React-jsi (0.74.3): - boost (= 1.83.0) - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-jsiexecutor (0.74.2): + - React-jsiexecutor (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-cxxreact (= 0.74.2) - - React-jsi (= 0.74.2) + - React-cxxreact (= 0.74.3) + - React-jsi (= 0.74.3) - React-jsinspector - - React-perflogger (= 0.74.2) - - React-jsinspector (0.74.2): + - React-perflogger (= 0.74.3) + - React-jsinspector (0.74.3): - DoubleConversion - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - React-featureflags - React-jsi - - React-runtimeexecutor (= 0.74.2) - - React-jsitracing (0.74.2): + - React-runtimeexecutor (= 0.74.3) + - React-jsitracing (0.74.3): - React-jsi - - React-logger (0.74.2): + - React-logger (0.74.3): - glog - - React-Mapbuffer (0.74.2): + - React-Mapbuffer (0.74.3): - glog - React-debug - - "react-native-video (6.2.0+dolbyxp.1.2)": + - "react-native-video (6.4.2+dolbyxp.1.5)": - DoubleConversion - glog - hermes-engine @@ -1008,7 +1008,7 @@ PODS: - React-featureflags - React-graphics - React-ImageManager - - "react-native-video/Video (= 6.2.0+dolbyxp.1.2)" + - "react-native-video/Video (= 6.4.2+dolbyxp.1.5)" - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -1016,7 +1016,7 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - "react-native-video/Video (6.2.0+dolbyxp.1.2)": + - react-native-video-plugin-sample (0.0.0): - DoubleConversion - glog - hermes-engine @@ -1030,6 +1030,7 @@ PODS: - React-featureflags - React-graphics - React-ImageManager + - react-native-video - React-NativeModulesApple - React-RCTFabric - React-rendererdebug @@ -1037,8 +1038,29 @@ PODS: - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - Yoga - - React-nativeconfig (0.74.2) - - React-NativeModulesApple (0.74.2): + - "react-native-video/Video (6.4.2+dolbyxp.1.5)": + - DoubleConversion + - glog + - hermes-engine + - RCT-Folly (= 2024.01.01.00) + - RCTRequired + - RCTTypeSafety + - React-Codegen + - React-Core + - React-debug + - React-Fabric + - React-featureflags + - React-graphics + - React-ImageManager + - React-NativeModulesApple + - React-RCTFabric + - React-rendererdebug + - React-utils + - ReactCommon/turbomodule/bridging + - ReactCommon/turbomodule/core + - Yoga + - React-nativeconfig (0.74.3) + - React-NativeModulesApple (0.74.3): - glog - hermes-engine - React-callinvoker @@ -1049,10 +1071,10 @@ PODS: - React-runtimeexecutor - ReactCommon/turbomodule/bridging - ReactCommon/turbomodule/core - - React-perflogger (0.74.2) - - React-RCTActionSheet (0.74.2): - - React-Core/RCTActionSheetHeaders (= 0.74.2) - - React-RCTAnimation (0.74.2): + - React-perflogger (0.74.3) + - React-RCTActionSheet (0.74.3): + - React-Core/RCTActionSheetHeaders (= 0.74.3) + - React-RCTAnimation (0.74.3): - RCT-Folly (= 2024.01.01.00) - RCTTypeSafety - React-Codegen @@ -1060,7 +1082,7 @@ PODS: - React-jsi - React-NativeModulesApple - ReactCommon - - React-RCTAppDelegate (0.74.2): + - React-RCTAppDelegate (0.74.3): - RCT-Folly (= 2024.01.01.00) - RCTRequired - RCTTypeSafety @@ -1084,7 +1106,7 @@ PODS: - React-runtimescheduler - React-utils - ReactCommon - - React-RCTBlob (0.74.2): + - React-RCTBlob (0.74.3): - DoubleConversion - fmt (= 9.1.0) - hermes-engine @@ -1097,7 +1119,7 @@ PODS: - React-NativeModulesApple - React-RCTNetwork - ReactCommon - - React-RCTFabric (0.74.2): + - React-RCTFabric (0.74.3): - glog - hermes-engine - RCT-Folly/Fabric (= 2024.01.01.00) @@ -1117,7 +1139,7 @@ PODS: - React-runtimescheduler - React-utils - Yoga - - React-RCTImage (0.74.2): + - React-RCTImage (0.74.3): - RCT-Folly (= 2024.01.01.00) - RCTTypeSafety - React-Codegen @@ -1126,14 +1148,14 @@ PODS: - React-NativeModulesApple - React-RCTNetwork - ReactCommon - - React-RCTLinking (0.74.2): + - React-RCTLinking (0.74.3): - React-Codegen - - React-Core/RCTLinkingHeaders (= 0.74.2) - - React-jsi (= 0.74.2) + - React-Core/RCTLinkingHeaders (= 0.74.3) + - React-jsi (= 0.74.3) - React-NativeModulesApple - ReactCommon - - ReactCommon/turbomodule/core (= 0.74.2) - - React-RCTNetwork (0.74.2): + - ReactCommon/turbomodule/core (= 0.74.3) + - React-RCTNetwork (0.74.3): - RCT-Folly (= 2024.01.01.00) - RCTTypeSafety - React-Codegen @@ -1141,7 +1163,7 @@ PODS: - React-jsi - React-NativeModulesApple - ReactCommon - - React-RCTSettings (0.74.2): + - React-RCTSettings (0.74.3): - RCT-Folly (= 2024.01.01.00) - RCTTypeSafety - React-Codegen @@ -1149,23 +1171,23 @@ PODS: - React-jsi - React-NativeModulesApple - ReactCommon - - React-RCTText (0.74.2): - - React-Core/RCTTextHeaders (= 0.74.2) + - React-RCTText (0.74.3): + - React-Core/RCTTextHeaders (= 0.74.3) - Yoga - - React-RCTVibration (0.74.2): + - React-RCTVibration (0.74.3): - RCT-Folly (= 2024.01.01.00) - React-Codegen - React-Core/RCTVibrationHeaders - React-jsi - React-NativeModulesApple - ReactCommon - - React-rendererdebug (0.74.2): + - React-rendererdebug (0.74.3): - DoubleConversion - fmt (= 9.1.0) - RCT-Folly (= 2024.01.01.00) - React-debug - - React-rncore (0.74.2) - - React-RuntimeApple (0.74.2): + - React-rncore (0.74.3) + - React-RuntimeApple (0.74.3): - hermes-engine - RCT-Folly/Fabric (= 2024.01.01.00) - React-callinvoker @@ -1183,7 +1205,7 @@ PODS: - React-runtimeexecutor - React-RuntimeHermes - React-utils - - React-RuntimeCore (0.74.2): + - React-RuntimeCore (0.74.3): - glog - hermes-engine - RCT-Folly/Fabric (= 2024.01.01.00) @@ -1196,9 +1218,9 @@ PODS: - React-runtimeexecutor - React-runtimescheduler - React-utils - - React-runtimeexecutor (0.74.2): - - React-jsi (= 0.74.2) - - React-RuntimeHermes (0.74.2): + - React-runtimeexecutor (0.74.3): + - React-jsi (= 0.74.3) + - React-RuntimeHermes (0.74.3): - hermes-engine - RCT-Folly/Fabric (= 2024.01.01.00) - React-featureflags @@ -1209,7 +1231,7 @@ PODS: - React-nativeconfig - React-RuntimeCore - React-utils - - React-runtimescheduler (0.74.2): + - React-runtimescheduler (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) @@ -1221,51 +1243,51 @@ PODS: - React-rendererdebug - React-runtimeexecutor - React-utils - - React-utils (0.74.2): + - React-utils (0.74.3): - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - React-debug - - React-jsi (= 0.74.2) - - ReactCommon (0.74.2): - - ReactCommon/turbomodule (= 0.74.2) - - ReactCommon/turbomodule (0.74.2): + - React-jsi (= 0.74.3) + - ReactCommon (0.74.3): + - ReactCommon/turbomodule (= 0.74.3) + - ReactCommon/turbomodule (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-callinvoker (= 0.74.2) - - React-cxxreact (= 0.74.2) - - React-jsi (= 0.74.2) - - React-logger (= 0.74.2) - - React-perflogger (= 0.74.2) - - ReactCommon/turbomodule/bridging (= 0.74.2) - - ReactCommon/turbomodule/core (= 0.74.2) - - ReactCommon/turbomodule/bridging (0.74.2): + - React-callinvoker (= 0.74.3) + - React-cxxreact (= 0.74.3) + - React-jsi (= 0.74.3) + - React-logger (= 0.74.3) + - React-perflogger (= 0.74.3) + - ReactCommon/turbomodule/bridging (= 0.74.3) + - ReactCommon/turbomodule/core (= 0.74.3) + - ReactCommon/turbomodule/bridging (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-callinvoker (= 0.74.2) - - React-cxxreact (= 0.74.2) - - React-jsi (= 0.74.2) - - React-logger (= 0.74.2) - - React-perflogger (= 0.74.2) - - ReactCommon/turbomodule/core (0.74.2): + - React-callinvoker (= 0.74.3) + - React-cxxreact (= 0.74.3) + - React-jsi (= 0.74.3) + - React-logger (= 0.74.3) + - React-perflogger (= 0.74.3) + - ReactCommon/turbomodule/core (0.74.3): - DoubleConversion - fmt (= 9.1.0) - glog - hermes-engine - RCT-Folly (= 2024.01.01.00) - - React-callinvoker (= 0.74.2) - - React-cxxreact (= 0.74.2) - - React-debug (= 0.74.2) - - React-jsi (= 0.74.2) - - React-logger (= 0.74.2) - - React-perflogger (= 0.74.2) - - React-utils (= 0.74.2) + - React-callinvoker (= 0.74.3) + - React-cxxreact (= 0.74.3) + - React-debug (= 0.74.3) + - React-jsi (= 0.74.3) + - React-logger (= 0.74.3) + - React-perflogger (= 0.74.3) + - React-utils (= 0.74.3) - RNCPicker (2.7.5): - React-Core - SDWebImage (5.19.2): @@ -1324,6 +1346,7 @@ DEPENDENCIES: - React-logger (from `../node_modules/react-native/ReactCommon/logger`) - React-Mapbuffer (from `../node_modules/react-native/ReactCommon`) - react-native-video (from `../../..`) + - react-native-video-plugin-sample (from `../../react-native-video-plugin-sample`) - React-nativeconfig (from `../node_modules/react-native/ReactCommon`) - React-NativeModulesApple (from `../node_modules/react-native/ReactCommon/react/nativemodule/core/platform/ios`) - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) @@ -1390,6 +1413,7 @@ EXTERNAL SOURCES: :podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec" hermes-engine: :podspec: "../node_modules/react-native/sdks/hermes-engine/hermes-engine.podspec" + :tag: hermes-2024-06-28-RNv0.74.3-7bda0c267e76d11b68a585f84cfdd65000babf85 RCT-Folly: :podspec: "../node_modules/react-native/third-party-podspecs/RCT-Folly.podspec" RCTDeprecation: @@ -1440,6 +1464,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon" react-native-video: :path: "../../.." + react-native-video-plugin-sample: + :path: "../../react-native-video-plugin-sample" React-nativeconfig: :path: "../node_modules/react-native/ReactCommon" React-NativeModulesApple: @@ -1495,76 +1521,77 @@ SPEC CHECKSUMS: boost: d3f49c53809116a5d38da093a8aa78bf551aed09 DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 EXConstants: 409690fbfd5afea964e5e9d6c4eb2c2b59222c59 - Expo: 9c87c876b45a6934894ba5e9353ee94fdba48125 - ExpoAsset: 39e60dc31b16e204a9949caf3edb6dcda322e667 + Expo: 675a5642b5860771507237259da50b921c03a9f3 + ExpoAsset: 323700f291684f110fb55f0d4022a3362ea9f875 ExpoFileSystem: 80bfe850b1f9922c16905822ecbf97acd711dc51 ExpoFont: 43b69559cef3d773db57c7ae7edd3cb0aa0dc610 ExpoImage: 2ccccff1219ebc765e344f3338f2430af2df4824 ExpoKeepAwake: 3b8815d9dd1d419ee474df004021c69fdd316d08 - ExpoModulesCore: 2731dc119f8c1400636a994df4efbc19522defbd - FBLazyVector: 4bc164e5b5e6cfc288d2b5ff28643ea15fa1a589 + ExpoModulesCore: b2fa8cc3c12f0ba45a9ae125c0e3bcad04f3fb7b + FBLazyVector: 7e977dd099937dc5458851233141583abba49ff2 fmt: 4c2741a687cc09f0634a2e2c72a838b99f1ff120 - glog: c5d68082e772fa1c511173d6b30a9de2c05a69a2 - hermes-engine: 01d3e052018c2a13937aca1860fbedbccd4a41b7 + glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f + hermes-engine: 1f547997900dd0752dc0cc0ae6dd16173c49e09b libavif: 84bbb62fb232c3018d6f1bab79beea87e35de7b7 libdav1d: 23581a4d8ec811ff171ed5e2e05cd27bad64c39f libwebp: 1786c9f4ff8a279e4dac1e8f385004d5fc253009 - RCT-Folly: 045d6ecaa59d826c5736dfba0b2f4083ff8d79df - RCTDeprecation: b03c35057846b685b3ccadc9bfe43e349989cdb2 - RCTRequired: 194626909cfa8d39ca6663138c417bc6c431648c - RCTTypeSafety: 552aff5b8e8341660594db00e53ac889682bc120 - React: a57fe42044fe6ed3e828f8867ce070a6c5872754 - React-callinvoker: 6bedefb354a8848b534752417954caa3a5cf34f9 - React-Codegen: dd259bee42d0b3f511c054ad7d2c34b9c61ac7d5 - React-Core: 289ee3dfc1639bb9058c1e77427bb48169c26d7a - React-CoreModules: eda5ce541a1f552158317abd90a5a0f6a4f8d6f7 - React-cxxreact: 56bd17ccc6d4248116f7f95884ddb8c528379fb6 - React-debug: c15fd39ae1d2eee8619f923203f3852d12d32937 - React-Fabric: f6d33e4407e75ed616561257915a7a31b82c12d2 - React-FabricImage: 1b327a02a376e908d8e220114590febca05ccd56 - React-featureflags: 2e6c82cdada488928df15d293c9cb06bd5d74cea - React-graphics: 192b5905a8d8198281ea4d508bd320a3f34479df - React-hermes: 6ccc301ababfa17a9aad25a7e33faf325fd024b4 - React-ImageManager: 1a3ded3a51b6d8058a5733db1b3c4addc5c61770 - React-jserrorhandler: 2e1c8f5f806275d396ab9b30f7aaeccc89ddc659 - React-jsi: 828703c235f4eea1647897ee8030efdc6e8e9f14 - React-jsiexecutor: 713d7bbef0a410cee5b3b78f73ed1fc16e177ba7 - React-jsinspector: a5866e1e0fb3ba64d5fec071956608eabae59781 - React-jsitracing: 34bc0fbc606f69e66f05286d94d5cd6cbf2ef562 - React-logger: 29fa3e048f5f67fe396bc08af7606426d9bd7b5d - React-Mapbuffer: 86703e9e4f6522053568300827b436ccc01e1101 - react-native-video: 59f262a2d87c998b747ca1f031efb6eba1c156b5 - React-nativeconfig: 5d452e509d6fbedc1522e21b566451fc673ac6b7 - React-NativeModulesApple: 6560431301ffdab8df6212cc8c8eff779396d8e0 - React-perflogger: 32ed45d9cee02cf6639acae34251590dccd30994 - React-RCTActionSheet: 19f967ddaea258182b56ef11437133b056ba2adf - React-RCTAnimation: d7f4137fc44a08bba465267ea7cb1dbdb7c4ec87 - React-RCTAppDelegate: 2b3f4d8009796af209a0d496e73276b743acee08 - React-RCTBlob: c6c3e1e0251700b7bea036b893913f22e2b9cb47 - React-RCTFabric: bff98f06c6877ab795b6a71bec60ec726879eec7 - React-RCTImage: 40528ab74a4fef0f0e2ee797a074b26d120b6cc6 - React-RCTLinking: 385b5beb96749aae9ae1606746e883e1c9f8a6a7 - React-RCTNetwork: ffc9f05bd8fa5b3bce562199ba41235ad0af645c - React-RCTSettings: 21914178bb65cb2c20c655ae1fb401617ae74618 - React-RCTText: 7f8dba1a311e99f4de15bbace2350e805f33f024 - React-RCTVibration: e4ccf673579d0d94a96b3a0b64492db08f8324d5 - React-rendererdebug: 1de9082085320466edb7c184bb23cdc614cc2293 - React-rncore: f8ce315afbe0835cc2324552e1019a956cb1ce36 - React-RuntimeApple: 025152efc25b08603a732fdc17e752973a17d785 - React-RuntimeCore: 965f409abab69cef1cd4e99a9c6748d9380456a5 - React-runtimeexecutor: 5961acc7a77b69f964e1645a5d6069e124ce6b37 - React-RuntimeHermes: 839b5525fa6171ed227f0ef351761b699cfc78ab - React-runtimescheduler: 1f0b3361460921edcbe9042ce690e5ca6dab9639 - React-utils: 5a40a1bb87d8c2d42a6bbbb7ead6d95785ca6042 - ReactCommon: e5866ad8f7487779853fa3fe33f1c075207c3262 + RCT-Folly: 02617c592a293bd6d418e0a88ff4ee1f88329b47 + RCTDeprecation: 4c7eeb42be0b2e95195563c49be08d0b839d22b4 + RCTRequired: d530a0f489699c8500e944fde963102c42dcd0c2 + RCTTypeSafety: b20878506b094fa3d9007d7b9e4be0faa3562499 + React: 2f9da0177233f60fa3462d83fcccde245759f81a + React-callinvoker: d0205f0dcebf72ec27263ab41e3a5ad827ed503f + React-Codegen: 27212e14727ad7d6d9fd1b1967fbf21929e4ce29 + React-Core: 690ebbbf8f8dcfba6686ce8927731d3f025c3114 + React-CoreModules: 185da31f5eb2e6043c3d19b10c64c4661322ed6a + React-cxxreact: c53d2ac9246235351086b8c588feaf775b4ec7f7 + React-debug: 40caf8ab4c0fd3afe831912e3d4d0e7303eecc5d + React-Fabric: 51ccb4f7e45df5837e796f339d602737063c463e + React-FabricImage: 376b7a81bfe64102e7da5fc85cd1775638584c92 + React-featureflags: 0d0576ae8306801a8a660b36afcdbda04dd7cc12 + React-graphics: e0e6b8fbb1c5968c70d3584dccec42544b769b60 + React-hermes: 917b7ab4c3cb9204c2ad020d74f313830097148b + React-ImageManager: 5cebcc0136f3b309c7f5189b96e6c0ebd0ec8192 + React-jserrorhandler: 5dc7e036cba3b7d167380c02afabf818ad0b2f98 + React-jsi: 024b933267079f80c30a5cae97bf5ce521217505 + React-jsiexecutor: 45cb079c87db3f514da3acfc686387a0e01de5c5 + React-jsinspector: c9551971f1298163c93e2bfb082c2b4245618fc6 + React-jsitracing: 1aa5681c353b41573b03e0e480a5adf5fa1c56d8 + React-logger: fa92ba4d3a5d39ac450f59be2a3cec7b099f0304 + React-Mapbuffer: 70da5955150a58732e9336a0c7e71cd49e909f25 + react-native-video: 62466b25be5b825ea1ed781aaa88271037d21d2c + react-native-video-plugin-sample: d3a93b7ad777cad7fa2c30473de75a2635ce5feb + React-nativeconfig: 84806b820491db30175afbf027e99e8415dc63f0 + React-NativeModulesApple: 7b79212f8cf496ab554e0b7b09acbd4aa4690260 + React-perflogger: 7bb9ba49435ff66b666e7966ee10082508a203e8 + React-RCTActionSheet: a2816ae2b5c8523c2bc18a8f874a724a096e6d97 + React-RCTAnimation: e78f52d7422bac13e1213e25e9bcbf99be872e1a + React-RCTAppDelegate: 24f46de486cfa3a9f46e4b0786eaf17d92e1e0c6 + React-RCTBlob: 9f9d6599d1b00690704dadc4a4bc33a7e76938be + React-RCTFabric: 416d20a24b117a7ec7d32088fc8f359b5e558fa7 + React-RCTImage: 39dd5aee6b92213845e1e7a7c41865801dc33493 + React-RCTLinking: 35d742a982f901f9ea416d772763e2da65c2dc7d + React-RCTNetwork: b078576c0c896c71905f841716b9f9f5922111dc + React-RCTSettings: 900aab52b5b1212f247c2944d88f4defbf6146f2 + React-RCTText: a3895ab4e5df4a5fd41b6f059eed484a0c7016d1 + React-RCTVibration: ab4912e1427d8de00ef89e9e6582094c4c25dc05 + React-rendererdebug: 8ea55aebb8cba804db2a8449a2f0c80ccfe0ce5a + React-rncore: 1f725aee4e00c317e51cb4d37aca7f6a47da9a11 + React-RuntimeApple: c1833d8e82f7c5314c001d61d289849c75217944 + React-RuntimeCore: 0a5b37b50737af3505b5801376ae5788532c013e + React-runtimeexecutor: 69cab8ddf409de6d6a855a71c8af9e7290c4e55b + React-RuntimeHermes: 44847ba3e8a9394b9829d9a9abde7590624f32d0 + React-runtimescheduler: e4ad653e1d2f5ff40ba047446cacde009694f0ed + React-utils: 6f7ac39d9a0de447d4334bb25d144a28c0c5d8c9 + ReactCommon: 4a09c7d8a06e93c1e2e988a3b9f3db3d2449f2fc RNCPicker: 3e2c37a8328f368ce14da050cdc8231deb5fc9f9 SDWebImage: dfe95b2466a9823cf9f0c6d01217c06550d7b29a SDWebImageAVIFCoder: 00310d246aab3232ce77f1d8f0076f8c4b021d90 SDWebImageSVGCoder: 15a300a97ec1c8ac958f009c02220ac0402e936c SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380 SocketRocket: abac6f5de4d4d62d24e11868d7a2f427e0ef940d - Yoga: 45564236f670899c9739b1581a12b00ead5d391f + Yoga: bd92064a0d558be92786820514d74fc4dddd1233 -PODFILE CHECKSUM: dfb9633fc816e568fd6d90dde654d15acd66faa9 +PODFILE CHECKSUM: a73d485df51877001f2b04a5a4379cfa5a3ba8fa COCOAPODS: 1.15.2 diff --git a/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj b/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj index 2c6b3b56c5..41daeee513 100644 --- a/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj +++ b/examples/basic/ios/videoplayer.xcodeproj/project.pbxproj @@ -8,15 +8,16 @@ /* Begin PBXBuildFile section */ 00E356F31AD99517003FC87E /* videoplayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* videoplayerTests.m */; }; - 11C6209C7B72C624AC36CAD1 /* Pods_videoplayer_videoplayerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 594390EE3512A597F6D2CFC8 /* Pods_videoplayer_videoplayerTests.framework */; }; 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.mm */; }; 13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; }; 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; + 208BB513171FFCC3277F9E0F /* Pods_videoplayer_videoplayerTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A5C7FBD972AC23420C9CAEF6 /* Pods_videoplayer_videoplayerTests.framework */; }; 20E2D2234B216472515590E5 /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B7A50CD29E62AE55CDBAC5 /* ExpoModulesProvider.swift */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; 8564D8A0ECE6B35EF7A78EDB /* ExpoModulesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF6DF30451E50AB13568EFC /* ExpoModulesProvider.swift */; }; - A64041D5CF85945B698F6FD0 /* Pods_videoplayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4610D42AC113C0F184AAF5BC /* Pods_videoplayer.framework */; }; + C57DB7DC75FFA5378D941129 /* Pods_videoplayer.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 10FD7EDE51B5059CB0982AD2 /* Pods_videoplayer.framework */; }; DA6F026ACB11B4361D7006B9 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 06EB80F4634394ABC14C45DC /* PrivacyInfo.xcprivacy */; }; + EC73F7EE64DE3B7F743B618D /* BuildFile in Frameworks */ = {isa = PBXBuildFile; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -33,22 +34,22 @@ 00E356EE1AD99517003FC87E /* videoplayerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = videoplayerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 00E356F21AD99517003FC87E /* videoplayerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = videoplayerTests.m; sourceTree = ""; }; + 058979377AFD7ECE5B23DBEB /* Pods-videoplayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer.release.xcconfig"; path = "Target Support Files/Pods-videoplayer/Pods-videoplayer.release.xcconfig"; sourceTree = ""; }; 06EB80F4634394ABC14C45DC /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; includeInIndex = 1; name = PrivacyInfo.xcprivacy; path = videoplayer/PrivacyInfo.xcprivacy; sourceTree = ""; }; + 10FD7EDE51B5059CB0982AD2 /* Pods_videoplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_videoplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07F961A680F5B00A75B9A /* videoplayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = videoplayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = videoplayer/AppDelegate.h; sourceTree = ""; }; 13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = videoplayer/AppDelegate.mm; sourceTree = ""; }; 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = videoplayer/Images.xcassets; sourceTree = ""; }; 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = videoplayer/Info.plist; sourceTree = ""; }; 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = videoplayer/main.m; sourceTree = ""; }; - 327740C386721461467B91B2 /* Pods-videoplayer.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer.release.xcconfig"; path = "Target Support Files/Pods-videoplayer/Pods-videoplayer.release.xcconfig"; sourceTree = ""; }; - 4610D42AC113C0F184AAF5BC /* Pods_videoplayer.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_videoplayer.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 5112808AA45F803BD0D3F411 /* Pods-videoplayer-videoplayerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer-videoplayerTests.release.xcconfig"; path = "Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests.release.xcconfig"; sourceTree = ""; }; - 594390EE3512A597F6D2CFC8 /* Pods_videoplayer_videoplayerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_videoplayer_videoplayerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 6E6DE29C8B861F4D5A4BBDEB /* Pods-videoplayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer.debug.xcconfig"; path = "Target Support Files/Pods-videoplayer/Pods-videoplayer.debug.xcconfig"; sourceTree = ""; }; + 2F5C4E6DD1564FCB6C9B7B94 /* Pods-videoplayer-videoplayerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer-videoplayerTests.debug.xcconfig"; path = "Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests.debug.xcconfig"; sourceTree = ""; }; 7AF6DF30451E50AB13568EFC /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-videoplayer-videoplayerTests/ExpoModulesProvider.swift"; sourceTree = ""; }; 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = videoplayer/LaunchScreen.storyboard; sourceTree = ""; }; + 9C018F4E223E0E71BA85ABC9 /* Pods-videoplayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer.debug.xcconfig"; path = "Target Support Files/Pods-videoplayer/Pods-videoplayer.debug.xcconfig"; sourceTree = ""; }; + A5C7FBD972AC23420C9CAEF6 /* Pods_videoplayer_videoplayerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_videoplayer_videoplayerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B9B7A50CD29E62AE55CDBAC5 /* ExpoModulesProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; name = ExpoModulesProvider.swift; path = "Pods/Target Support Files/Pods-videoplayer/ExpoModulesProvider.swift"; sourceTree = ""; }; - CBE734469FBE698BF938A7EF /* Pods-videoplayer-videoplayerTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer-videoplayerTests.debug.xcconfig"; path = "Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests.debug.xcconfig"; sourceTree = ""; }; + CF1F0C5E1D8D8D557C4C7043 /* Pods-videoplayer-videoplayerTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-videoplayer-videoplayerTests.release.xcconfig"; path = "Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests.release.xcconfig"; sourceTree = ""; }; ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; }; /* End PBXFileReference section */ @@ -57,7 +58,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 11C6209C7B72C624AC36CAD1 /* Pods_videoplayer_videoplayerTests.framework in Frameworks */, + 208BB513171FFCC3277F9E0F /* Pods_videoplayer_videoplayerTests.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -65,7 +66,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - A64041D5CF85945B698F6FD0 /* Pods_videoplayer.framework in Frameworks */, + EC73F7EE64DE3B7F743B618D /* BuildFile in Frameworks */, + C57DB7DC75FFA5378D941129 /* Pods_videoplayer.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -107,8 +109,8 @@ isa = PBXGroup; children = ( ED297162215061F000B7C4FE /* JavaScriptCore.framework */, - 4610D42AC113C0F184AAF5BC /* Pods_videoplayer.framework */, - 594390EE3512A597F6D2CFC8 /* Pods_videoplayer_videoplayerTests.framework */, + 10FD7EDE51B5059CB0982AD2 /* Pods_videoplayer.framework */, + A5C7FBD972AC23420C9CAEF6 /* Pods_videoplayer_videoplayerTests.framework */, ); name = Frameworks; sourceTree = ""; @@ -165,10 +167,10 @@ BBD78D7AC51CEA395F1C20DB /* Pods */ = { isa = PBXGroup; children = ( - 6E6DE29C8B861F4D5A4BBDEB /* Pods-videoplayer.debug.xcconfig */, - 327740C386721461467B91B2 /* Pods-videoplayer.release.xcconfig */, - CBE734469FBE698BF938A7EF /* Pods-videoplayer-videoplayerTests.debug.xcconfig */, - 5112808AA45F803BD0D3F411 /* Pods-videoplayer-videoplayerTests.release.xcconfig */, + 9C018F4E223E0E71BA85ABC9 /* Pods-videoplayer.debug.xcconfig */, + 058979377AFD7ECE5B23DBEB /* Pods-videoplayer.release.xcconfig */, + 2F5C4E6DD1564FCB6C9B7B94 /* Pods-videoplayer-videoplayerTests.debug.xcconfig */, + CF1F0C5E1D8D8D557C4C7043 /* Pods-videoplayer-videoplayerTests.release.xcconfig */, ); path = Pods; sourceTree = ""; @@ -188,13 +190,13 @@ isa = PBXNativeTarget; buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "videoplayerTests" */; buildPhases = ( - C0C880E0881EE98C1792E57D /* [CP] Check Pods Manifest.lock */, + 05848CC282AE20BB2B2AA52D /* [CP] Check Pods Manifest.lock */, E0436766C647BDEAF9FD5ED3 /* [Expo] Configure project */, 00E356EA1AD99517003FC87E /* Sources */, 00E356EB1AD99517003FC87E /* Frameworks */, 00E356EC1AD99517003FC87E /* Resources */, - E3461B2529EDAA05BCA42787 /* [CP] Embed Pods Frameworks */, - 0765D094F5C79DBE6CC6386B /* [CP] Copy Pods Resources */, + 0F69B47FEB727B4EBBAC0C93 /* [CP] Embed Pods Frameworks */, + 8DEA7E188641F8CD9B4543DD /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -210,15 +212,15 @@ isa = PBXNativeTarget; buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "videoplayer" */; buildPhases = ( - 66FA7E36D064B737784DDFB7 /* [CP] Check Pods Manifest.lock */, + 4BC7B73D9362CA23BDA1E909 /* [CP] Check Pods Manifest.lock */, FD10A7F022414F080027D42C /* Start Packager */, 43E82399B51FE7A2CADEE958 /* [Expo] Configure project */, 13B07F871A680F5B00A75B9A /* Sources */, 13B07F8C1A680F5B00A75B9A /* Frameworks */, 13B07F8E1A680F5B00A75B9A /* Resources */, 00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */, - 189A4605ED0B2F88CF1DCFA8 /* [CP] Embed Pods Frameworks */, - F467D0E16E9AD72917847B43 /* [CP] Copy Pods Resources */, + 5580EE7ED1DD133A3CB36FB0 /* [CP] Embed Pods Frameworks */, + 4617BBDCD64674510B35868A /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -302,38 +304,43 @@ 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')\")\"\nfi\nif [[ -z \"$BUNDLE_COMMAND\" ]]; then\n # Default Expo CLI command for bundling\n export BUNDLE_COMMAND=\"export:embed\"\nfi\n\n`\"$NODE_BINARY\" --print \"require('path').dirname(require.resolve('react-native/package.json')) + '/scripts/react-native-xcode.sh'\"`\n"; }; - 0765D094F5C79DBE6CC6386B /* [CP] Copy Pods Resources */ = { + 05848CC282AE20BB2B2AA52D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Copy Pods Resources"; + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-videoplayer-videoplayerTests-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources.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; }; - 189A4605ED0B2F88CF1DCFA8 /* [CP] Embed Pods Frameworks */ = { + 0F69B47FEB727B4EBBAC0C93 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks-${CONFIGURATION}-input-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks-${CONFIGURATION}-output-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks.sh\"\n"; showEnvVarsInLog = 0; }; 43E82399B51FE7A2CADEE958 /* [Expo] Configure project */ = { @@ -355,29 +362,24 @@ shellPath = /bin/sh; shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-videoplayer/expo-configure-project.sh\"\n"; }; - 66FA7E36D064B737784DDFB7 /* [CP] Check Pods Manifest.lock */ = { + 4617BBDCD64674510B35868A /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - "${PODS_PODFILE_DIR_PATH}/Podfile.lock", - "${PODS_ROOT}/Manifest.lock", - ); - name = "[CP] Check Pods Manifest.lock"; + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( - ); - outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-videoplayer-checkManifestLockResult.txt", + "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; 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-videoplayer/Pods-videoplayer-resources.sh\"\n"; showEnvVarsInLog = 0; }; - C0C880E0881EE98C1792E57D /* [CP] Check Pods Manifest.lock */ = { + 4BC7B73D9362CA23BDA1E909 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -392,65 +394,65 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-videoplayer-videoplayerTests-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-videoplayer-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; 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"; showEnvVarsInLog = 0; }; - E0436766C647BDEAF9FD5ED3 /* [Expo] Configure project */ = { + 5580EE7ED1DD133A3CB36FB0 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; - alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); - name = "[Expo] Configure project"; + name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( - ); - outputPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-videoplayer-videoplayerTests/expo-configure-project.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks.sh\"\n"; + showEnvVarsInLog = 0; }; - E3461B2529EDAA05BCA42787 /* [CP] Embed Pods Frameworks */ = { + 8DEA7E188641F8CD9B4543DD /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks-${CONFIGURATION}-input-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Embed Pods Frameworks"; + name = "[CP] Copy Pods Resources"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist", + "${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources-${CONFIGURATION}-output-files.xcfilelist", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-resources.sh\"\n"; showEnvVarsInLog = 0; }; - F467D0E16E9AD72917847B43 /* [CP] Copy Pods Resources */ = { + E0436766C647BDEAF9FD5ED3 /* [Expo] Configure project */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-input-files.xcfilelist", ); - name = "[CP] Copy Pods Resources"; + inputPaths = ( + ); + name = "[Expo] Configure project"; outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-output-files.xcfilelist", + ); + outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources.sh\"\n"; - showEnvVarsInLog = 0; + shellScript = "# This script configures Expo modules and generates the modules provider file.\nbash -l -c \"./Pods/Target\\ Support\\ Files/Pods-videoplayer-videoplayerTests/expo-configure-project.sh\"\n"; }; FD10A7F022414F080027D42C /* Start Packager */ = { isa = PBXShellScriptBuildPhase; @@ -506,7 +508,7 @@ /* Begin XCBuildConfiguration section */ 00E356F61AD99517003FC87E /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = CBE734469FBE698BF938A7EF /* Pods-videoplayer-videoplayerTests.debug.xcconfig */; + baseConfigurationReference = 2F5C4E6DD1564FCB6C9B7B94 /* Pods-videoplayer-videoplayerTests.debug.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; GCC_PREPROCESSOR_DEFINITIONS = ( @@ -534,7 +536,7 @@ }; 00E356F71AD99517003FC87E /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 5112808AA45F803BD0D3F411 /* Pods-videoplayer-videoplayerTests.release.xcconfig */; + baseConfigurationReference = CF1F0C5E1D8D8D557C4C7043 /* Pods-videoplayer-videoplayerTests.release.xcconfig */; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; COPY_PHASE_STRIP = NO; @@ -559,7 +561,7 @@ }; 13B07F941A680F5B00A75B9A /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 6E6DE29C8B861F4D5A4BBDEB /* Pods-videoplayer.debug.xcconfig */; + baseConfigurationReference = 9C018F4E223E0E71BA85ABC9 /* Pods-videoplayer.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; @@ -587,7 +589,7 @@ }; 13B07F951A680F5B00A75B9A /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 327740C386721461467B91B2 /* Pods-videoplayer.release.xcconfig */; + baseConfigurationReference = 058979377AFD7ECE5B23DBEB /* Pods-videoplayer.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; diff --git a/examples/basic/package.json b/examples/basic/package.json index adb35deb59..86cb65706b 100644 --- a/examples/basic/package.json +++ b/examples/basic/package.json @@ -14,21 +14,21 @@ }, "dependencies": { "@react-native-picker/picker": "2.7.5", - "expo": "^51.0.14", + "expo": "^51.0.17", "expo-asset": "^10.0.9", "expo-image": "^1.12.12", "react": "18.2.0", - "react-native": "0.74.2", + "react-native": "0.74.3", "react-native-windows": "0.74.1" }, "devDependencies": { "@babel/core": "^7.24.0", "@babel/preset-env": "^7.22.10", "@babel/runtime": "^7.22.10", - "@react-native/babel-preset": "0.74.83", - "@react-native/eslint-config": "0.74.83", - "@react-native/metro-config": "0.74.83", - "@react-native/typescript-config": "0.74.83", + "@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", diff --git a/examples/basic/src/MultiValueControl.tsx b/examples/basic/src/MultiValueControl.tsx index bf58f3a96a..d9298ec3b8 100644 --- a/examples/basic/src/MultiValueControl.tsx +++ b/examples/basic/src/MultiValueControl.tsx @@ -1,5 +1,4 @@ -import React, {FunctionComponent} from 'react'; - +import React from 'react'; import { StyleSheet, Text, @@ -9,8 +8,6 @@ import { } from 'react-native'; import {ResizeMode} from 'react-native-video'; -export type MultiValueControlPropType = number | string | ResizeMode; - /* * MultiValueControl displays a list clickable text view */ @@ -21,12 +18,14 @@ interface MultiValueControlType { // The selected value in values selected?: T; // callback to press onPress - onPress: (arg: MultiValueControlPropType) => void; + onPress: (arg: T) => void; } -const MultiValueControl: FunctionComponent< - MultiValueControlType -> = ({values, selected, onPress}) => { +const MultiValueControl = ({ + values, + selected, + onPress, +}: MultiValueControlType) => { const selectedStyle: TextStyle = StyleSheet.flatten([ styles.option, {fontWeight: 'bold'}, @@ -39,7 +38,7 @@ const MultiValueControl: FunctionComponent< return ( - {values.map((value: MultiValueControlPropType) => { + {values.map(value => { const _style = value === selected ? selectedStyle : unselectedStyle; return ( ; - textTracks: Array; - videoTracks: Array; - selectedAudioTrack: SelectedTrack | undefined; - selectedTextTrack: SelectedTrack | undefined; - selectedVideoTrack: SelectedVideoTrack; - srcListId: number; - loop: boolean; - showRNVControls: boolean; - useCache: boolean; - poster?: string; - showNotificationControls: boolean; - isSeeking: boolean; -} - -class VideoPlayer extends Component { - state: StateType = { - rate: 1, - volume: 1, - muted: false, - resizeMode: ResizeMode.CONTAIN, - duration: 0.0, - currentTime: 0.0, - videoWidth: 0, - videoHeight: 0, - paused: false, - fullscreen: true, - decoration: true, - isLoading: false, - audioTracks: [], - textTracks: [], - videoTracks: [], - selectedAudioTrack: undefined, - selectedTextTrack: undefined, - selectedVideoTrack: { - type: SelectedVideoTrackType.AUTO, - }, - srcListId: 0, - loop: false, - showRNVControls: false, - useCache: false, - poster: undefined, - showNotificationControls: false, - isSeeking: false, - }; - - // internal usage change to index if you want to select tracks by index instead of lang - textTracksSelectionBy = 'index'; - - srcAllPlatformList = [ - { - description: 'local file landscape', - uri: require('./broadchurch.mp4'), - }, - { - description: 'local file landscape cropped', - uri: require('./broadchurch.mp4'), - cropStart: 3000, - cropEnd: 10000, - }, - { - description: 'local file portrait', - uri: require('./portrait.mp4'), - metadata: { - title: 'Test Title', - subtitle: 'Test Subtitle', - artist: 'Test Artist', - description: 'Test Description', - imageUri: - 'https://pbs.twimg.com/profile_images/1498641868397191170/6qW2XkuI_400x400.png', - }, - }, - { - description: '(hls|live) red bull tv', - textTracksAllowChunklessPreparation: false, - uri: 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8', - metadata: { - title: 'Custom Title', - subtitle: 'Custom Subtitle', - artist: 'Custom Artist', - description: 'Custom Description', - imageUri: - 'https://pbs.twimg.com/profile_images/1498641868397191170/6qW2XkuI_400x400.png', - }, - }, - { - description: 'invalid URL', - uri: 'mmt://www.youtube.com', - type: 'mpd', - }, - {description: '(no url) Stopped playback', uri: undefined}, - { - description: '(no view) no View', - noView: true, - }, - { - description: 'Another live sample', - uri: 'https://live.forstreet.cl/live/livestream.m3u8', - }, - { - description: 'another bunny (can be saved)', - uri: 'https://rawgit.com/mediaelement/mediaelement-files/master/big_buck_bunny.mp4', - headers: {referer: 'www.github.com', 'User-Agent': 'react.native.video'}, - }, - { - description: 'sintel with subtitles', - uri: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8', - }, - { - description: 'sintel starts at 20sec', - uri: 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8', - startPosition: 50000, - }, - { - description: 'BigBugBunny sideLoaded subtitles', - // sideloaded subtitles wont work for streaming like HLS on ios - // mp4 - uri: 'https://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', - textTracks: [ - { - title: 'test', - language: 'en' as ISO639_1, - type: TextTrackType.VTT, - uri: 'https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt', - }, - ], - }, - ]; - - srcIosList = []; +type Props = NonNullable; - srcAndroidList = [ - { - description: 'Another live sample', - uri: 'https://live.forstreet.cl/live/livestream.m3u8', - }, - { - description: 'asset file', - uri: 'asset:///broadchurch.mp4', - }, - { - description: '(dash) sintel subtitles', - uri: 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd', - }, - { - description: '(mp4) big buck bunny', - uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', - }, - { - description: '(mp4|subtitles) demo with sintel Subtitles', - uri: 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0', - type: 'mpd', - }, - { - description: '(mp4) big buck bunny With Ads', - adTagUrl: - 'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=', - uri: 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4', - }, - { - description: 'WV: Secure SD & HD (cbcs,MP4,H264)', - uri: 'https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd', - drm: { - type: DRMType.WIDEVINE, - licenseServer: - 'https://proxy.uat.widevine.com/proxy?provider=widevine_test', - }, - }, - { - description: 'Secure UHD (cenc)', - uri: 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd', - drm: { - type: DRMType.WIDEVINE, - licenseServer: - 'https://proxy.uat.widevine.com/proxy?provider=widevine_test', - }, - }, - { - description: 'rtsp big bug bunny', - uri: 'rtsp://rtspstream:3cfa3c36a9c00f4aa38f3cd35816b287@zephyr.rtsp.stream/movie', - type: 'rtsp', - }, - ]; - - // poster which can be displayed - samplePoster = - 'https://upload.wikimedia.org/wikipedia/commons/1/18/React_Native_Logo.png'; - - srcList: SampleVideoSource[] = this.srcAllPlatformList.concat( - Platform.OS === 'android' ? this.srcAndroidList : this.srcIosList, +const VideoPlayer: FC = ({}) => { + const [rate, setRate] = useState(1); + const [volume, setVolume] = useState(1); + const [muted, setMuted] = useState(false); + const [resizeMode, setResizeMode] = useState>( + ResizeMode.CONTAIN, ); - - video?: VideoRef; - - popupInfo = () => { - VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => { - VideoDecoderProperties.isHEVCSupported().then((hevc: string) => { - VideoDecoderProperties.isCodecSupported('video/avc', 1920, 1080).then( - (avc: string) => { - this.toast( - true, - 'Widevine level: ' + - widevineLevel + - '\n hevc: ' + - hevc + - '\n avc: ' + - avc, - ); - }, - ); - }); + const [duration, setDuration] = useState(0); + const [currentTime, setCurrentTime] = useState(0); + const [_, setVideoSize] = useState({videoWidth: 0, videoHeight: 0}); + const [paused, setPaused] = useState(false); + const [fullscreen, setFullscreen] = useState(true); + const [decoration, setDecoration] = useState(true); + const [isLoading, setIsLoading] = useState(false); + const [audioTracks, setAudioTracks] = useState([]); + const [textTracks, setTextTracks] = useState([]); + const [videoTracks, setVideoTracks] = useState([]); + const [selectedAudioTrack, setSelectedAudioTrack] = useState< + SelectedTrack | undefined + >(undefined); + const [selectedTextTrack, setSelectedTextTrack] = useState< + SelectedTrack | undefined + >(undefined); + const [selectedVideoTrack, setSelectedVideoTrack] = + useState({ + type: SelectedVideoTrackType.AUTO, }); - }; - - onLoad = (data: OnLoadData) => { - this.setState({duration: data.duration, loading: false}); - this.onAudioTracks(data); - this.onTextTracks(data); - this.onVideoTracks(data); - }; - - onProgress = (data: OnProgressData) => { - this.setState({currentTime: data.currentTime}); - }; - - onSeek = (data: OnSeekData) => { - this.setState({isSeeking: false}); - this.setState({currentTime: data.currentTime}); - }; - - onVideoLoadStart = () => { - console.log('onVideoLoadStart'); - this.setState({isLoading: true}); - }; - - onAudioTracks = (data: OnAudioTracksData) => { + const [srcListId, setSrcListId] = useState(0); + const [repeat, setRepeat] = useState(false); + const [controls, setControls] = useState(false); + const [useCache, setUseCache] = useState(false); + const [poster, setPoster] = useState(undefined); + const [showNotificationControls, setShowNotificationControls] = + useState(false); + const [isSeeking, setIsSeeking] = useState(false); + + const videoRef = useRef(null); + const viewStyle = fullscreen ? styles.fullScreen : styles.halfScreen; + const currentSrc = srcList[srcListId]; + const additional = currentSrc as AdditionalSourceInfo; + + const onAudioTracks = (data: OnAudioTracksData) => { const selectedTrack = data.audioTracks?.find((x: AudioTrack) => { return x.selected; }); if (selectedTrack?.index) { - this.setState({ - audioTracks: data.audioTracks, - selectedAudioTrack: { - type: SelectedVideoTrackType.INDEX, - value: selectedTrack?.index, - }, + setAudioTracks(data.audioTracks); + setSelectedAudioTrack({ + type: SelectedTrackType.INDEX, + value: selectedTrack.index, }); } else { - this.setState({ - audioTracks: data.audioTracks, - }); + setAudioTracks(data.audioTracks); } }; - onVideoTracks = (data: OnVideoTracksData) => { + const onVideoTracks = (data: OnVideoTracksData) => { console.log('onVideoTracks', data.videoTracks); - this.setState({ - videoTracks: data.videoTracks, - }); + setVideoTracks(data.videoTracks); }; - onTextTracks = (data: OnTextTracksData) => { + const onTextTracks = (data: OnTextTracksData) => { const selectedTrack = data.textTracks?.find((x: TextTrack) => { return x?.selected; }); if (selectedTrack?.language) { - this.setState({ - textTracks: data.textTracks, - selectedTextTrack: - this.textTracksSelectionBy === 'index' - ? { - type: 'index', - value: selectedTrack?.index, - } - : { - type: 'language', - value: selectedTrack?.language, - }, - }); + setTextTracks(data.textTracks); + if (textTracksSelectionBy === 'index') { + setSelectedTextTrack({ + type: SelectedTrackType.INDEX, + value: selectedTrack?.index, + }); + } else { + setSelectedTextTrack({ + type: SelectedTrackType.LANGUAGE, + value: selectedTrack?.language, + }); + } } else { - this.setState({ - textTracks: data.textTracks, - }); + setTextTracks(data.textTracks); } }; - onTextTrackDataChanged = (data: OnTextTrackDataChangedData) => { + const onLoad = (data: OnLoadData) => { + setDuration(data.duration); + onAudioTracks(data); + onTextTracks(data); + onVideoTracks(data); + }; + + const onProgress = (data: OnProgressData) => { + setCurrentTime(data.currentTime); + }; + + const onSeek = (data: OnSeekData) => { + setCurrentTime(data.currentTime); + setIsSeeking(false); + }; + + const onVideoLoadStart = () => { + console.log('onVideoLoadStart'); + setIsLoading(true); + }; + + const onTextTrackDataChanged = (data: OnTextTrackDataChangedData) => { console.log(`Subtitles: ${JSON.stringify(data, null, 2)}`); }; - onAspectRatio = (data: OnVideoAspectRatioData) => { + const onAspectRatio = (data: OnVideoAspectRatioData) => { console.log('onAspectRadio called ' + JSON.stringify(data)); - this.setState({ - videoWidth: data.width, - videoHeight: data.height, - }); + setVideoSize({videoWidth: data.width, videoHeight: data.height}); }; - onVideoBuffer = (param: OnBufferData) => { + const onVideoBuffer = (param: OnBufferData) => { console.log('onVideoBuffer'); - this.setState({isLoading: param.isBuffering}); + setIsLoading(param.isBuffering); }; - onReadyForDisplay = () => { + const onReadyForDisplay = () => { console.log('onReadyForDisplay'); - this.setState({isLoading: false}); + setIsLoading(false); }; - onAudioBecomingNoisy = () => { - this.setState({paused: true}); + const onAudioBecomingNoisy = () => { + setPaused(true); }; - onAudioFocusChanged = (event: OnAudioFocusChangedData) => { - this.setState({paused: !event.hasAudioFocus}); - }; - - toast = (visible: boolean, message: string) => { - if (visible) { - if (Platform.OS === 'android') { - ToastAndroid.showWithGravityAndOffset( - message, - ToastAndroid.LONG, - ToastAndroid.BOTTOM, - 25, - 50, - ); - } else { - Alert.alert(message, message); - } - } + const onAudioFocusChanged = (event: OnAudioFocusChangedData) => { + setPaused(!event.hasAudioFocus); }; - onError = (err: OnVideoErrorData) => { + const onError = (err: OnVideoErrorData) => { console.log(JSON.stringify(err)); - this.toast(true, 'error: ' + JSON.stringify(err)); + toast(true, 'error: ' + JSON.stringify(err)); }; - onEnd = () => { - if (!this.state.loop) { - this.channelUp(); + const onEnd = () => { + if (!repeat) { + channelUp(); } }; - onPlaybackRateChange = (data: OnPlaybackRateChangeData) => { + const onPlaybackRateChange = (data: OnPlaybackRateChangeData) => { console.log('onPlaybackRateChange', data); }; - onPlaybackStateChanged = (data: OnPlaybackStateChangedData) => { + const onPlaybackStateChanged = (data: OnPlaybackStateChangedData) => { console.log('onPlaybackStateChanged', data); }; - toggleFullscreen() { - this.setState({fullscreen: !this.state.fullscreen}); - } - toggleControls() { - this.setState({showRNVControls: !this.state.showRNVControls}); - } - - toggleDecoration() { - this.setState({decoration: !this.state.decoration}); - this.video?.setFullScreen(!this.state.decoration); - } - - toggleShowNotificationControls() { - this.setState({ - showNotificationControls: !this.state.showNotificationControls, - }); - } - - goToChannel(channel: number) { - this.setState({ - srcListId: channel, - duration: 0.0, - currentTime: 0.0, - videoWidth: 0, - videoHeight: 0, - isLoading: false, - audioTracks: [], - textTracks: [], - selectedAudioTrack: undefined, - selectedTextTrack: undefined, - selectedVideoTrack: { - type: SelectedVideoTrackType.AUTO, - }, + const goToChannel = (channel: number) => { + setSrcListId(channel); + setDuration(0); + setCurrentTime(0); + setVideoSize({videoWidth: 0, videoHeight: 0}); + setIsLoading(false); + setAudioTracks([]); + setTextTracks([]); + setSelectedAudioTrack(undefined); + setSelectedTextTrack(undefined); + setSelectedVideoTrack({ + type: SelectedVideoTrackType.AUTO, }); - } + }; - channelUp() { + const channelUp = useCallback(() => { console.log('channel up'); - this.goToChannel((this.state.srcListId + 1) % this.srcList.length); - } + goToChannel((srcListId + 1) % srcList.length); + }, [srcListId]); - channelDown() { + const channelDown = useCallback(() => { console.log('channel down'); - this.goToChannel( - (this.state.srcListId + this.srcList.length - 1) % this.srcList.length, - ); - } - - videoSeek(position: number) { - this.setState({isSeeking: true}); - this.video?.seek(position); - } - - renderSeekBar() { - return ( - this.videoSeek(prop)} - isUISeeking={this.state.isSeeking} + goToChannel((srcListId + srcList.length - 1) % srcList.length); + }, [srcListId]); + + return ( + + {(srcList[srcListId] as AdditionalSourceInfo)?.noView ? null : ( + + + )} + - ); - } - - IndicatorLoadingView() { - if (this.state.isLoading) { - return ( - - ); - } else { - return ; - } - } - - renderTopControl() { - return ( - - - {(this.srcList[this.state.srcListId] as AdditionnalSourceInfo) - ?.description || 'local file'} - - - { - this.toggleControls(); - }}> - - {this.state.showRNVControls ? 'Hide controls' : 'Show controls'} - - - - - ); - } - - onRateSelected = (value: MultiValueControlPropType) => { - this.setState({rate: value}); - }; - onVolumeSelected = (value: MultiValueControlPropType) => { - this.setState({volume: value}); - }; - onResizeModeSelected = (value: MultiValueControlPropType) => { - this.setState({resizeMode: value}); - }; - - onSelectedAudioTrackChange = (itemValue: string) => { - console.log('on audio value change ' + itemValue); - if (itemValue === 'none') { - this.setState({ - selectedAudioTrack: SelectedVideoTrackType.DISABLED, - }); - } else { - this.setState({ - selectedAudioTrack: { - type: SelectedVideoTrackType.INDEX, - value: itemValue, - }, - }); - } - }; - - onSelectedTextTrackChange = (itemValue: string) => { - console.log('on value change ' + itemValue); - this.setState({ - selectedTextTrack: { - type: this.textTracksSelectionBy === 'index' ? 'index' : 'language', - value: itemValue, - }, - }); - }; - - onSelectedVideoTrackChange = (itemValue: string) => { - console.log('on value change ' + itemValue); - if (itemValue === undefined || itemValue === 'auto') { - this.setState({ - selectedVideoTrack: { - type: SelectedVideoTrackType.AUTO, - }, - }); - } else { - this.setState({ - selectedVideoTrack: { - type: SelectedVideoTrackType.INDEX, - value: itemValue, - }, - }); - } - }; - - renderOverlay() { - return ( - <> - {this.IndicatorLoadingView()} - - - {this.renderTopControl()} - - - {!this.state.showRNVControls ? ( - <> - - { - this.channelDown(); - }} - text="ChDown" - /> - - - { - this.channelUp(); - }} - text="ChUp" - /> - - - - {Platform.OS === 'android' ? ( - - { - this.popupInfo(); - }} - text="decoderInfo" - /> - { - this.setState({useCache: !this.state.useCache}); - }} - selectedText="enable cache" - unselectedText="disable cache" - /> - - ) : null} - { - this.setState({paused: !this.state.paused}); - }} - selectedText="pause" - unselectedText="playing" - /> - { - this.setState({loop: !this.state.loop}); - }} - selectedText="loop enable" - unselectedText="loop disable" - /> - { - this.toggleFullscreen(); - }} - text="fullscreen" - /> - { - this.toggleDecoration(); - }} - text="decoration" - /> - { - this.setState({ - poster: this.state.poster ? undefined : this.samplePoster, - }); - }} - selectedText="poster" - unselectedText="no poster" - /> - { - this.toggleShowNotificationControls(); - }} - selectedText="hide notification controls" - unselectedText="show notification controls" - /> - - - {/* shall be replaced by slider */} - - {/* shall be replaced by slider */} - - - { - this.setState({muted: !this.state.muted}); - }} - text="muted" - /> - {Platform.OS === 'ios' ? ( - { - this.video - ?.save({}) - ?.then(response => { - console.log('Downloaded URI', response); - }) - .catch(error => { - console.log('error during save ', error); - }); - }} - text="save" - /> - ) : null} - - {this.renderSeekBar()} - - - - - - - - ) : null} - - ); - } - - renderVideoView() { - const viewStyle = this.state.fullscreen - ? styles.fullScreen - : styles.halfScreen; - - const currentSrc = this.srcList[this.state.srcListId]; - const additionnal = currentSrc as AdditionnalSourceInfo; - - return ( - - - ); - } - - render() { - return ( - - {(this.srcList[this.state.srcListId] as AdditionnalSourceInfo)?.noView - ? null - : this.renderVideoView()} - {this.renderOverlay()} - - ); - } -} + + ); +}; export default VideoPlayer; diff --git a/examples/basic/src/VideoPlayer.windows.tsx b/examples/basic/src/VideoPlayer.windows.tsx index f39f177b7f..5c66eebae2 100644 --- a/examples/basic/src/VideoPlayer.windows.tsx +++ b/examples/basic/src/VideoPlayer.windows.tsx @@ -108,7 +108,7 @@ class VideoPlayer extends Component { this.setState({paused: !this.state.paused}); }}>