Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/build-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ jobs:
-scheme BareExample \
-sdk iphonesimulator \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 14' \
-destination 'platform=iOS Simulator,name=iPhone 16' \
build \
CODE_SIGNING_ALLOWED=NO | xcpretty"

Expand Down Expand Up @@ -142,7 +142,7 @@ jobs:
-scheme BareExample \
-sdk iphonesimulator \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 14' \
-destination 'platform=iOS Simulator,name=iPhone 16' \
build \
CODE_SIGNING_ALLOWED=NO | xcpretty"

Expand Down Expand Up @@ -209,6 +209,6 @@ jobs:
-scheme BareExample \
-sdk iphonesimulator \
-configuration Debug \
-destination 'platform=iOS Simulator,name=iPhone 14' \
-destination 'platform=iOS Simulator,name=iPhone 16' \
build \
CODE_SIGNING_ALLOWED=NO | xcpretty"
36 changes: 36 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,41 @@


## [6.19.1](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.19.0...v6.19.1) (2026-03-15)


### Bug Fixes

* **ios:** IMA ad container resizing on orientation change ([#4771](https://github.com/TheWidlarzGroup/react-native-video/issues/4771)) ([fc936c4](https://github.com/TheWidlarzGroup/react-native-video/commit/fc936c49ef3c2734173442042b7d5038aeaef301))
* RCTVideoManager crash in bridgeless mode RN0.84 ([#4855](https://github.com/TheWidlarzGroup/react-native-video/issues/4855)) ([92b0a0e](https://github.com/TheWidlarzGroup/react-native-video/commit/92b0a0e416c7f313120a811cd2dc972f87b1c82f))

# [6.19.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.18.0...v6.19.0) (2026-01-19)


### Bug Fixes

* **android:** correct videoTrack type definitions to match Android implementation ([#4778](https://github.com/TheWidlarzGroup/react-native-video/issues/4778)) ([commit](https://github.com/TheWidlarzGroup/react-native-video/commit/f38717778515b06c462fe75dcd94d2cce5ba3f95))


### Features

* **BREAKING CHANGE:** add DAI support ([#4816](https://github.com/TheWidlarzGroup/react-native-video/issues/4816)) ([commit](https://github.com/TheWidlarzGroup/react-native-video/commit/88ac1ae1dcdc907415f806bd64bd3d0a92ccd7d1))

# [6.18.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.17.0...v6.18.0) (2025-11-18)


### Bug Fixes

* **android:** prevent duplicate `onVideoEnd` callback on prop changes ([#4762](https://github.com/TheWidlarzGroup/react-native-video/issues/4762)) ([05cd597](https://github.com/TheWidlarzGroup/react-native-video/commit/05cd5972c21ebcacf3cd5952e92f121a84b5c9a9))
* **ci:** update ios device for builds ([#4757](https://github.com/TheWidlarzGroup/react-native-video/issues/4757)) ([a9f7524](https://github.com/TheWidlarzGroup/react-native-video/commit/a9f752435f3d94abfdb37ef5dc9c444038e3ad6a))
* entering PiP mode when controls are true ([#4776](https://github.com/TheWidlarzGroup/react-native-video/issues/4776)) ([ba65ab1](https://github.com/TheWidlarzGroup/react-native-video/commit/ba65ab123321713e537fc7ccb1ac3ed5676f1677))
* **iOS:** use top-most presented view controller for fullscreen presentation on iOS ([#4753](https://github.com/TheWidlarzGroup/react-native-video/issues/4753)) ([5d75b48](https://github.com/TheWidlarzGroup/react-native-video/commit/5d75b482952a9cd3e5f59237e302137857739d4e))
* prevent `audiovisualBackgroundPlaybackPolicy` crash ([#4763](https://github.com/TheWidlarzGroup/react-native-video/issues/4763)) ([fbb260e](https://github.com/TheWidlarzGroup/react-native-video/commit/fbb260e9164194a55d2b26404aea000e924e2f04))


### Features

* **ios:** add PublicAudioSessionManager for audio session management ([#4747](https://github.com/TheWidlarzGroup/react-native-video/issues/4747)) ([f2afd16](https://github.com/TheWidlarzGroup/react-native-video/commit/f2afd16d0bc7fc72e0b4d8400d74342244158674))

# [6.17.0](https://github.com/TheWidlarzGroup/react-native-video/compare/v6.16.1...v6.17.0) (2025-10-06)


Expand Down
46 changes: 40 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ export default () => (

## 🧩 Plugins

<a href="https://www.thewidlarzgroup.com/offline-video-sdk?utm_source=rnv&utm_medium=readme&utm_id=banner">
<img src="./docs/assets/baners/sdk-banner.png" alt="Offline SDK Preview" width="40%" align="right" />
<a href="https://sdk.thewidlarzgroup.com/offline-video?utm_source=rnv&utm_medium=readme&utm_id=banner">
<img src="./docs/assets/baners/offline-sdk-banner.png" alt="Offline SDK Preview" width="40%" align="right" />
</a>

### 1 · 📥 Offline SDK
Expand All @@ -74,7 +74,7 @@ export default () => (

If you're building a video-first app and need to **download HLS streams for offline playback**, you're in the right place.

#### 👉 [Check Offline Video SDK for React Native](https://www.thewidlarzgroup.com/offline-video-sdk?utm_source=rnv&utm_medium=readme&utm_id=check-offline-video-sdk)
#### 👉 [Check Offline Video SDK for React Native](https://sdk.thewidlarzgroup.com/offline-video?utm_source=rnv&utm_medium=readme&utm_id=check-offline-video-sdk)

This SDK supports:
- 🎞 Offline HLS playback
Expand All @@ -93,12 +93,45 @@ This SDK supports:

👉 **[Start Free Trial on the SDK Platform →](https://sdk.thewidlarzgroup.com/signup?utm_source=rnv&utm_medium=readme&utm_id=start-trial-offline-video-sdk)**

---
<a href="https://sdk.thewidlarzgroup.com/background-uploader?utm_source=rnv&utm_medium=readme&utm_id=banner">
<img src="./docs/assets/baners/bgupload-sdk-banner.png" alt="Offline SDK Preview" width="40%" align="right" />
</a>

### 2 · ⚡ Background Upload SDK

#### Need Reliable Video Uploads in React Native?

If you're building a video-first app and need to **upload large video files reliably in the background**, you're in the right place.

#### 👉 [Check Background Upload SDK for React Native](https://sdk.thewidlarzgroup.com/background-uploader?utm_source=rnv&utm_medium=readme&utm_id=check-background-upload-sdk)

This SDK supports:
- 📤 Background video uploads
- 🔄 Automatic retry mechanisms
- 📊 Upload progress tracking
- 🛡️ Resume interrupted uploads
- 📱 Works when app is backgrounded
- 🔐 Secure upload handling

---

#### 🚀 Perfect for Apps Uploading Large Media

Whether you're building social media apps, content platforms, or enterprise solutions, our Background Upload SDK ensures your users can upload videos seamlessly without interruption.

#### 📞 Ready to Get Started?

Contact us to learn more about integrating background video uploads into your React Native application.

👉 **Contact us at [hi@thewidlarzgroup.com](mailto:hi@thewidlarzgroup.com)**

---

### 2 · 🧪 Architecture
### 3 · 🧪 Architecture

Write your own plugins to extend library logic, attach analytics or add custom workflows - **without forking** the core SDK.
→ [Plugin documentation](https://docs.thewidlarzgroup.com/react-native-video/other/plugin?utm_source=rnv&utm_medium=readme&utm_id=plugin-text)
→ [Plugin documentation](https://docs.thewidlarzgroup.com/react-native-video/docs/v6/other/plugin?utm_source=rnv&utm_medium=readme&utm_id=plugin-text)

---

Expand All @@ -108,7 +141,8 @@ Write your own plugins to extend library logic, attach analytics or add custom w
|----------|-------------|
| [**Professional Support Packages**](https://www.thewidlarzgroup.com/issue-boost?utm_source=rnv&utm_medium=readme&utm_campaign=professional-support-packages#Contact) | Priority bug-fixes, guaranteed SLAs, [roadmap influence](https://github.com/orgs/TheWidlarzGroup/projects/6) |
| [**Issue Booster**](https://www.thewidlarzgroup.com/issue-boost?utm_source=rnv&utm_medium=readme) | Fast-track urgent fixes with a pay‑per‑issue model |
| [**Offline Video SDK**](https://www.thewidlarzgroup.com/offline-video-sdk/?utm_source=rnv&utm_medium=readme&utm_campaign=downloading&utm_id=offline-video-sdk-link) | Plug‑and‑play secure download solution for iOS & Android |
| [**Offline Video SDK**](https://sdk.thewidlarzgroup.com/offline-video?utm_source=rnv&utm_medium=readme&utm_campaign=downloading&utm_id=offline-video-sdk-link) | Plug‑and‑play secure download solution for iOS & Android |
| [**Background Upload SDK**](https://sdk.thewidlarzgroup.com/background-uploader?utm_source=rnv&utm_medium=readme&utm_campaign=uploading&utm_id=background-upload-sdk-link) | Reliable background upload solution for iOS & Android |
| [**Integration Support**](https://www.thewidlarzgroup.com/?utm_source=rnv&utm_medium=readme&utm_campaign=integration-support#Contact) | Hands‑on help integrating video, DRM & offline into your app |
| [**Free DRM Token Generator**](https://www.thewidlarzgroup.com/services/free-drm-token-generator-for-video?utm_source=rnv&utm_medium=readme&utm_id=free-drm) | Generate Widevine / FairPlay tokens for testing |
| [**Ready Boilerplates**](https://www.thewidlarzgroup.com/showcases?utm_source=rnv&utm_medium=readme) | Ready-to-use apps with offline HLS/DASH DRM, video frame scrubbing, TikTok-style video feed, background uploads, Skia-based frame processor (R&D phase), and more |
Expand Down
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ RNVideo_targetSdkVersion=35
RNVideo_compileSdkVersion=35
RNVideo_ndkversion=27.1.12297006
RNVideo_buildToolsVersion=35.0.0
RNVideo_media3Version=1.4.1
RNVideo_media3Version=1.8.0
RNVideo_useExoplayerIMA=false
RNVideo_useExoplayerRtsp=false
RNVideo_useExoplayerSmoothStreaming=true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package androidx.media3.exoplayer.ima;

import android.content.Context;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.media3.exoplayer.drm.DrmSessionManagerProvider;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.exoplayer.upstream.LoadErrorHandlingPolicy;

public class ImaServerSideAdInsertionMediaSource {

public static class AdsLoader {
public void setPlayer(@Nullable Player player) {
}

public void release() {
}

public static class Builder {
public Builder(Context context, View playerView) {
}

public Builder setAdEventListener(Object listener) {
return this;
}

public Builder setAdErrorListener(Object listener) {
return this;
}

public AdsLoader build() {
return new AdsLoader();
}
}
}

public static class Factory implements MediaSource.Factory {
public Factory(AdsLoader adsLoader, MediaSource.Factory mediaSourceFactory) {
}

@Override
public MediaSource.Factory setDrmSessionManagerProvider(DrmSessionManagerProvider drmSessionManagerProvider) {
return this;
}

@Override
public MediaSource.Factory setLoadErrorHandlingPolicy(LoadErrorHandlingPolicy loadErrorHandlingPolicy) {
return this;
}

@Override
public int[] getSupportedTypes() {
return new int[0];
}

@Override
public MediaSource createMediaSource(MediaItem mediaItem) {
return null;
}
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package androidx.media3.exoplayer.ima;

import android.net.Uri;

public class ImaServerSideAdInsertionUriBuilder {
public ImaServerSideAdInsertionUriBuilder setAssetKey(String assetKey) {
return this;
}

public ImaServerSideAdInsertionUriBuilder setContentSourceId(String contentSourceId) {
return this;
}

public ImaServerSideAdInsertionUriBuilder setVideoId(String videoId) {
return this;
}

public ImaServerSideAdInsertionUriBuilder setFormat(int format) {
return this;
}

public Uri build() {
return Uri.EMPTY;
}
}

72 changes: 66 additions & 6 deletions android/src/main/java/com/brentvatne/common/api/AdsProps.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,98 @@ import android.net.Uri
import android.text.TextUtils
import com.brentvatne.common.toolbox.ReactBridgeUtils
import com.facebook.react.bridge.ReadableMap
import java.util.Objects

class AdsProps {
var type: String? = null
var streamType: String? = null
var adTagUrl: Uri? = null
var adLanguage: String? = null
var contentSourceId: String? = null
var videoId: String? = null
var assetKey: String? = null
var format: String? = null
var adTagParameters: Map<String, String>? = null
var fallbackUri: String? = null

fun isCSAI(): Boolean = type == "csai" && adTagUrl != null
fun isDAI(): Boolean = type == "ssai"
fun isDAIVod(): Boolean = type == "ssai" && streamType == "vod"
fun isDAILive(): Boolean = type == "ssai" && streamType == "live"

/** return true if this and src are equals */
override fun equals(other: Any?): Boolean {
if (other == null || other !is AdsProps) return false
return (
adTagUrl == other.adTagUrl &&
adLanguage == other.adLanguage
type == other.type &&
streamType == other.streamType &&
adTagUrl == other.adTagUrl &&
adLanguage == other.adLanguage &&
contentSourceId == other.contentSourceId &&
videoId == other.videoId &&
assetKey == other.assetKey &&
format == other.format &&
adTagParameters == other.adTagParameters &&
fallbackUri == other.fallbackUri
)
}

override fun hashCode(): Int =
Objects.hash(
type, streamType, adTagUrl, adLanguage, contentSourceId, videoId, assetKey, format, adTagParameters, fallbackUri
)

companion object {
private const val PROP_TYPE = "type"
private const val PROP_STREAM_TYPE = "streamType"
private const val PROP_AD_TAG_URL = "adTagUrl"
private const val PROP_AD_LANGUAGE = "adLanguage"
private const val PROP_CONTENT_SOURCE_ID = "contentSourceId"
private const val PROP_VIDEO_ID = "videoId"
private const val PROP_ASSET_KEY = "assetKey"
private const val PROP_FORMAT = "format"
private const val PROP_AD_TAG_PARAMETERS = "adTagParameters"
private const val PROP_FALLBACK_URI = "fallbackUri"

@JvmStatic
fun parse(src: ReadableMap?): AdsProps {
val adsProps = AdsProps()
if (src != null) {
adsProps.type = ReactBridgeUtils.safeGetString(src, PROP_TYPE)
adsProps.streamType = ReactBridgeUtils.safeGetString(src, PROP_STREAM_TYPE)

val uriString = ReactBridgeUtils.safeGetString(src, PROP_AD_TAG_URL)
if (TextUtils.isEmpty(uriString)) {
adsProps.adTagUrl = null
} else {
if (!TextUtils.isEmpty(uriString)) {
adsProps.adTagUrl = Uri.parse(uriString)
}

val languageString = ReactBridgeUtils.safeGetString(src, PROP_AD_LANGUAGE)
if (!TextUtils.isEmpty(languageString)) {
adsProps.adLanguage = languageString
}

adsProps.contentSourceId = ReactBridgeUtils.safeGetString(src, PROP_CONTENT_SOURCE_ID)
adsProps.videoId = ReactBridgeUtils.safeGetString(src, PROP_VIDEO_ID)
adsProps.assetKey = ReactBridgeUtils.safeGetString(src, PROP_ASSET_KEY)
adsProps.format = ReactBridgeUtils.safeGetString(src, PROP_FORMAT)
adsProps.fallbackUri = ReactBridgeUtils.safeGetString(src, PROP_FALLBACK_URI)

if (src.hasKey(PROP_AD_TAG_PARAMETERS)) {
val adTagParamsMap = src.getMap(PROP_AD_TAG_PARAMETERS)
if (adTagParamsMap != null) {
val params = mutableMapOf<String, String>()
val iterator = adTagParamsMap.keySetIterator()
while (iterator.hasNextKey()) {
val key = iterator.nextKey()
val value = adTagParamsMap.getString(key)
if (value != null) {
params[key] = value
}
}
if (params.isNotEmpty()) {
adsProps.adTagParameters = params
}
}
}
}
return adsProps
}
Expand Down
Loading