Merge branch 'master' of https://github.com/react-native-video/react-native-video into feat/add_new_events_on_tracks_changed

# Conflicts:
#	API.md
#	android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
#	android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java
#	examples/basic/yarn.lock
This commit is contained in:
olivier bouillet 2023-01-02 22:59:10 +01:00
commit 2b6654b458
86 changed files with 6030 additions and 5373 deletions

263
API.md
View File

@ -263,82 +263,85 @@ var styles = StyleSheet.create({
``` ```
### Configurable props ### Configurable props
| Name |Plateforms Support | | Name | Platforms Support |
|--|--| |-------------------------------------------------------------------------------------|---------------------------|
|[allowsExternalPlayback](#allowsexternalplayback) |iOS | | [adTagUrl](#adTagUrl) | Android, iOS |
|[audioOnly](#audioonly)|All | | [allowsExternalPlayback](#allowsexternalplayback) | iOS |
|[automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling) | iOS|\ | [audioOnly](#audioonly) | All |
|[backBufferDurationMs](#backBufferDurationMs)| Android | | [automaticallyWaitsToMinimizeStalling](#automaticallyWaitsToMinimizeStalling) | iOS |
|[bufferConfig](#bufferconfig)|Android| | [backBufferDurationMs](#backBufferDurationMs) | Android |
|[contentStartTime](#contentStartTime)| Android | | [bufferConfig](#bufferconfig) | Android |
|[controls](#controls)|Android, iOS| | [contentStartTime](#contentStartTime) | Android |
|[currentPlaybackTime](#currentPlaybackTime)|Android| | [controls](#controls) | Android, iOS |
|[disableFocus](#disableFocus)|Android, iOS| | [currentPlaybackTime](#currentPlaybackTime) | Android |
|[disableDisconnectError](#disableDisconnectError)|Android| | [disableFocus](#disableFocus) | Android, iOS |
|[filter](#filter)|iOS| | [disableDisconnectError](#disableDisconnectError) | Android |
|[filterEnabled](#filterEnabled)|iOS| | [filter](#filter) | iOS |
|[focusable](#focusable)|Android| | [filterEnabled](#filterEnabled) | iOS |
|[fullscreen](#fullscreen)|iOS| | [focusable](#focusable) | Android |
|[fullscreenAutorotate](#fullscreenautorotate)|iOS| | [fullscreen](#fullscreen) | iOS |
|[fullscreenOrientation](#fullscreenorientation)|iOS| | [fullscreenAutorotate](#fullscreenautorotate) | iOS |
|[headers](#headers)|Android| | [fullscreenOrientation](#fullscreenorientation) | iOS |
|[hideShutterView](#hideshutterview)|Android| | [headers](#headers) | Android |
|[ignoreSilentSwitch](#ignoresilentswitch)|iOS| | [hideShutterView](#hideshutterview) | Android |
|[maxBitRate](#maxbitrate)|Android, iOS| | [ignoreSilentSwitch](#ignoresilentswitch) | iOS |
|[minLoadRetryCount](#minLoadRetryCount)|Android| | [maxBitRate](#maxbitrate) | Android, iOS |
|[mixWithOthers](#mixWithOthers)|iOS| | [minLoadRetryCount](#minLoadRetryCount) | Android |
|[muted](#muted)|All| | [mixWithOthers](#mixWithOthers) | iOS |
|[paused](#paused)|All| | [muted](#muted) | All |
|[pictureInPicture](#pictureinpicture)|iOS| | [paused](#paused) | All |
|[playInBackground](#playinbackground)|Android, iOS| | [pictureInPicture](#pictureinpicture) | iOS |
|[playWhenInactive](#playwheninactive)|iOS| | [playInBackground](#playinbackground) | Android, iOS |
|[poster](#poster)|All| | [playWhenInactive](#playwheninactive) | iOS |
|[posterResizeMode](#posterresizemode)|All| | [poster](#poster) | All |
|[preferredForwardBufferDuration](#preferredForwardBufferDuration)|iOS| | [posterResizeMode](#posterresizemode) | All |
|[preventsDisplaySleepDuringVideoPlayback](#preventsDisplaySleepDuringVideoPlayback)|iOS, Android| | [preferredForwardBufferDuration](#preferredForwardBufferDuration) | iOS |
|[progressUpdateInterval](#progressupdateinterval)|All| | [preventsDisplaySleepDuringVideoPlayback](#preventsDisplaySleepDuringVideoPlayback) | iOS, Android |
|[rate](#rate)|All| | [progressUpdateInterval](#progressupdateinterval) | All |
|[repeat](#repeat)|All| | [rate](#rate) | All |
|[reportBandwidth](#reportbandwidth)|Android| | [repeat](#repeat) | All |
|[resizeMode](#resizemode)|Android, iOS, Windows UWP| | [reportBandwidth](#reportbandwidth) | Android |
|[selectedAudioTrack](#selectedaudiotrack)|Android, iOS| | [resizeMode](#resizemode) | Android, iOS, Windows UWP |
|[selectedTextTrack](#selectedtexttrack)|Android, iOS| | [selectedAudioTrack](#selectedaudiotrack) | Android, iOS |
|[selectedVideoTrack](#selectedvideotrack)|Android| | [selectedTextTrack](#selectedtexttrack) | Android, iOS |
|[source](#source)|All| | [selectedVideoTrack](#selectedvideotrack) | Android |
|[subtitleStyle](#subtitleStyle)|Android| | [source](#source) | All |
|[textTracks](#texttracks)|Android, iOS| | [subtitleStyle](#subtitleStyle) | Android |
|[trackId](#trackId)|Android| | [textTracks](#texttracks) | Android, iOS |
|[useTextureView](#usetextureview)|Android| | [trackId](#trackId) | Android |
|[useSecureView](#useSecureView)|Android| | [useTextureView](#usetextureview) | Android |
|[volume](#volume)|All| | [useSecureView](#useSecureView) | Android |
|[localSourceEncryptionKeyScheme](#localSourceEncryptionKeyScheme)|All| | [volume](#volume) | All |
| [localSourceEncryptionKeyScheme](#localSourceEncryptionKeyScheme) | All |
### Event props ### Event props
| Name |Plateforms Support |
|--|--|
|[onAudioBecomingNoisy](#onaudiobecomingnoisy)|Android, iOS|
|[onAudioTracks](#onAudioTracks)|Android|
|[onBandwidthUpdate](#onbandwidthupdate)|Android|
|[onBuffer](#onbuffer)|Android, iOS|
|[onEnd](#onend)|All|
|[onExternalPlaybackChange](#onexternalplaybackchange)|iOS|
|[onFullscreenPlayerWillPresent](#onfullscreenplayerwillpresent)|Android, iOS|
|[onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent)|Android, iOS|
|[onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss)|Android, iOS|
|[onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss)|Android, iOS|
|[onLoad](#onload)|All|
|[onLoadStart](#onloadstart)|All|
|[onReadyForDisplay](#onreadyfordisplay)|Android, iOS, Web|
|[onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged)|iOS|
|[onPlaybackRateChange](#onplaybackratechange)|All|
|[onProgress](#onprogress)|All|
|[onSeek](#onseek)|Android, iOS, Windows UWP|
|[onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop)|iOS|
|[onTimedMetadata](#ontimedmetadata)|Android, iOS|
|[onTextTracks](#onTextTracks)|Android|
|[onVideoTracks](#onVideoTracks)|Android|
| Name | Platforms Support |
|-------------------------------------------------------------------------------------------------|---------------------------|
| [onAudioBecomingNoisy](#onaudiobecomingnoisy) | Android, iOS |
| [onAudioTracks](#onAudioTracks) |Android |
| [onBandwidthUpdate](#onbandwidthupdate) | Android |
| [onBuffer](#onbuffer) | Android, iOS |
| [onEnd](#onend) | All |
| [onError](#onerror) | Android, iOS |
| [onExternalPlaybackChange](#onexternalplaybackchange) | iOS |
| [onFullscreenPlayerWillPresent](#onfullscreenplayerwillpresent) | Android, iOS |
| [onFullscreenPlayerDidPresent](#onfullscreenplayerdidpresent) | Android, iOS |
| [onFullscreenPlayerWillDismiss](#onfullscreenplayerwilldismiss) | Android, iOS |
| [onFullscreenPlayerDidDismiss](#onfullscreenplayerdiddismiss) | Android, iOS |
| [onLoad](#onload) | All |
| [onLoadStart](#onloadstart) | All |
| [onPictureInPictureStatusChanged](#onpictureinpicturestatuschanged) | iOS |
| [onPlaybackRateChange](#onplaybackratechange) | All |
| [onProgress](#onprogress) | All |
| [onReadyForDisplay](#onreadyfordisplay) | Android, iOS, Web |
| [onReceiveAdEvent](#onReceiveAdEvent) | Android, iOS |
| [onRestoreUserInterfaceForPictureInPictureStop](#onrestoreuserinterfaceforpictureinpicturestop) | iOS |
| [onSeek](#onseek) | Android, iOS, Windows UWP |
| [onTimedMetadata](#ontimedmetadata) | Android, iOS |
| [onTextTracks](#onTextTracks) |Android |
| [onVideoTracks](#onVideoTracks) |Android |
### Methods ### Methods
| Name |Plateforms Support | | Name |Plateforms Support |
@ -359,6 +362,16 @@ var styles = StyleSheet.create({
### Configurable props ### Configurable props
#### adTagUrl
Sets the VAST uri to play AVOD ads.
Example:
```
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="
```
Platforms: Android, iOS
#### allowsExternalPlayback #### allowsExternalPlayback
Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI. Indicates whether the player allows switching to external playback mode such as AirPlay or HDMI.
* **true (default)** - allow switching to external playback mode * **true (default)** - allow switching to external playback mode
@ -1045,6 +1058,17 @@ Payload: none
Platforms: all Platforms: all
#### onError
Callback function that is called when the player experiences a playback error.
Payload:
Property | Type | Description
--- | --- | ---
error | object | Object containing properties with information about the error
Platforms: all
#### onExternalPlaybackChange #### onExternalPlaybackChange
Callback function that is called when external playback mode for current playing video has changed. Mostly useful when connecting/disconnecting to Apple TV it's called on connection/disconnection. Callback function that is called when external playback mode for current playing video has changed. Mostly useful when connecting/disconnecting to Apple TV it's called on connection/disconnection.
@ -1180,16 +1204,6 @@ Example:
Platforms: Android Platforms: Android
#### onReadyForDisplay
Callback function that is called when the first video frame is ready for display. This is when the poster is removed.
Payload: none
* iOS: [readyForDisplay](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-readyfordisplay?language=objc)
* Android [STATE_READY](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY)
Platforms: Android, iOS, Web
#### onPictureInPictureStatusChanged #### onPictureInPictureStatusChanged
Callback function that is called when picture in picture becomes active or inactive. Callback function that is called when picture in picture becomes active or inactive.
@ -1222,7 +1236,6 @@ Example:
Platforms: all Platforms: all
#### onProgress #### onProgress
Callback function that is called every progressUpdateInterval milliseconds with info about which position the media is currently playing. Callback function that is called every progressUpdateInterval milliseconds with info about which position the media is currently playing.
@ -1243,6 +1256,83 @@ Example:
Platforms: all Platforms: all
#### onReadyForDisplay
Callback function that is called when the first video frame is ready for display. This is when the poster is removed.
Payload: none
* iOS: [readyForDisplay](https://developer.apple.com/documentation/avkit/avplayerviewcontroller/1615830-readyfordisplay?language=objc)
* Android [STATE_READY](https://exoplayer.dev/doc/reference/com/google/android/exoplayer2/Player.html#STATE_READY)
Platforms: Android, iOS, Web
#### onReceiveAdEvent
Callback function that is called when an AdEvent is received from the IMA's SDK.
Enum `AdEvent` possible values for [Android](https://developers.google.com/interactive-media-ads/docs/sdks/html5/client-side/reference/js/google.ima.AdEvent) and [iOS](https://developers.google.com/interactive-media-ads/docs/sdks/ios/client-side/reference/Enums/IMAAdEventType):
| Event | Platform | Description |
|----------------------------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `AD_BREAK_ENDED` | iOS | Fired the first time each ad break ends. Applications must reenable seeking when this occurs (only used for dynamic ad insertion). |
| `AD_BREAK_READY` | Android, iOS | Fires when an ad rule or a VMAP ad break would have played if autoPlayAdBreaks is false. |
| `AD_BREAK_STARTED` | iOS | Fired first time each ad break begins playback. If an ad break is watched subsequent times this will not be fired. Applications must disable seeking when this occurs (only used for dynamic ad insertion). |
| `AD_BUFFERING` | Android | Fires when the ad has stalled playback to buffer. |
| `AD_CAN_PLAY` | Android | Fires when the ad is ready to play without buffering, either at the beginning of the ad or after buffering completes. |
| `AD_METADATA` | Android | Fires when an ads list is loaded. |
| `AD_PERIOD_ENDED` | iOS | Fired every time the stream switches from advertising or slate to content. This will be fired even when an ad is played a second time or when seeking into an ad (only used for dynamic ad insertion). |
| `AD_PERIOD_STARTED` | iOS | Fired every time the stream switches from content to advertising or slate. This will be fired even when an ad is played a second time or when seeking into an ad (only used for dynamic ad insertion). |
| `AD_PROGRESS` | Android | Fires when the ad's current time value changes. Calling getAdData() on this event will return an AdProgressData object. |
| `ALL_ADS_COMPLETED` | Android, iOS | Fires when the ads manager is done playing all the valid ads in the ads response, or when the response doesn't return any valid ads. |
| `CLICK` | Android, iOS | Fires when the ad is clicked. |
| `COMPLETE` | Android, iOS | Fires when the ad completes playing. |
| `CONTENT_PAUSE_REQUESTED` | Android | Fires when content should be paused. This usually happens right before an ad is about to cover the content. |
| `CONTENT_RESUME_REQUESTED` | Android | Fires when content should be resumed. This usually happens when an ad finishes or collapses. |
| `CUEPOINTS_CHANGED` | iOS | Cuepoints changed for VOD stream (only used for dynamic ad insertion). |
| `DURATION_CHANGE` | Android | Fires when the ad's duration changes. |
| `FIRST_QUARTILE` | Android, iOS | Fires when the ad playhead crosses first quartile. |
| `IMPRESSION` | Android | Fires when the impression URL has been pinged. |
| `INTERACTION` | Android | Fires when an ad triggers the interaction callback. Ad interactions contain an interaction ID string in the ad data. |
| `LINEAR_CHANGED` | Android | Fires when the displayed ad changes from linear to nonlinear, or the reverse. |
| `LOADED` | Android, iOS | Fires when ad data is available. |
| `LOG` | Android, iOS | Fires when a non-fatal error is encountered. The user need not take any action since the SDK will continue with the same or next ad playback depending on the error situation. |
| `MIDPOINT` | Android, iOS | Fires when the ad playhead crosses midpoint. |
| `PAUSED` | Android, iOS | Fires when the ad is paused. |
| `RESUMED` | Android, iOS | Fires when the ad is resumed. |
| `SKIPPABLE_STATE_CHANGED` | Android | Fires when the displayed ads skippable state is changed. |
| `SKIPPED` | Android, iOS | Fires when the ad is skipped by the user. |
| `STARTED` | Android, iOS | Fires when the ad starts playing. |
| `STREAM_LOADED` | iOS | Stream request has loaded (only used for dynamic ad insertion). |
| `TAPPED` | iOS | Fires when the ad is tapped. |
| `THIRD_QUARTILE` | Android, iOS | Fires when the ad playhead crosses third quartile. |
| `UNKNOWN` | iOS | An unknown event has fired |
| `USER_CLOSE` | Android | Fires when the ad is closed by the user. |
| `VIDEO_CLICKED` | Android | Fires when the non-clickthrough portion of a video ad is clicked. |
| `VIDEO_ICON_CLICKED` | Android | Fires when a user clicks a video icon. |
| `VOLUME_CHANGED` | Android | Fires when the ad volume has changed. |
| `VOLUME_MUTED` | Android | Fires when the ad volume has been muted. |
Payload:
| Property | Type | Description |
|----------|---------|-----------------------|
| event | AdEvent | The ad event received |
Example:
```
{
"event": "LOADED"
}
```
Platforms: Android, iOS
#### onRestoreUserInterfaceForPictureInPictureStop
Callback function that corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside of this function when done restoring the user interface.
Payload: none
Platforms: iOS
#### onSeek #### onSeek
Callback function that is called when a seek completes. Callback function that is called when a seek completes.
@ -1266,13 +1356,6 @@ Both the currentTime & seekTime are reported because the video player may not se
Platforms: Android, iOS, Windows UWP Platforms: Android, iOS, Windows UWP
#### onRestoreUserInterfaceForPictureInPictureStop
Callback function that corresponds to Apple's [`restoreUserInterfaceForPictureInPictureStopWithCompletionHandler`](https://developer.apple.com/documentation/avkit/avpictureinpicturecontrollerdelegate/1614703-pictureinpicturecontroller?language=objc). Call `restoreUserInterfaceForPictureInPictureStopCompleted` inside of this function when done restoring the user interface.
Payload: none
Platforms: iOS
#### onTimedMetadata #### onTimedMetadata
Callback function that is called when timed metadata becomes available Callback function that is called when timed metadata becomes available

View File

@ -1,8 +1,15 @@
## Changelog ## Changelog
### Version 6.0.0-alpha.5
- Android: add new events on tracks changed to be notified of audio/text/video Tracks update during playback [2806](https://github.com/react-native-video/react-native-video/pull/2806)
- iOS: app crashes on call to presentFullScreenPlayer [#2808](https://github.com/react-native-video/react-native-video/pull/2971)
- Android: Fix publicated progress handler causing duplicated progress event [#2972](https://github.com/react-native-video/react-native-video/pull/2972)
- Feature: Add VAST support for AVOD [#2923](https://github.com/react-native-video/react-native-video/pull/2923)
- Sample: Upgrade react-native version of basic sample [#2960](https://github.com/react-native-video/react-native-video/pull/2960)
### Version 6.0.0-alpha.4 ### Version 6.0.0-alpha.4
- Exoplayer: add new events on tracks changed to be notified of audio/text/video Tracks update during playback [2806](https://github.com/react-native-video/react-native-video/pull/2806)
- ensure src is always provided to native player even if it is invalid [#2857](https://github.com/react-native-video/react-native-video/pull/2857) - ensure src is always provided to native player even if it is invalid [#2857](https://github.com/react-native-video/react-native-video/pull/2857)
- Sample: Add react-native-video controls support [#2852](https://github.com/react-native-video/react-native-video/pull/2852) - Sample: Add react-native-video controls support [#2852](https://github.com/react-native-video/react-native-video/pull/2852)
- Android: Switch Google's maven repository to default `google()` [#2860](https://github.com/react-native-video/react-native-video/pull/2860) - Android: Switch Google's maven repository to default `google()` [#2860](https://github.com/react-native-video/react-native-video/pull/2860)
@ -10,6 +17,9 @@
- Android: fix linter warning [#2891] (https://github.com/react-native-video/react-native-video/pull/2891) - Android: fix linter warning [#2891] (https://github.com/react-native-video/react-native-video/pull/2891)
- Fix iOS RCTSwiftLog naming collision [#2868](https://github.com/react-native-video/react-native-video/issues/2868) - Fix iOS RCTSwiftLog naming collision [#2868](https://github.com/react-native-video/react-native-video/issues/2868)
- Added "homepage" to package.json [#2882](https://github.com/react-native-video/react-native-video/pull/2882) - Added "homepage" to package.json [#2882](https://github.com/react-native-video/react-native-video/pull/2882)
- Fix regression when fullscreen prop is used combined with controls [#2911](https://github.com/react-native-video/react-native-video/pull/2911)
- Fix: memory leak issue on iOS [#2907](https://github.com/react-native-video/react-native-video/pull/2907)
- Fix setting text tracks before player is initialized on iOS [#2935](https://github.com/react-native-video/react-native-video/pull/2935)
### Version 6.0.0-alpha.3 ### Version 6.0.0-alpha.3

View File

@ -279,6 +279,13 @@ export default class Video extends Component {
} }
} }
} }
_onReceiveAdEvent = (event) => {
if (this.props.onReceiveAdEvent) {
this.props.onReceiveAdEvent(event.nativeEvent);
}
};
getViewManagerConfig = viewManagerName => { getViewManagerConfig = viewManagerName => {
if (!UIManager.getViewManagerConfig) { if (!UIManager.getViewManagerConfig) {
return UIManager[viewManagerName]; return UIManager[viewManagerName];
@ -364,6 +371,7 @@ export default class Video extends Component {
onGetLicense: nativeProps.drm && nativeProps.drm.getLicense && this._onGetLicense, onGetLicense: nativeProps.drm && nativeProps.drm.getLicense && this._onGetLicense,
onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged, onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged,
onRestoreUserInterfaceForPictureInPictureStop: this._onRestoreUserInterfaceForPictureInPictureStop, onRestoreUserInterfaceForPictureInPictureStop: this._onRestoreUserInterfaceForPictureInPictureStop,
onReceiveAdEvent: this._onReceiveAdEvent,
}); });
const posterStyle = { const posterStyle = {
@ -551,6 +559,8 @@ Video.propTypes = {
onPictureInPictureStatusChanged: PropTypes.func, onPictureInPictureStatusChanged: PropTypes.func,
needsToRestoreUserInterfaceForPictureInPictureStop: PropTypes.func, needsToRestoreUserInterfaceForPictureInPictureStop: PropTypes.func,
onExternalPlaybackChange: PropTypes.func, onExternalPlaybackChange: PropTypes.func,
adTagUrl: PropTypes.string,
onReceiveAdEvent: PropTypes.func,
/* Required by react-native */ /* Required by react-native */
scaleX: PropTypes.number, scaleX: PropTypes.number,

View File

@ -45,5 +45,7 @@ dependencies {
implementation('com.google.android.exoplayer:extension-okhttp:2.18.1') { implementation('com.google.android.exoplayer:extension-okhttp:2.18.1') {
exclude group: 'com.squareup.okhttp3', module: 'okhttp' exclude group: 'com.squareup.okhttp3', module: 'okhttp'
} }
implementation 'com.google.android.exoplayer:extension-ima:2.18.1'
implementation "com.squareup.okhttp3:okhttp:" + '$OKHTTP_VERSION' implementation "com.squareup.okhttp3:okhttp:" + '$OKHTTP_VERSION'
} }

View File

@ -4,7 +4,6 @@ import android.annotation.TargetApi;
import android.content.Context; import android.content.Context;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.Gravity; import android.view.Gravity;
import android.view.SurfaceView; import android.view.SurfaceView;
@ -22,13 +21,14 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Tracks; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.AdViewProvider;
import com.google.android.exoplayer2.ui.SubtitleView; import com.google.android.exoplayer2.ui.SubtitleView;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.video.VideoSize; import com.google.android.exoplayer2.video.VideoSize;
import java.util.List; import java.util.List;
@TargetApi(16) public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
public final class ExoPlayerView extends FrameLayout {
private View surfaceView; private View surfaceView;
private final View shutterView; private final View shutterView;
@ -38,6 +38,7 @@ public final class ExoPlayerView extends FrameLayout {
private ExoPlayer player; private ExoPlayer player;
private Context context; private Context context;
private ViewGroup.LayoutParams layoutParams; private ViewGroup.LayoutParams layoutParams;
private final FrameLayout adOverlayFrameLayout;
private boolean useTextureView = true; private boolean useTextureView = true;
private boolean useSecureView = false; private boolean useSecureView = false;
@ -80,8 +81,11 @@ public final class ExoPlayerView extends FrameLayout {
updateSurfaceView(); updateSurfaceView();
adOverlayFrameLayout = new FrameLayout(context);
layout.addView(shutterView, 1, layoutParams); layout.addView(shutterView, 1, layoutParams);
layout.addView(subtitleLayout, 2, layoutParams); layout.addView(subtitleLayout, 2, layoutParams);
layout.addView(adOverlayFrameLayout, 3, layoutParams);
addViewInLayout(layout, 0, aspectRatioParams); addViewInLayout(layout, 0, aspectRatioParams);
} }
@ -139,6 +143,19 @@ public final class ExoPlayerView extends FrameLayout {
shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE); shutterView.setVisibility(this.hideShutterView ? View.INVISIBLE : View.VISIBLE);
} }
@Override
public void requestLayout() {
super.requestLayout();
post(measureAndLayout);
}
// AdsLoader.AdViewProvider implementation.
@Override
public ViewGroup getAdViewGroup() {
return Assertions.checkNotNull(adOverlayFrameLayout, "exo_ad_overlay must be present for ad playback");
}
/** /**
* Set the {@link ExoPlayer} to use. The {@link ExoPlayer#addListener} method of the * Set the {@link ExoPlayer} to use. The {@link ExoPlayer#addListener} method of the
* player will be called and previous * player will be called and previous

View File

@ -1,5 +1,10 @@
package com.brentvatne.exoplayer; package com.brentvatne.exoplayer;
import static com.google.android.exoplayer2.C.CONTENT_TYPE_DASH;
import static com.google.android.exoplayer2.C.CONTENT_TYPE_HLS;
import static com.google.android.exoplayer2.C.CONTENT_TYPE_OTHER;
import static com.google.android.exoplayer2.C.CONTENT_TYPE_SS;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.app.ActivityManager; import android.app.ActivityManager;
@ -30,6 +35,7 @@ import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.google.ads.interactivemedia.v3.api.AdEvent;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl; import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory; import com.google.android.exoplayer2.DefaultRenderersFactory;
@ -68,11 +74,11 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection; import com.google.android.exoplayer2.trackselection.ExoTrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides; import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.upstream.DefaultAllocator; import com.google.android.exoplayer2.upstream.DefaultAllocator;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.HttpDataSource; import com.google.android.exoplayer2.upstream.HttpDataSource;
@ -84,6 +90,11 @@ import com.google.android.exoplayer2.source.dash.manifest.Period;
import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet;
import com.google.android.exoplayer2.source.dash.manifest.Representation; import com.google.android.exoplayer2.source.dash.manifest.Representation;
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.common.collect.ImmutableList;
import java.net.CookieHandler; import java.net.CookieHandler;
import java.net.CookieManager; import java.net.CookieManager;
import java.net.CookiePolicy; import java.net.CookiePolicy;
@ -107,7 +118,8 @@ class ReactExoplayerView extends FrameLayout implements
BandwidthMeter.EventListener, BandwidthMeter.EventListener,
BecomingNoisyListener, BecomingNoisyListener,
AudioManager.OnAudioFocusChangeListener, AudioManager.OnAudioFocusChangeListener,
DrmSessionEventListener { DrmSessionEventListener,
AdEvent.AdEventListener {
public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1; public static final double DEFAULT_MAX_HEAP_ALLOCATION_PERCENT = 1;
public static final double DEFAULT_MIN_BACK_BUFFER_MEMORY_RESERVE = 0; public static final double DEFAULT_MIN_BACK_BUFFER_MEMORY_RESERVE = 0;
@ -132,6 +144,7 @@ class ReactExoplayerView extends FrameLayout implements
private ExoPlayerView exoPlayerView; private ExoPlayerView exoPlayerView;
private FullScreenPlayerView fullScreenPlayerView; private FullScreenPlayerView fullScreenPlayerView;
private ImaAdsLoader adsLoader;
private DataSource.Factory mediaDataSourceFactory; private DataSource.Factory mediaDataSourceFactory;
private ExoPlayer player; private ExoPlayer player;
@ -191,6 +204,7 @@ class ReactExoplayerView extends FrameLayout implements
private String drmLicenseUrl = null; private String drmLicenseUrl = null;
private String[] drmLicenseHeader = null; private String[] drmLicenseHeader = null;
private boolean controls; private boolean controls;
private Uri adTagUrl;
// \ End props // \ End props
// React // React
@ -209,6 +223,9 @@ class ReactExoplayerView extends FrameLayout implements
switch (msg.what) { switch (msg.what) {
case SHOW_PROGRESS: case SHOW_PROGRESS:
if (player != null) { if (player != null) {
if (playerControlView != null && isPlayingAd() && controls) {
playerControlView.hide();
}
long pos = player.getCurrentPosition(); long pos = player.getCurrentPosition();
long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100; long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100;
long duration = player.getDuration(); long duration = player.getDuration();
@ -251,6 +268,9 @@ class ReactExoplayerView extends FrameLayout implements
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext); audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
} }
private boolean isPlayingAd() {
return player != null && player.isPlayingAd();
}
@Override @Override
public void setId(int id) { public void setId(int id) {
@ -360,6 +380,15 @@ class ReactExoplayerView extends FrameLayout implements
playerControlView = new PlayerControlView(getContext()); playerControlView = new PlayerControlView(getContext());
} }
if (fullScreenPlayerView == null) {
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setFullscreen(false);
}
});
}
// Setting the player for the playerControlView // Setting the player for the playerControlView
playerControlView.setPlayer(player); playerControlView.setPlayer(player);
playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container); playPauseControlContainer = playerControlView.findViewById(R.id.exo_play_pause_container);
@ -368,7 +397,9 @@ class ReactExoplayerView extends FrameLayout implements
exoPlayerView.setOnClickListener(new OnClickListener() { exoPlayerView.setOnClickListener(new OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
togglePlayerControlVisibility(); if (!isPlayingAd()) {
togglePlayerControlVisibility();
}
} }
}); });
@ -394,8 +425,9 @@ class ReactExoplayerView extends FrameLayout implements
}); });
//Handling the fullScreenButton click event //Handling the fullScreenButton click event
ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen); final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen)); fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen));
updateFullScreenButtonVisbility();
// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player // Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
eventListener = new Player.Listener() { eventListener = new Player.Listener() {
@ -409,7 +441,6 @@ class ReactExoplayerView extends FrameLayout implements
if (pauseButton != null && pauseButton.getVisibility() == GONE) { if (pauseButton != null && pauseButton.getVisibility() == GONE) {
pauseButton.setVisibility(INVISIBLE); pauseButton.setVisibility(INVISIBLE);
} }
reLayout(playPauseControlContainer); reLayout(playPauseControlContainer);
//Remove this eventListener once its executed. since UI will work fine once after the reLayout is done //Remove this eventListener once its executed. since UI will work fine once after the reLayout is done
player.removeListener(eventListener); player.removeListener(eventListener);
@ -429,7 +460,7 @@ class ReactExoplayerView extends FrameLayout implements
* Adding Player control to the frame layout * Adding Player control to the frame layout
*/ */
private void addPlayerControl() { private void addPlayerControl() {
if(player == null) return; if(playerControlView == null) return;
LayoutParams layoutParams = new LayoutParams( LayoutParams layoutParams = new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT); LayoutParams.MATCH_PARENT);
@ -535,6 +566,12 @@ class ReactExoplayerView extends FrameLayout implements
return; return;
} }
if (activity == null) {
Log.e("ExoPlayer Exception", "Failed to initialize Player!");
eventEmitter.error("Failed to initialize Player!", new Exception("Current Activity is null!"), "1001");
return;
}
// Initialize handler to run on the main thread // Initialize handler to run on the main thread
activity.runOnUiThread(new Runnable() { activity.runOnUiThread(new Runnable() {
public void run() { public void run() {
@ -586,13 +623,22 @@ class ReactExoplayerView extends FrameLayout implements
DefaultRenderersFactory renderersFactory = DefaultRenderersFactory renderersFactory =
new DefaultRenderersFactory(getContext()) new DefaultRenderersFactory(getContext())
.setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF); .setExtensionRendererMode(DefaultRenderersFactory.EXTENSION_RENDERER_MODE_OFF);
// Create an AdsLoader.
adsLoader = new ImaAdsLoader.Builder(themedReactContext).setAdEventListener(this).build();
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
player = new ExoPlayer.Builder(getContext(), renderersFactory) player = new ExoPlayer.Builder(getContext(), renderersFactory)
.setTrackSelector(self.trackSelector) .setTrackSelector(self.trackSelector)
.setBandwidthMeter(bandwidthMeter) .setBandwidthMeter(bandwidthMeter)
.setLoadControl(loadControl) .setLoadControl(loadControl)
.setMediaSourceFactory(mediaSourceFactory)
.build(); .build();
player.addListener(self); player.addListener(self);
exoPlayerView.setPlayer(player); exoPlayerView.setPlayer(player);
adsLoader.setPlayer(player);
audioBecomingNoisyReceiver.setListener(self); audioBecomingNoisyReceiver.setListener(self);
bandwidthMeter.addEventListener(new Handler(), self); bandwidthMeter.addEventListener(new Handler(), self);
setPlayWhenReady(!isPaused); setPlayWhenReady(!isPaused);
@ -622,11 +668,26 @@ class ReactExoplayerView extends FrameLayout implements
private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) { private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) {
ArrayList<MediaSource> mediaSourceList = buildTextSources(); ArrayList<MediaSource> mediaSourceList = buildTextSources();
MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager); MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager);
MediaSource mediaSourceWithAds = null;
if (adTagUrl != null) {
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
.setLocalAdInsertionComponents(unusedAdTagUri -> adsLoader, exoPlayerView);
DataSpec adTagDataSpec = new DataSpec(adTagUrl);
mediaSourceWithAds = new AdsMediaSource(videoSource, adTagDataSpec, ImmutableList.of(srcUri, adTagUrl), mediaSourceFactory, adsLoader, exoPlayerView);
}
MediaSource mediaSource; MediaSource mediaSource;
if (mediaSourceList.size() == 0) { if (mediaSourceList.size() == 0) {
mediaSource = videoSource; if (mediaSourceWithAds != null) {
mediaSource = mediaSourceWithAds;
} else {
mediaSource = videoSource;
}
} else { } else {
mediaSourceList.add(0, videoSource); if (mediaSourceWithAds != null) {
mediaSourceList.add(0, mediaSourceWithAds);
} else {
mediaSourceList.add(0, videoSource);
}
MediaSource[] textSourceArray = mediaSourceList.toArray( MediaSource[] textSourceArray = mediaSourceList.toArray(
new MediaSource[mediaSourceList.size()] new MediaSource[mediaSourceList.size()]
); );
@ -663,12 +724,6 @@ class ReactExoplayerView extends FrameLayout implements
setControls(controls); setControls(controls);
applyModifiers(); applyModifiers();
startBufferCheckTimer(); startBufferCheckTimer();
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setFullscreen(false);
}
});
} }
private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException { private DrmSessionManager buildDrmSessionManager(UUID uuid, String licenseUrl, String[] keyRequestPropertiesArray) throws UnsupportedDrmException {
@ -714,7 +769,17 @@ class ReactExoplayerView extends FrameLayout implements
int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension int type = Util.inferContentType(!TextUtils.isEmpty(overrideExtension) ? "." + overrideExtension
: uri.getLastPathSegment()); : uri.getLastPathSegment());
config.setDisableDisconnectError(this.disableDisconnectError); config.setDisableDisconnectError(this.disableDisconnectError);
MediaItem mediaItem = new MediaItem.Builder().setUri(uri).build();
MediaItem.Builder mediaItemBuilder = new MediaItem.Builder().setUri(uri);
if (adTagUrl != null) {
mediaItemBuilder.setAdsConfiguration(
new MediaItem.AdsConfiguration.Builder(adTagUrl).build()
);
}
MediaItem mediaItem = mediaItemBuilder.build();
DrmSessionManagerProvider drmProvider = null; DrmSessionManagerProvider drmProvider = null;
if (drmSessionManager != null) { if (drmSessionManager != null) {
drmProvider = new DrmSessionManagerProvider() { drmProvider = new DrmSessionManagerProvider() {
@ -727,7 +792,7 @@ class ReactExoplayerView extends FrameLayout implements
drmProvider = new DefaultDrmSessionManagerProvider(); drmProvider = new DefaultDrmSessionManagerProvider();
} }
switch (type) { switch (type) {
case C.TYPE_SS: case CONTENT_TYPE_SS:
return new SsMediaSource.Factory( return new SsMediaSource.Factory(
new DefaultSsChunkSource.Factory(mediaDataSourceFactory), new DefaultSsChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false) buildDataSourceFactory(false)
@ -735,7 +800,7 @@ class ReactExoplayerView extends FrameLayout implements
.setLoadErrorHandlingPolicy( .setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem); ).createMediaSource(mediaItem);
case C.TYPE_DASH: case CONTENT_TYPE_DASH:
return new DashMediaSource.Factory( return new DashMediaSource.Factory(
new DefaultDashChunkSource.Factory(mediaDataSourceFactory), new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
buildDataSourceFactory(false) buildDataSourceFactory(false)
@ -743,14 +808,14 @@ class ReactExoplayerView extends FrameLayout implements
.setLoadErrorHandlingPolicy( .setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem); ).createMediaSource(mediaItem);
case C.TYPE_HLS: case CONTENT_TYPE_HLS:
return new HlsMediaSource.Factory( return new HlsMediaSource.Factory(
mediaDataSourceFactory mediaDataSourceFactory
).setDrmSessionManagerProvider(drmProvider) ).setDrmSessionManagerProvider(drmProvider)
.setLoadErrorHandlingPolicy( .setLoadErrorHandlingPolicy(
config.buildLoadErrorHandlingPolicy(minLoadRetryCount) config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
).createMediaSource(mediaItem); ).createMediaSource(mediaItem);
case C.TYPE_OTHER: case CONTENT_TYPE_OTHER:
return new ProgressiveMediaSource.Factory( return new ProgressiveMediaSource.Factory(
mediaDataSourceFactory mediaDataSourceFactory
).setDrmSessionManagerProvider(drmProvider) ).setDrmSessionManagerProvider(drmProvider)
@ -798,12 +863,15 @@ class ReactExoplayerView extends FrameLayout implements
private void releasePlayer() { private void releasePlayer() {
if (player != null) { if (player != null) {
adsLoader.setPlayer(null);
updateResumePosition(); updateResumePosition();
player.release(); player.release();
player.removeListener(this); player.removeListener(this);
trackSelector = null; trackSelector = null;
player = null; player = null;
} }
adsLoader.release();
adsLoader = null;
progressHandler.removeMessages(SHOW_PROGRESS); progressHandler.removeMessages(SHOW_PROGRESS);
themedReactContext.removeLifecycleEventListener(this); themedReactContext.removeLifecycleEventListener(this);
audioBecomingNoisyReceiver.removeListener(); audioBecomingNoisyReceiver.removeListener();
@ -995,6 +1063,7 @@ class ReactExoplayerView extends FrameLayout implements
text += "ready"; text += "ready";
eventEmitter.ready(); eventEmitter.ready();
onBuffering(false); onBuffering(false);
clearProgressMessageHandler(); // ensure there is no other message
startProgressHandler(); startProgressHandler();
videoLoaded(); videoLoaded();
if (selectTrackWhenReady && isUsingContentResolution) { if (selectTrackWhenReady && isUsingContentResolution) {
@ -1034,7 +1103,7 @@ class ReactExoplayerView extends FrameLayout implements
} }
private void videoLoaded() { private void videoLoaded() {
if (loadVideoStarted) { if (!player.isPlayingAd() && loadVideoStarted) {
loadVideoStarted = false; loadVideoStarted = false;
if (audioTrackType != null) { if (audioTrackType != null) {
setSelectedAudioTrack(audioTrackType, audioTrackValue); setSelectedAudioTrack(audioTrackType, audioTrackValue);
@ -1427,6 +1496,10 @@ class ReactExoplayerView extends FrameLayout implements
mReportBandwidth = reportBandwidth; mReportBandwidth = reportBandwidth;
} }
public void setAdTagUrl(final Uri uri) {
adTagUrl = uri;
}
public void setRawSrc(final Uri uri, final String extension) { public void setRawSrc(final Uri uri, final String extension) {
if (uri != null) { if (uri != null) {
boolean isSourceEqual = uri.equals(srcUri); boolean isSourceEqual = uri.equals(srcUri);
@ -1778,6 +1851,22 @@ class ReactExoplayerView extends FrameLayout implements
this.disableBuffering = disableBuffering; this.disableBuffering = disableBuffering;
} }
private void updateFullScreenButtonVisbility() {
if (playerControlView != null) {
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
if (controls) {
//Handling the fullScreenButton click event
if (isFullscreen && fullScreenPlayerView != null && !fullScreenPlayerView.isShowing()) {
fullScreenButton.setVisibility(GONE);
} else {
fullScreenButton.setVisibility(VISIBLE);
}
} else {
fullScreenButton.setVisibility(GONE);
}
}
}
public void setDisableDisconnectError(boolean disableDisconnectError) { public void setDisableDisconnectError(boolean disableDisconnectError) {
this.disableDisconnectError = disableDisconnectError; this.disableDisconnectError = disableDisconnectError;
} }
@ -1793,15 +1882,6 @@ class ReactExoplayerView extends FrameLayout implements
return; return;
} }
if (fullScreenPlayerView == null) {
fullScreenPlayerView = new FullScreenPlayerView(getContext(), exoPlayerView, playerControlView, new OnBackPressedCallback(true) {
@Override
public void handleOnBackPressed() {
setFullscreen(false);
}
});
}
Window window = activity.getWindow(); Window window = activity.getWindow();
View decorView = window.getDecorView(); View decorView = window.getDecorView();
int uiOptions; int uiOptions;
@ -1815,7 +1895,7 @@ class ReactExoplayerView extends FrameLayout implements
| SYSTEM_UI_FLAG_FULLSCREEN; | SYSTEM_UI_FLAG_FULLSCREEN;
} }
eventEmitter.fullscreenWillPresent(); eventEmitter.fullscreenWillPresent();
if (controls) { if (controls && fullScreenPlayerView != null) {
fullScreenPlayerView.show(); fullScreenPlayerView.show();
} }
post(() -> { post(() -> {
@ -1825,7 +1905,7 @@ class ReactExoplayerView extends FrameLayout implements
} else { } else {
uiOptions = View.SYSTEM_UI_FLAG_VISIBLE; uiOptions = View.SYSTEM_UI_FLAG_VISIBLE;
eventEmitter.fullscreenWillDismiss(); eventEmitter.fullscreenWillDismiss();
if (controls) { if (controls && fullScreenPlayerView != null) {
fullScreenPlayerView.dismiss(); fullScreenPlayerView.dismiss();
reLayout(exoPlayerView); reLayout(exoPlayerView);
} }
@ -1834,6 +1914,8 @@ class ReactExoplayerView extends FrameLayout implements
eventEmitter.fullscreenDidDismiss(); eventEmitter.fullscreenDidDismiss();
}); });
} }
// need to be done at the end to avoid hiding fullscreen control button when fullScreenPlayerView is shown
updateFullScreenButtonVisbility();
} }
public void setUseTextureView(boolean useTextureView) { public void setUseTextureView(boolean useTextureView) {
@ -1902,9 +1984,9 @@ class ReactExoplayerView extends FrameLayout implements
*/ */
public void setControls(boolean controls) { public void setControls(boolean controls) {
this.controls = controls; this.controls = controls;
if (player == null || exoPlayerView == null) return;
if (controls) { if (controls) {
addPlayerControl(); addPlayerControl();
updateFullScreenButtonVisbility();
} else { } else {
int indexOfPC = indexOfChild(playerControlView); int indexOfPC = indexOfChild(playerControlView);
if (indexOfPC != -1) { if (indexOfPC != -1) {
@ -1916,4 +1998,9 @@ class ReactExoplayerView extends FrameLayout implements
public void setSubtitleStyle(SubtitleStyle style) { public void setSubtitleStyle(SubtitleStyle style) {
exoPlayerView.setSubtitleStyle(style); exoPlayerView.setSubtitleStyle(style);
} }
@Override
public void onAdEvent(AdEvent adEvent) {
eventEmitter.receiveAdEvent(adEvent.getType().name());
}
} }

View File

@ -31,6 +31,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_SRC = "src"; private static final String PROP_SRC = "src";
private static final String PROP_SRC_URI = "uri"; private static final String PROP_SRC_URI = "uri";
private static final String PROP_AD_TAG_URL = "adTagUrl";
private static final String PROP_SRC_TYPE = "type"; private static final String PROP_SRC_TYPE = "type";
private static final String PROP_DRM = "drm"; private static final String PROP_DRM = "drm";
private static final String PROP_DRM_TYPE = "type"; private static final String PROP_DRM_TYPE = "type";
@ -189,6 +190,18 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
} }
} }
@ReactProp(name = PROP_AD_TAG_URL)
public void setAdTagUrl(final ReactExoplayerView videoView, final String uriString) {
if (TextUtils.isEmpty(uriString)) {
return;
}
Uri adTagUrl = Uri.parse(uriString);
videoView.setAdTagUrl(adTagUrl);
}
@ReactProp(name = PROP_RESIZE_MODE) @ReactProp(name = PROP_RESIZE_MODE)
public void setResizeMode(final ReactExoplayerView videoView, final String resizeModeOrdinalString) { public void setResizeMode(final ReactExoplayerView videoView, final String resizeModeOrdinalString) {
videoView.setResizeModeModifier(convertToIntDef(resizeModeOrdinalString)); videoView.setResizeModeModifier(convertToIntDef(resizeModeOrdinalString));

View File

@ -56,6 +56,7 @@ class VideoEventEmitter {
private static final String EVENT_AUDIO_TRACKS = "onAudioTracks"; private static final String EVENT_AUDIO_TRACKS = "onAudioTracks";
private static final String EVENT_TEXT_TRACKS = "onTextTracks"; private static final String EVENT_TEXT_TRACKS = "onTextTracks";
private static final String EVENT_VIDEO_TRACKS = "onVideoTracks"; private static final String EVENT_VIDEO_TRACKS = "onVideoTracks";
private static final String EVENT_ON_RECEIVE_AD_EVENT = "onReceiveAdEvent";
static final String[] Events = { static final String[] Events = {
EVENT_LOAD_START, EVENT_LOAD_START,
@ -82,6 +83,7 @@ class VideoEventEmitter {
EVENT_TEXT_TRACKS, EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS, EVENT_VIDEO_TRACKS,
EVENT_BANDWIDTH, EVENT_BANDWIDTH,
EVENT_ON_RECEIVE_AD_EVENT
}; };
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@ -110,6 +112,7 @@ class VideoEventEmitter {
EVENT_TEXT_TRACKS, EVENT_TEXT_TRACKS,
EVENT_VIDEO_TRACKS, EVENT_VIDEO_TRACKS,
EVENT_BANDWIDTH, EVENT_BANDWIDTH,
EVENT_ON_RECEIVE_AD_EVENT
}) })
@interface VideoEvents { @interface VideoEvents {
} }
@ -432,6 +435,13 @@ class VideoEventEmitter {
receiveEvent(EVENT_AUDIO_BECOMING_NOISY, null); receiveEvent(EVENT_AUDIO_BECOMING_NOISY, null);
} }
void receiveAdEvent(String event) {
WritableMap map = Arguments.createMap();
map.putString("event", event);
receiveEvent(EVENT_ON_RECEIVE_AD_EVENT, map);
}
private void receiveEvent(@VideoEvents String type, WritableMap event) { private void receiveEvent(@VideoEvents String type, WritableMap event) {
eventEmitter.receiveEvent(viewId, type, event); eventEmitter.receiveEvent(viewId, type, event);
} }

View File

@ -0,0 +1,6 @@
[android]
target = Google Inc.:Google APIs:23
[maven_repositories]
central = https://repo1.maven.org/maven2

View File

@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: '@react-native-community',
};

View File

@ -0,0 +1,66 @@
[ignore]
; We fork some components by platform
.*/*[.]android.js
; Ignore "BUCK" generated dirs
<PROJECT_ROOT>/\.buckd/
; Ignore polyfills
node_modules/react-native/Libraries/polyfills/.*
; Flow doesn't support platforms
.*/Libraries/Utilities/LoadingView.js
.*/node_modules/resolve/test/resolver/malformed_package_json/package\.json$
[untyped]
.*/node_modules/@react-native-community/cli/.*/.*
[include]
[libs]
node_modules/react-native/interface.js
node_modules/react-native/flow/
[options]
emoji=true
exact_by_default=true
format.bracket_spacing=false
module.file_ext=.js
module.file_ext=.json
module.file_ext=.ios.js
munge_underscores=true
module.name_mapper='^react-native/\(.*\)$' -> '<PROJECT_ROOT>/node_modules/react-native/\1'
module.name_mapper='^@?[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> '<PROJECT_ROOT>/node_modules/react-native/Libraries/Image/RelativeImageStub'
suppress_type=$FlowIssue
suppress_type=$FlowFixMe
suppress_type=$FlowFixMeProps
suppress_type=$FlowFixMeState
[lints]
sketchy-null-number=warn
sketchy-null-mixed=warn
sketchy-number=warn
untyped-type-import=warn
nonstrict-import=warn
deprecated-type=warn
unsafe-getters-setters=warn
unnecessary-invariant=warn
[strict]
deprecated-type
nonstrict-import
sketchy-null
unclear-type
unsafe-getters-setters
untyped-import
untyped-type-import
[version]
^0.182.0

64
examples/basic/.gitignore vendored Normal file
View File

@ -0,0 +1,64 @@
# OSX
#
.DS_Store
# Xcode
#
build/
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata
*.xccheckout
*.moved-aside
DerivedData
*.hmap
*.ipa
*.xcuserstate
ios/.xcode.env.local
# Android/IntelliJ
#
build/
.idea
.gradle
local.properties
*.iml
*.hprof
.cxx/
# node.js
#
node_modules/
npm-debug.log
yarn-error.log
# BUCK
buck-out/
\.buckd/
*.keystore
!debug.keystore
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/
**/fastlane/report.xml
**/fastlane/Preview.html
**/fastlane/screenshots
**/fastlane/test_output
# Bundle artifact
*.jsbundle
# Ruby / CocoaPods
/ios/Pods/
/vendor/bundle/

View File

@ -0,0 +1,7 @@
module.exports = {
arrowParens: 'avoid',
bracketSameLine: true,
bracketSpacing: false,
singleQuote: true,
trailingComma: 'all',
};

View File

@ -0,0 +1 @@
{}

6
examples/basic/Gemfile Normal file
View File

@ -0,0 +1,6 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.5'
gem 'cocoapods', '~> 1.11', '>= 1.11.2'

View File

@ -4,11 +4,11 @@
import 'react-native'; import 'react-native';
import React from 'react'; import React from 'react';
import VideoPlayer from '../src/VideoPlayer'; import App from '../App';
// Note: test renderer must be required after react-native. // Note: test renderer must be required after react-native.
import renderer from 'react-test-renderer'; import renderer from 'react-test-renderer';
it('renders correctly', () => { it('renders correctly', () => {
renderer.create(<VideoPlayer />); renderer.create(<App />);
}); });

View File

@ -0,0 +1,2 @@
BUNDLE_PATH: "vendor/bundle"
BUNDLE_FORCE_RUBY_PLATFORM: 1

View File

@ -0,0 +1 @@
16

View File

@ -0,0 +1 @@
2.7.5

View File

@ -1,6 +1,7 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
import com.android.build.OutputFile import com.android.build.OutputFile
import org.apache.tools.ant.taskdefs.condition.Os
/** /**
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets * The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
@ -78,7 +79,7 @@ import com.android.build.OutputFile
*/ */
project.ext.react = [ project.ext.react = [
enableHermes: false, // clean and rebuild if changing enableHermes: true, // clean and rebuild if changing
] ]
apply from: "../../node_modules/react-native/react.gradle" apply from: "../../node_modules/react-native/react.gradle"
@ -114,19 +115,24 @@ def jscFlavor = 'org.webkit:android-jsc:+'
/** /**
* Whether to enable the Hermes VM. * Whether to enable the Hermes VM.
* *
* This should be set on project.ext.react and mirrored here. If it is not set * This should be set on project.ext.react and that value will be read here. If it is not set
* on project.ext.react, JavaScript will not be compiled to Hermes Bytecode * on project.ext.react, JavaScript will not be compiled to Hermes Bytecode
* and the benefits of using Hermes will therefore be sharply reduced. * and the benefits of using Hermes will therefore be sharply reduced.
*/ */
def enableHermes = project.ext.react.get("enableHermes", false); def enableHermes = project.ext.react.get("enableHermes", false);
android { /**
compileSdkVersion rootProject.ext.compileSdkVersion * Architectures to build native code for.
*/
def reactNativeArchitectures() {
def value = project.getProperties().get("reactNativeArchitectures")
return value ? value.split(",") : ["armeabi-v7a", "x86", "x86_64", "arm64-v8a"]
}
compileOptions { android {
sourceCompatibility JavaVersion.VERSION_1_8 ndkVersion rootProject.ext.ndkVersion
targetCompatibility JavaVersion.VERSION_1_8
} compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig { defaultConfig {
applicationId "com.videoplayer" applicationId "com.videoplayer"
@ -134,15 +140,75 @@ android {
targetSdkVersion rootProject.ext.targetSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
multiDexEnabled true multiDexEnabled true
if (isNewArchitectureEnabled()) {
// We configure the CMake build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
arguments "-DPROJECT_BUILD_DIR=$buildDir",
"-DREACT_ANDROID_DIR=$rootDir/../node_modules/react-native/ReactAndroid",
"-DREACT_ANDROID_BUILD_DIR=$rootDir/../node_modules/react-native/ReactAndroid/build",
"-DNODE_MODULES_DIR=$rootDir/../node_modules",
"-DANDROID_STL=c++_shared"
}
}
if (!enableSeparateBuildPerCPUArchitecture) {
ndk {
abiFilters (*reactNativeArchitectures())
}
}
}
} }
if (isNewArchitectureEnabled()) {
// We configure the NDK build only if you decide to opt-in for the New Architecture.
externalNativeBuild {
cmake {
path "$projectDir/src/main/jni/CMakeLists.txt"
}
}
def reactAndroidProjectDir = project(':ReactAndroid').projectDir
def packageReactNdkDebugLibs = tasks.register("packageReactNdkDebugLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkDebugLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
def packageReactNdkReleaseLibs = tasks.register("packageReactNdkReleaseLibs", Copy) {
dependsOn(":ReactAndroid:packageReactNdkReleaseLibsForBuck")
from("$reactAndroidProjectDir/src/main/jni/prebuilt/lib")
into("$buildDir/react-ndk/exported")
}
afterEvaluate {
// If you wish to add a custom TurboModule or component locally,
// you should uncomment this line.
// preBuild.dependsOn("generateCodegenArtifactsFromSchema")
preDebugBuild.dependsOn(packageReactNdkDebugLibs)
preReleaseBuild.dependsOn(packageReactNdkReleaseLibs)
// Due to a bug inside AGP, we have to explicitly set a dependency
// between configureCMakeDebug* tasks and the preBuild tasks.
// This can be removed once this is solved: https://issuetracker.google.com/issues/207403732
configureCMakeRelWithDebInfo.dependsOn(preReleaseBuild)
configureCMakeDebug.dependsOn(preDebugBuild)
reactNativeArchitectures().each { architecture ->
tasks.findByName("configureCMakeDebug[${architecture}]")?.configure {
dependsOn("preDebugBuild")
}
tasks.findByName("configureCMakeRelWithDebInfo[${architecture}]")?.configure {
dependsOn("preReleaseBuild")
}
}
}
}
splits { splits {
abi { abi {
reset() reset()
enable enableSeparateBuildPerCPUArchitecture enable enableSeparateBuildPerCPUArchitecture
universalApk false // If true, also generate a universal APK universalApk false // If true, also generate a universal APK
include "armeabi-v7a", "x86", "arm64-v8a", "x86_64" include (*reactNativeArchitectures())
} }
} }
signingConfigs { signingConfigs {
@ -171,11 +237,12 @@ android {
variant.outputs.each { output -> variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here: // For each separate APK per architecture, set a unique version code as described here:
// https://developer.android.com/studio/build/configure-apk-splits.html // 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 versionCodes = ["armeabi-v7a": 1, "x86": 2, "arm64-v8a": 3, "x86_64": 4]
def abi = output.getFilter(OutputFile.ABI) def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride = output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode defaultConfig.versionCode * 1000 + versionCodes.get(abi)
} }
} }
@ -184,13 +251,14 @@ android {
dependencies { dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"]) implementation fileTree(dir: "libs", include: ["*.jar"])
//noinspection GradleDynamicVersion //noinspection GradleDynamicVersion
implementation "com.facebook.react:react-native:+" // From node_modules implementation "com.facebook.react:react-native:+" // From node_modules
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0" implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") { debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
exclude group:'com.facebook.fbjni' exclude group:'com.facebook.fbjni'
} }
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") { debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
@ -203,19 +271,44 @@ dependencies {
} }
if (enableHermes) { if (enableHermes) {
def hermesPath = "../../node_modules/hermes-engine/android/"; //noinspection GradleDynamicVersion
debugImplementation files(hermesPath + "hermes-debug.aar") implementation("com.facebook.react:hermes-engine:+") { // From node_modules
releaseImplementation files(hermesPath + "hermes-release.aar") exclude group:'com.facebook.fbjni'
}
} else { } else {
implementation jscFlavor implementation jscFlavor
} }
} }
if (isNewArchitectureEnabled()) {
// If new architecture is enabled, we let you build RN from source
// Otherwise we fallback to a prebuilt .aar bundled in the NPM package.
// This will be applied to all the imported transtitive dependency.
configurations.all {
resolutionStrategy.dependencySubstitution {
substitute(module("com.facebook.react:react-native"))
.using(project(":ReactAndroid"))
.because("On New Architecture we're building React Native from source")
substitute(module("com.facebook.react:hermes-engine"))
.using(project(":ReactAndroid:hermes-engine"))
.because("On New Architecture we're building Hermes from source")
}
}
}
// Run this once to be able to run the application with BUCK // Run this once to be able to run the application with BUCK
// puts all compile dependencies into folder libs for BUCK to use // puts all compile dependencies into folder libs for BUCK to use
task copyDownloadableDepsToLibs(type: Copy) { task copyDownloadableDepsToLibs(type: Copy) {
from configurations.compile from configurations.implementation
into 'libs' into 'libs'
} }
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project) apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
def isNewArchitectureEnabled() {
// To opt-in for the New Architecture, you can either:
// - Set `newArchEnabled` to true inside the `gradle.properties` file
// - Invoke gradle with `-newArchEnabled=true`
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
}

View File

@ -8,59 +8,3 @@
# http://developer.android.com/guide/developing/tools/proguard.html # http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here: # Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Disabling obfuscation is useful if you collect stack traces from production crashes
# (unless you are using a system that supports de-obfuscate the stack traces).
-dontobfuscate
# React Native
# Keep our interfaces so they can be used by other ProGuard rules.
# See http://sourceforge.net/p/proguard/bugs/466/
-keep,allowobfuscation @interface com.facebook.proguard.annotations.DoNotStrip
-keep,allowobfuscation @interface com.facebook.proguard.annotations.KeepGettersAndSetters
-keep,allowobfuscation @interface com.facebook.common.internal.DoNotStrip
# Do not strip any method/class that is annotated with @DoNotStrip
-keep @com.facebook.proguard.annotations.DoNotStrip class *
-keep @com.facebook.common.internal.DoNotStrip class *
-keepclassmembers class * {
@com.facebook.proguard.annotations.DoNotStrip *;
@com.facebook.common.internal.DoNotStrip *;
}
-keepclassmembers @com.facebook.proguard.annotations.KeepGettersAndSetters class * {
void set*(***);
*** get*();
}
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; }
-keepclassmembers,includedescriptorclasses class * { native <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.annotations.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
# okhttp
-keepattributes Signature
-keepattributes *Annotation*
-keep class okhttp3.** { *; }
-keep interface okhttp3.** { *; }
-dontwarn okhttp3.**
# okio
-keep class sun.misc.Unsafe { *; }
-dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.**

View File

@ -4,5 +4,10 @@
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" /> <application
android:usesCleartextTraffic="true"
tools:targetApi="28"
tools:ignore="GoogleAppIndexingWarning">
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" android:exported="false" />
</application>
</manifest> </manifest>

View File

@ -1,5 +1,5 @@
/** /**
* Copyright (c) Facebook, Inc. and its affiliates. * Copyright (c) Meta Platforms, Inc. and affiliates.
* *
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
* directory of this source tree. * directory of this source tree.
@ -19,6 +19,7 @@ import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin; import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
import com.facebook.flipper.plugins.react.ReactFlipperPlugin; import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin; import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
import com.facebook.react.ReactInstanceEventListener;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule; import com.facebook.react.modules.network.NetworkingModule;
@ -51,7 +52,7 @@ public class ReactNativeFlipper {
ReactContext reactContext = reactInstanceManager.getCurrentReactContext(); ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
if (reactContext == null) { if (reactContext == null) {
reactInstanceManager.addReactInstanceEventListener( reactInstanceManager.addReactInstanceEventListener(
new ReactInstanceManager.ReactInstanceEventListener() { new ReactInstanceEventListener() {
@Override @Override
public void onReactContextInitialized(ReactContext reactContext) { public void onReactContextInitialized(ReactContext reactContext) {
reactInstanceManager.removeReactInstanceEventListener(this); reactInstanceManager.removeReactInstanceEventListener(this);

View File

@ -23,16 +23,15 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:label="@string/app_name" android:label="@string/app_name"
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode" android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode"
android:launchMode="singleTask" android:launchMode="singleTask"
android:windowSoftInputMode="adjustResize"> android:windowSoftInputMode="adjustResize"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.LEANBACK_LAUNCHER" /> <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application> </application>
</manifest> </manifest>

View File

@ -1,6 +1,8 @@
package com.videoplayer; package com.videoplayer;
import com.facebook.react.ReactActivity; import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactRootView;
public class MainActivity extends ReactActivity { public class MainActivity extends ReactActivity {
@ -12,4 +14,35 @@ public class MainActivity extends ReactActivity {
protected String getMainComponentName() { protected String getMainComponentName() {
return "VideoPlayer"; return "VideoPlayer";
} }
/**
* Returns the instance of the {@link ReactActivityDelegate}. There the RootView is created and
* you can specify the renderer you wish to use - the new renderer (Fabric) or the old renderer
* (Paper).
*/
@Override
protected ReactActivityDelegate createReactActivityDelegate() {
return new MainActivityDelegate(this, getMainComponentName());
}
public static class MainActivityDelegate extends ReactActivityDelegate {
public MainActivityDelegate(ReactActivity activity, String mainComponentName) {
super(activity, mainComponentName);
}
@Override
protected ReactRootView createRootView() {
ReactRootView reactRootView = new ReactRootView(getContext());
// If you opted-in for the New Architecture, we enable the Fabric Renderer.
reactRootView.setIsFabric(BuildConfig.IS_NEW_ARCHITECTURE_ENABLED);
return reactRootView;
}
@Override
protected boolean isConcurrentRootEnabled() {
// If you opted-in for the New Architecture, we enable Concurrent Root (i.e. React 18).
// More on this on https://reactjs.org/blog/2022/03/29/react-v18.html
return BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
}
}
} }

View File

@ -7,42 +7,85 @@ import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager; import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import com.videoplayer.newarchitecture.MainApplicationReactNativeHost;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
public class MainApplication extends Application implements ReactApplication { public class MainApplication extends Application implements ReactApplication {
private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { private final ReactNativeHost mReactNativeHost =
@Override new ReactNativeHost(this) {
public boolean getUseDeveloperSupport() { @Override
return BuildConfig.DEBUG; public boolean getUseDeveloperSupport() {
} return BuildConfig.DEBUG;
}
@Override @Override
protected List<ReactPackage> getPackages() { protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable") @SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages(); List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for // Packages that cannot be autolinked yet can be added manually here, for example:
// example: // packages.add(new MyReactNativePackage());
// packages.add(new MyReactNativePackage()); return packages;
return packages; }
}
@Override @Override
protected String getJSMainModuleName() { protected String getJSMainModuleName() {
return "src/index"; return "src/index";
} }
}; };
private final ReactNativeHost mNewArchitectureNativeHost =
new MainApplicationReactNativeHost(this);
@Override @Override
public ReactNativeHost getReactNativeHost() { public ReactNativeHost getReactNativeHost() {
return mReactNativeHost; if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
return mNewArchitectureNativeHost;
} else {
return mReactNativeHost;
}
} }
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
// If you opted-in for the New Architecture, we enable the TurboModule system
ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
SoLoader.init(this, /* native exopackage */ false); SoLoader.init(this, /* native exopackage */ false);
initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
}
/**
* Loads Flipper in React Native templates. Call this in the onCreate method with something like
* initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
*
* @param context
* @param reactInstanceManager
*/
private static void initializeFlipper(
Context context, ReactInstanceManager reactInstanceManager) {
if (BuildConfig.DEBUG) {
try {
/*
We use reflection here to pick up the class that initializes Flipper,
since Flipper library is not available in release mode
*/
Class<?> aClass = Class.forName("com.videoplayer.ReactNativeFlipper");
aClass
.getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
.invoke(null, context, reactInstanceManager);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
} }
} }

View File

@ -0,0 +1,116 @@
package com.videoplayer.newarchitecture;
import android.app.Application;
import androidx.annotation.NonNull;
import com.facebook.react.PackageList;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.JSIModulePackage;
import com.facebook.react.bridge.JSIModuleProvider;
import com.facebook.react.bridge.JSIModuleSpec;
import com.facebook.react.bridge.JSIModuleType;
import com.facebook.react.bridge.JavaScriptContextHolder;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.UIManager;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.react.fabric.CoreComponentsRegistry;
import com.facebook.react.fabric.FabricJSIModuleProvider;
import com.facebook.react.fabric.ReactNativeConfig;
import com.facebook.react.uimanager.ViewManagerRegistry;
import com.videoplayer.BuildConfig;
import com.videoplayer.newarchitecture.components.MainComponentsRegistry;
import com.videoplayer.newarchitecture.modules.MainApplicationTurboModuleManagerDelegate;
import java.util.ArrayList;
import java.util.List;
/**
* A {@link ReactNativeHost} that helps you load everything needed for the New Architecture, both
* TurboModule delegates and the Fabric Renderer.
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationReactNativeHost extends ReactNativeHost {
public MainApplicationReactNativeHost(Application application) {
super(application);
}
@Override
public boolean getUseDeveloperSupport() {
return BuildConfig.DEBUG;
}
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
// Packages that cannot be autolinked yet can be added manually here, for example:
// packages.add(new MyReactNativePackage());
// TurboModules must also be loaded here providing a valid TurboReactPackage implementation:
// packages.add(new TurboReactPackage() { ... });
// If you have custom Fabric Components, their ViewManagers should also be loaded here
// inside a ReactPackage.
return packages;
}
@Override
protected String getJSMainModuleName() {
return "src/index";
}
@NonNull
@Override
protected ReactPackageTurboModuleManagerDelegate.Builder
getReactPackageTurboModuleManagerDelegateBuilder() {
// Here we provide the ReactPackageTurboModuleManagerDelegate Builder. This is necessary
// for the new architecture and to use TurboModules correctly.
return new MainApplicationTurboModuleManagerDelegate.Builder();
}
@Override
protected JSIModulePackage getJSIModulePackage() {
return new JSIModulePackage() {
@Override
public List<JSIModuleSpec> getJSIModules(
final ReactApplicationContext reactApplicationContext,
final JavaScriptContextHolder jsContext) {
final List<JSIModuleSpec> specs = new ArrayList<>();
// Here we provide a new JSIModuleSpec that will be responsible of providing the
// custom Fabric Components.
specs.add(
new JSIModuleSpec() {
@Override
public JSIModuleType getJSIModuleType() {
return JSIModuleType.UIManager;
}
@Override
public JSIModuleProvider<UIManager> getJSIModuleProvider() {
final ComponentFactory componentFactory = new ComponentFactory();
CoreComponentsRegistry.register(componentFactory);
// Here we register a Components Registry.
// The one that is generated with the template contains no components
// and just provides you the one from React Native core.
MainComponentsRegistry.register(componentFactory);
final ReactInstanceManager reactInstanceManager = getReactInstanceManager();
ViewManagerRegistry viewManagerRegistry =
new ViewManagerRegistry(
reactInstanceManager.getOrCreateViewManagers(reactApplicationContext));
return new FabricJSIModuleProvider(
reactApplicationContext,
componentFactory,
ReactNativeConfig.DEFAULT_CONFIG,
viewManagerRegistry);
}
});
return specs;
}
};
}
}

View File

@ -0,0 +1,36 @@
package com.videoplayer.newarchitecture.components;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.fabric.ComponentFactory;
import com.facebook.soloader.SoLoader;
/**
* Class responsible to load the custom Fabric Components. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
@DoNotStrip
public class MainComponentsRegistry {
static {
SoLoader.loadLibrary("fabricjni");
}
@DoNotStrip private final HybridData mHybridData;
@DoNotStrip
private native HybridData initHybrid(ComponentFactory componentFactory);
@DoNotStrip
private MainComponentsRegistry(ComponentFactory componentFactory) {
mHybridData = initHybrid(componentFactory);
}
@DoNotStrip
public static MainComponentsRegistry register(ComponentFactory componentFactory) {
return new MainComponentsRegistry(componentFactory);
}
}

View File

@ -0,0 +1,48 @@
package com.videoplayer.newarchitecture.modules;
import com.facebook.jni.HybridData;
import com.facebook.react.ReactPackage;
import com.facebook.react.ReactPackageTurboModuleManagerDelegate;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.soloader.SoLoader;
import java.util.List;
/**
* Class responsible to load the TurboModules. This class has native methods and needs a
* corresponding C++ implementation/header file to work correctly (already placed inside the jni/
* folder for you).
*
* <p>Please note that this class is used ONLY if you opt-in for the New Architecture (see the
* `newArchEnabled` property). Is ignored otherwise.
*/
public class MainApplicationTurboModuleManagerDelegate
extends ReactPackageTurboModuleManagerDelegate {
private static volatile boolean sIsSoLibraryLoaded;
protected MainApplicationTurboModuleManagerDelegate(
ReactApplicationContext reactApplicationContext, List<ReactPackage> packages) {
super(reactApplicationContext, packages);
}
protected native HybridData initHybrid();
native boolean canCreateTurboModule(String moduleName);
public static class Builder extends ReactPackageTurboModuleManagerDelegate.Builder {
protected MainApplicationTurboModuleManagerDelegate build(
ReactApplicationContext context, List<ReactPackage> packages) {
return new MainApplicationTurboModuleManagerDelegate(context, packages);
}
}
@Override
protected synchronized void maybeLoadOtherSoLibraries() {
if (!sIsSoLibraryLoaded) {
// If you change the name of your application .so file in the Android.mk file,
// make sure you update the name here as well.
SoLoader.loadLibrary("videoplayer_appmodules");
sIsSoLibraryLoaded = true;
}
}
}

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.13)
# Define the library name here.
project(videoplayer_appmodules)
# This file includes all the necessary to let you build your application with the New Architecture.
include(${REACT_ANDROID_DIR}/cmake-utils/ReactNative-application.cmake)

View File

@ -0,0 +1,32 @@
#include "MainApplicationModuleProvider.h"
#include <rncli.h>
#include <rncore.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string &moduleName,
const JavaTurboModule::InitParams &params) {
// Here you can provide your own module provider for TurboModules coming from
// either your application or from external libraries. The approach to follow
// is similar to the following (for a library called `samplelibrary`:
//
// auto module = samplelibrary_ModuleProvider(moduleName, params);
// if (module != nullptr) {
// return module;
// }
// return rncore_ModuleProvider(moduleName, params);
// Module providers autolinked by RN CLI
auto rncli_module = rncli_ModuleProvider(moduleName, params);
if (rncli_module != nullptr) {
return rncli_module;
}
return rncore_ModuleProvider(moduleName, params);
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,16 @@
#pragma once
#include <memory>
#include <string>
#include <ReactCommon/JavaTurboModule.h>
namespace facebook {
namespace react {
std::shared_ptr<TurboModule> MainApplicationModuleProvider(
const std::string &moduleName,
const JavaTurboModule::InitParams &params);
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,45 @@
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainApplicationModuleProvider.h"
namespace facebook {
namespace react {
jni::local_ref<MainApplicationTurboModuleManagerDelegate::jhybriddata>
MainApplicationTurboModuleManagerDelegate::initHybrid(
jni::alias_ref<jhybridobject>) {
return makeCxxInstance();
}
void MainApplicationTurboModuleManagerDelegate::registerNatives() {
registerHybrid({
makeNativeMethod(
"initHybrid", MainApplicationTurboModuleManagerDelegate::initHybrid),
makeNativeMethod(
"canCreateTurboModule",
MainApplicationTurboModuleManagerDelegate::canCreateTurboModule),
});
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string &name,
const std::shared_ptr<CallInvoker> &jsInvoker) {
// Not implemented yet: provide pure-C++ NativeModules here.
return nullptr;
}
std::shared_ptr<TurboModule>
MainApplicationTurboModuleManagerDelegate::getTurboModule(
const std::string &name,
const JavaTurboModule::InitParams &params) {
return MainApplicationModuleProvider(name, params);
}
bool MainApplicationTurboModuleManagerDelegate::canCreateTurboModule(
const std::string &name) {
return getTurboModule(name, nullptr) != nullptr ||
getTurboModule(name, {.moduleName = name}) != nullptr;
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,38 @@
#include <memory>
#include <string>
#include <ReactCommon/TurboModuleManagerDelegate.h>
#include <fbjni/fbjni.h>
namespace facebook {
namespace react {
class MainApplicationTurboModuleManagerDelegate
: public jni::HybridClass<
MainApplicationTurboModuleManagerDelegate,
TurboModuleManagerDelegate> {
public:
// Adapt it to the package you used for your Java class.
static constexpr auto kJavaDescriptor =
"Lcom/videoplayer/newarchitecture/modules/MainApplicationTurboModuleManagerDelegate;";
static jni::local_ref<jhybriddata> initHybrid(jni::alias_ref<jhybridobject>);
static void registerNatives();
std::shared_ptr<TurboModule> getTurboModule(
const std::string &name,
const std::shared_ptr<CallInvoker> &jsInvoker) override;
std::shared_ptr<TurboModule> getTurboModule(
const std::string &name,
const JavaTurboModule::InitParams &params) override;
/**
* Test-only method. Allows user to verify whether a TurboModule can be
* created by instances of this class.
*/
bool canCreateTurboModule(const std::string &name);
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,65 @@
#include "MainComponentsRegistry.h"
#include <CoreComponentsRegistry.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/components/rncore/ComponentDescriptors.h>
#include <rncli.h>
namespace facebook {
namespace react {
MainComponentsRegistry::MainComponentsRegistry(ComponentFactory *delegate) {}
std::shared_ptr<ComponentDescriptorProviderRegistry const>
MainComponentsRegistry::sharedProviderRegistry() {
auto providerRegistry = CoreComponentsRegistry::sharedProviderRegistry();
// Autolinked providers registered by RN CLI
rncli_registerProviders(providerRegistry);
// Custom Fabric Components go here. You can register custom
// components coming from your App or from 3rd party libraries here.
//
// providerRegistry->add(concreteComponentDescriptorProvider<
// AocViewerComponentDescriptor>());
return providerRegistry;
}
jni::local_ref<MainComponentsRegistry::jhybriddata>
MainComponentsRegistry::initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate) {
auto instance = makeCxxInstance(delegate);
auto buildRegistryFunction =
[](EventDispatcher::Weak const &eventDispatcher,
ContextContainer::Shared const &contextContainer)
-> ComponentDescriptorRegistry::Shared {
auto registry = MainComponentsRegistry::sharedProviderRegistry()
->createComponentDescriptorRegistry(
{eventDispatcher, contextContainer});
auto mutableRegistry =
std::const_pointer_cast<ComponentDescriptorRegistry>(registry);
mutableRegistry->setFallbackComponentDescriptor(
std::make_shared<UnimplementedNativeViewComponentDescriptor>(
ComponentDescriptorParameters{
eventDispatcher, contextContainer, nullptr}));
return registry;
};
delegate->buildRegistryFunction = buildRegistryFunction;
return instance;
}
void MainComponentsRegistry::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", MainComponentsRegistry::initHybrid),
});
}
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,32 @@
#pragma once
#include <ComponentFactory.h>
#include <fbjni/fbjni.h>
#include <react/renderer/componentregistry/ComponentDescriptorProviderRegistry.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
namespace facebook {
namespace react {
class MainComponentsRegistry
: public facebook::jni::HybridClass<MainComponentsRegistry> {
public:
// Adapt it to the package you used for your Java class.
constexpr static auto kJavaDescriptor =
"Lcom/videoplayer/newarchitecture/components/MainComponentsRegistry;";
static void registerNatives();
MainComponentsRegistry(ComponentFactory *delegate);
private:
static std::shared_ptr<ComponentDescriptorProviderRegistry const>
sharedProviderRegistry();
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
ComponentFactory *delegate);
};
} // namespace react
} // namespace facebook

View File

@ -0,0 +1,11 @@
#include <fbjni/fbjni.h>
#include "MainApplicationTurboModuleManagerDelegate.h"
#include "MainComponentsRegistry.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
facebook::react::MainApplicationTurboModuleManagerDelegate::
registerNatives();
facebook::react::MainComponentsRegistry::registerNatives();
});
}

View File

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2014 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.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="@dimen/abc_edit_text_inset_horizontal_material"
android:insetRight="@dimen/abc_edit_text_inset_horizontal_material"
android:insetTop="@dimen/abc_edit_text_inset_top_material"
android:insetBottom="@dimen/abc_edit_text_inset_bottom_material">
<selector>
<!--
This file is a copy of abc_edit_text_material (https://bit.ly/3k8fX7I).
The item below with state_pressed="false" and state_focused="false" causes a NullPointerException.
NullPointerException:tempt to invoke virtual method 'android.graphics.drawable.Drawable android.graphics.drawable.Drawable$ConstantState.newDrawable(android.content.res.Resources)'
<item android:state_pressed="false" android:state_focused="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
For more info, see https://bit.ly/3CdLStv (react-native/pull/29452) and https://bit.ly/3nxOMoR.
-->
<item android:state_enabled="false" android:drawable="@drawable/abc_textfield_default_mtrl_alpha"/>
<item android:drawable="@drawable/abc_textfield_activated_mtrl_alpha"/>
</selector>
</inset>

View File

@ -1,9 +1,9 @@
<resources> <resources>
<!-- Base application theme. --> <!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> <style name="AppTheme" parent="Theme.AppCompat.DayNight.NoActionBar">
<!-- Customize your theme here. --> <!-- Customize your theme here. -->
<item name="android:textColor">#000000</item> <item name="android:editTextBackground">@drawable/rn_edit_text_material</item>
</style> </style>
</resources> </resources>

View File

@ -2,17 +2,27 @@
buildscript { buildscript {
ext { ext {
buildToolsVersion = "30.0.2" buildToolsVersion = "31.0.0"
minSdkVersion = 21 minSdkVersion = 21
compileSdkVersion = 31 compileSdkVersion = 31
targetSdkVersion = 29 targetSdkVersion = 31
if (System.properties['os.arch'] == "aarch64") {
// For M1 Users we need to use the NDK 24 which added support for aarch64
ndkVersion = "24.0.8215888"
} else {
// Otherwise we default to the side-by-side NDK version from AGP.
ndkVersion = "21.4.7075529"
}
} }
repositories { repositories {
google() google()
jcenter() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:4.2.2") classpath("com.android.tools.build:gradle:7.2.1")
classpath("com.facebook.react:react-native-gradle-plugin")
classpath("de.undercouch:gradle-download-task:5.0.1")
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files
} }
@ -20,7 +30,6 @@ buildscript {
allprojects { allprojects {
repositories { repositories {
mavenLocal()
maven { maven {
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
url("$rootDir/../node_modules/react-native/android") url("$rootDir/../node_modules/react-native/android")
@ -29,9 +38,14 @@ allprojects {
// Android JSC is installed from npm // Android JSC is installed from npm
url("$rootDir/../node_modules/jsc-android/dist") 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() google()
jcenter()
maven { url 'https://www.jitpack.io' } maven { url 'https://www.jitpack.io' }
} }
} }

View File

@ -9,8 +9,8 @@
# Specifies the JVM arguments used for the daemon process. # Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings. # The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m # Default value: -Xmx512m -XX:MaxMetaspaceSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m
# When configured, Gradle will run in incubating parallel mode. # When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit # This option should only be used with decoupled projects. More details, visit
@ -25,4 +25,16 @@ android.useAndroidX=true
android.enableJetifier=true android.enableJetifier=true
# Version of flipper SDK to use with React Native # Version of flipper SDK to use with React Native
FLIPPER_VERSION=0.54.0 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 <task> -PreactNativeArchitectures=x86_64
reactNativeArchitectures=armeabi-v7a,arm64-v8a,x86,x86_64
# Use this property to enable support to the new architecture.
# This will allow you to use TurboModules and the Fabric render in
# your application. You should enable this flag either if you want
# to write custom TurboModules/Fabric components OR use libraries that
# are providing them.
newArchEnabled=false

View File

@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists

View File

@ -1,7 +1,7 @@
#!/usr/bin/env sh #!/bin/sh
# #
# Copyright 2015 the original author or authors. # Copyright © 2015-2021 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -17,78 +17,113 @@
# #
############################################################################## ##############################################################################
## #
## Gradle start up script for UN*X # Gradle start up script for POSIX generated by Gradle.
## #
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# 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
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
############################################################################## ##############################################################################
# Attempt to set APP_HOME # Attempt to set APP_HOME
# Resolve links: $0 may be a link # Resolve links: $0 may be a link
PRG="$0" app_path=$0
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do # Need this for daisy-chained symlinks.
ls=`ls -ld "$PRG"` while
link=`expr "$ls" : '.*-> \(.*\)$'` APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
if expr "$link" : '/.*' > /dev/null; then [ -h "$app_path" ]
PRG="$link" do
else ls=$( ls -ld "$app_path" )
PRG=`dirname "$PRG"`"/$link" link=${ls#*' -> '}
fi case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle" APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"` 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. # 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"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum" MAX_FD=maximum
warn () { warn () {
echo "$*" echo "$*"
} } >&2
die () { die () {
echo echo
echo "$*" echo "$*"
echo echo
exit 1 exit 1
} } >&2
# OS specific support (must be 'true' or 'false'). # OS specific support (must be 'true' or 'false').
cygwin=false cygwin=false
msys=false msys=false
darwin=false darwin=false
nonstop=false nonstop=false
case "`uname`" in case "$( uname )" in #(
CYGWIN* ) CYGWIN* ) cygwin=true ;; #(
cygwin=true Darwin* ) darwin=true ;; #(
;; MSYS* | MINGW* ) msys=true ;; #(
Darwin* ) NONSTOP* ) nonstop=true ;;
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables # IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java" JAVACMD=$JAVA_HOME/jre/sh/java
else else
JAVACMD="$JAVA_HOME/bin/java" JAVACMD=$JAVA_HOME/bin/java
fi fi
if [ ! -x "$JAVACMD" ] ; then if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation." location of your Java installation."
fi fi
else else
JAVACMD="java" 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. which java >/dev/null 2>&1 || 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 Please set the JAVA_HOME variable in your environment to match the
@ -105,79 +140,95 @@ location of your Java installation."
fi fi
# Increase the maximum file descriptors if we can. # Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
MAX_FD_LIMIT=`ulimit -H -n` case $MAX_FD in #(
if [ $? -eq 0 ] ; then max*)
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then MAX_FD=$( ulimit -H -n ) ||
MAX_FD="$MAX_FD_LIMIT" warn "Could not query maximum file descriptor limit"
fi esac
ulimit -n $MAX_FD case $MAX_FD in #(
if [ $? -ne 0 ] ; then '' | soft) :;; #(
warn "Could not set maximum file descriptor limit: $MAX_FD" *)
fi ulimit -n "$MAX_FD" ||
else warn "Could not set maximum file descriptor limit to $MAX_FD"
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac esac
fi fi
# Escape application args # Collect all arguments for the java command, stacking in reverse order:
save () { # * args from the command line
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done # * the main class name
echo " " # * -classpath
} # * -D...appname settings
APP_ARGS=`save "$@"` # * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules # For Cygwin or MSYS, switch paths to Windows format before running java
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# 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
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@" exec "$JAVACMD" "$@"

View File

@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@ -64,28 +64,14 @@ echo location of your Java installation.
goto fail goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@ -1,5 +1,11 @@
rootProject.name = 'VideoPlayer' rootProject.name = 'videoplayer'
apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings) apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
include ':app' include ':app'
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')
}

View File

@ -3,14 +3,14 @@ module.exports = {
plugins: [ plugins: [
[ [
'module-resolver', 'module-resolver',
{ {
extensions: ['.js', '.tsx', '.ts'], extensions: ['.js', '.tsx', '.ts'],
root: ['./src'], root: ['./src'],
alias: { alias: {
src: './src', src: './src',
},
}, },
},
], ],
], ],
}; };

View File

@ -1,26 +1,43 @@
require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
platform :ios, '10.0' platform :ios, '12.4'
use_frameworks! :linkage => :static install! 'cocoapods', :deterministic_uuids => false
target 'VideoPlayer' do target 'videoplayer' do
config = use_native_modules! config = use_native_modules!
use_react_native!(:path => config["reactNativePath"]) # Flags change depending on the env values.
flags = get_default_flags()
target 'VideoPlayerTests' do 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,
# An absolute path to your application root.
:app_path => "#{Pod::Config.instance.installation_root}/.."
)
target 'videoplayerTests' do
inherit! :complete inherit! :complete
# Pods for testing # Pods for testing
end end
end post_install do |installer|
react_native_post_install(
target 'VideoPlayer-tvOS' do installer,
# Pods for VideoPlayer-tvOS # Set `mac_catalyst_enabled` to `true` in order to apply patches
# necessary for Mac Catalyst builds
target 'VideoPlayer-tvOSTests' do :mac_catalyst_enabled => false
inherit! :search_paths )
# Pods for testing __apply_Xcode_12_5_M1_post_install_workaround(installer)
end end
end end

View File

@ -1,392 +0,0 @@
PODS:
- boost-for-react-native (1.63.0)
- DoubleConversion (1.1.6)
- FBLazyVector (0.63.4)
- FBReactNativeSpec (0.63.4):
- Folly (= 2020.01.13.00)
- RCTRequired (= 0.63.4)
- RCTTypeSafety (= 0.63.4)
- React-Core (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- Folly (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
- Folly/Default (= 2020.01.13.00)
- glog
- Folly/Default (2020.01.13.00):
- boost-for-react-native
- DoubleConversion
- glog
- glog (0.3.5)
- PromisesObjC (2.0.0)
- PromisesSwift (2.0.0):
- PromisesObjC (= 2.0.0)
- RCTRequired (0.63.4)
- RCTTypeSafety (0.63.4):
- FBLazyVector (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTRequired (= 0.63.4)
- React-Core (= 0.63.4)
- React (0.63.4):
- React-Core (= 0.63.4)
- React-Core/DevSupport (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-RCTActionSheet (= 0.63.4)
- React-RCTAnimation (= 0.63.4)
- React-RCTBlob (= 0.63.4)
- React-RCTImage (= 0.63.4)
- React-RCTLinking (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- React-RCTSettings (= 0.63.4)
- React-RCTText (= 0.63.4)
- React-RCTVibration (= 0.63.4)
- React-callinvoker (0.63.4)
- React-Core (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/CoreModulesHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/Default (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/DevSupport (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- React-jsinspector (= 0.63.4)
- Yoga
- React-Core/RCTActionSheetHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTAnimationHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTBlobHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTImageHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTLinkingHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTNetworkHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTSettingsHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTTextHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTVibrationHeaders (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-Core/RCTWebSocket (0.63.4):
- Folly (= 2020.01.13.00)
- glog
- React-Core/Default (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsiexecutor (= 0.63.4)
- Yoga
- React-CoreModules (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/CoreModulesHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTImage (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-cxxreact (0.63.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-callinvoker (= 0.63.4)
- React-jsinspector (= 0.63.4)
- React-jsi (0.63.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-jsi/Default (= 0.63.4)
- React-jsi/Default (0.63.4):
- boost-for-react-native (= 1.63.0)
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-jsiexecutor (0.63.4):
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- React-jsinspector (0.63.4)
- react-native-video (6.0.0-alpha1):
- React-Core
- react-native-video/Video (= 6.0.0-alpha1)
- react-native-video/Video (6.0.0-alpha1):
- PromisesSwift
- React-Core
- React-RCTActionSheet (0.63.4):
- React-Core/RCTActionSheetHeaders (= 0.63.4)
- React-RCTAnimation (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTAnimationHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTBlob (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- React-Core/RCTBlobHeaders (= 0.63.4)
- React-Core/RCTWebSocket (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTImage (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTImageHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- React-RCTNetwork (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTLinking (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- React-Core/RCTLinkingHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTNetwork (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTNetworkHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTSettings (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- RCTTypeSafety (= 0.63.4)
- React-Core/RCTSettingsHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- React-RCTText (0.63.4):
- React-Core/RCTTextHeaders (= 0.63.4)
- React-RCTVibration (0.63.4):
- FBReactNativeSpec (= 0.63.4)
- Folly (= 2020.01.13.00)
- React-Core/RCTVibrationHeaders (= 0.63.4)
- React-jsi (= 0.63.4)
- ReactCommon/turbomodule/core (= 0.63.4)
- ReactCommon/turbomodule/core (0.63.4):
- DoubleConversion
- Folly (= 2020.01.13.00)
- glog
- React-callinvoker (= 0.63.4)
- React-Core (= 0.63.4)
- React-cxxreact (= 0.63.4)
- React-jsi (= 0.63.4)
- RNCPicker (1.16.8):
- React-Core
- Yoga (1.14.0)
DEPENDENCIES:
- 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/Libraries/FBReactNativeSpec`)
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
- glog (from `../node_modules/react-native/third-party-podspecs/glog.podspec`)
- RCTRequired (from `../node_modules/react-native/Libraries/RCTRequired`)
- RCTTypeSafety (from `../node_modules/react-native/Libraries/TypeSafety`)
- React (from `../node_modules/react-native/`)
- React-callinvoker (from `../node_modules/react-native/ReactCommon/callinvoker`)
- 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-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-native-video (from `../node_modules/react-native-video`)
- React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`)
- React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`)
- React-RCTBlob (from `../node_modules/react-native/Libraries/Blob`)
- React-RCTImage (from `../node_modules/react-native/Libraries/Image`)
- React-RCTLinking (from `../node_modules/react-native/Libraries/LinkingIOS`)
- React-RCTNetwork (from `../node_modules/react-native/Libraries/Network`)
- 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`)
- 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:
- boost-for-react-native
- PromisesObjC
- PromisesSwift
EXTERNAL SOURCES:
DoubleConversion:
:podspec: "../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec"
FBLazyVector:
:path: "../node_modules/react-native/Libraries/FBLazyVector"
FBReactNativeSpec:
:path: "../node_modules/react-native/Libraries/FBReactNativeSpec"
Folly:
:podspec: "../node_modules/react-native/third-party-podspecs/Folly.podspec"
glog:
:podspec: "../node_modules/react-native/third-party-podspecs/glog.podspec"
RCTRequired:
:path: "../node_modules/react-native/Libraries/RCTRequired"
RCTTypeSafety:
:path: "../node_modules/react-native/Libraries/TypeSafety"
React:
:path: "../node_modules/react-native/"
React-callinvoker:
:path: "../node_modules/react-native/ReactCommon/callinvoker"
React-Core:
:path: "../node_modules/react-native/"
React-CoreModules:
:path: "../node_modules/react-native/React/CoreModules"
React-cxxreact:
:path: "../node_modules/react-native/ReactCommon/cxxreact"
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"
react-native-video:
:path: "../node_modules/react-native-video"
React-RCTActionSheet:
:path: "../node_modules/react-native/Libraries/ActionSheetIOS"
React-RCTAnimation:
:path: "../node_modules/react-native/Libraries/NativeAnimation"
React-RCTBlob:
:path: "../node_modules/react-native/Libraries/Blob"
React-RCTImage:
:path: "../node_modules/react-native/Libraries/Image"
React-RCTLinking:
:path: "../node_modules/react-native/Libraries/LinkingIOS"
React-RCTNetwork:
:path: "../node_modules/react-native/Libraries/Network"
React-RCTSettings:
:path: "../node_modules/react-native/Libraries/Settings"
React-RCTText:
:path: "../node_modules/react-native/Libraries/Text"
React-RCTVibration:
:path: "../node_modules/react-native/Libraries/Vibration"
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-for-react-native: 39c7adb57c4e60d6c5479dd8623128eb5b3f0f2c
DoubleConversion: cde416483dac037923206447da6e1454df403714
FBLazyVector: 3bb422f41b18121b71783a905c10e58606f7dc3e
FBReactNativeSpec: f2c97f2529dd79c083355182cc158c9f98f4bd6e
Folly: b73c3869541e86821df3c387eb0af5f65addfab4
glog: 40a13f7840415b9a77023fbcae0f1e6f43192af3
PromisesObjC: 68159ce6952d93e17b2dfe273b8c40907db5ba58
PromisesSwift: e0b2a6433469efb0b83a2b84c62a2abab8e5e5d4
RCTRequired: 082f10cd3f905d6c124597fd1c14f6f2655ff65e
RCTTypeSafety: 8c9c544ecbf20337d069e4ae7fd9a377aadf504b
React: b0a957a2c44da4113b0c4c9853d8387f8e64e615
React-callinvoker: c3f44dd3cb195b6aa46621fff95ded79d59043fe
React-Core: d3b2a1ac9a2c13c3bcde712d9281fc1c8a5b315b
React-CoreModules: 0581ff36cb797da0943d424f69e7098e43e9be60
React-cxxreact: c1480d4fda5720086c90df537ee7d285d4c57ac3
React-jsi: a0418934cf48f25b485631deb27c64dc40fb4c31
React-jsiexecutor: 93bd528844ad21dc07aab1c67cb10abae6df6949
React-jsinspector: 58aef7155bc9a9683f5b60b35eccea8722a4f53a
react-native-video: 7ce6d16e47b8a6a1ccdc5d9f4f3ce50e42acaf3b
React-RCTActionSheet: 89a0ca9f4a06c1f93c26067af074ccdce0f40336
React-RCTAnimation: 1bde3ecc0c104c55df246eda516e0deb03c4e49b
React-RCTBlob: a97d378b527740cc667e03ebfa183a75231ab0f0
React-RCTImage: c1b1f2d3f43a4a528c8946d6092384b5c880d2f0
React-RCTLinking: 35ae4ab9dc0410d1fcbdce4d7623194a27214fb2
React-RCTNetwork: 29ec2696f8d8cfff7331fac83d3e893c95ef43ae
React-RCTSettings: 60f0691bba2074ef394f95d4c2265ec284e0a46a
React-RCTText: 5c51df3f08cb9dedc6e790161195d12bac06101c
React-RCTVibration: ae4f914cfe8de7d4de95ae1ea6cc8f6315d73d9d
ReactCommon: 73d79c7039f473b76db6ff7c6b159c478acbbb3b
RNCPicker: 0991c56da7815c0cf946d6f63cf920b25296e5f6
Yoga: 4bd86afe9883422a7c4028c00e34790f560923d6
PODFILE CHECKSUM: 51ba394e28c02b1e60e7686b5b2926921af36c49
COCOAPODS: 1.11.2

View File

@ -1,12 +0,0 @@
//
// VideoPlayer-Bridging-Header.h
// VideoPlayer
//
// Created by nick fujita on 2/1/22.
//
#ifndef VideoPlayer_Bridging_Header_h
#define VideoPlayer_Bridging_Header_h
#endif /* VideoPlayer_Bridging_Header_h */

File diff suppressed because it is too large Load Diff

View File

@ -1,88 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1130"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "VideoPlayer-tvOS.app"
BlueprintName = "VideoPlayer-tvOS"
ReferencedContainer = "container:VideoPlayer.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E48F1E0B4A5D006451C7"
BuildableName = "VideoPlayer-tvOSTests.xctest"
BlueprintName = "VideoPlayer-tvOSTests"
ReferencedContainer = "container:VideoPlayer.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "VideoPlayer-tvOS.app"
BlueprintName = "VideoPlayer-tvOS"
ReferencedContainer = "container:VideoPlayer.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2D02E47A1E0B4A5D006451C7"
BuildableName = "VideoPlayer-tvOS.app"
BlueprintName = "VideoPlayer-tvOS"
ReferencedContainer = "container:VideoPlayer.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:VideoPlayer.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -1,17 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

View File

@ -1,67 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
static void InitializeFlipper(UIApplication *application) {
FlipperClient *client = [FlipperClient sharedClient];
SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults];
[client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]];
[client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]];
[client addPlugin:[FlipperKitReactPlugin new]];
[client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]];
[client start];
}
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef FB_SONARKIT_ENABLED
InitializeFlipper(application);
#endif
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
moduleName:@"VideoPlayer"
initialProperties:nil];
rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"src/index" fallbackResource:nil];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
@end

View File

@ -1 +0,0 @@
import Foundation

View File

@ -1,38 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleDisplayName</key>
<string>VideoPlayer</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
<key>NSExceptionDomains</key>
<dict>
<key>localhost</key>
<dict>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>

View File

@ -1,18 +0,0 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@ -0,0 +1,11 @@
# This `.xcode.env` file is versioned and is used to source the environment
# used when running script phases inside Xcode.
# To customize your local environment, you can create an `.xcode.env.local`
# file that is not versioned.
# NODE_BINARY variable contains the PATH to the node executable.
#
# Customize the NODE_BINARY variable here.
# For example, to use nvm with brew, add the following line
# . "$(brew --prefix nvm)/nvm.sh" --no-use
export NODE_BINARY=$(command -v node)

View File

@ -0,0 +1,700 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objects = {
/* Begin PBXBuildFile section */
00E356F31AD99517003FC87E /* videoplayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* videoplayerTests.m */; };
0C80B921A6F3F58F76C31292 /* libPods-videoplayer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DCACB8F33CDC322A6C60F78 /* libPods-videoplayer.a */; };
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 */; };
7699B88040F8A987B510C191 /* libPods-videoplayer-videoplayerTests.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 19F6CBCC0A4E27FBF8BF4A61 /* libPods-videoplayer-videoplayerTests.a */; };
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = videoplayer;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
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 = "<group>"; };
00E356F21AD99517003FC87E /* videoplayerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = videoplayerTests.m; sourceTree = "<group>"; };
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 = "<group>"; };
13B07FB01A68108700A75B9A /* AppDelegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = AppDelegate.mm; path = videoplayer/AppDelegate.mm; sourceTree = "<group>"; };
13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = videoplayer/Images.xcassets; sourceTree = "<group>"; };
13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = videoplayer/Info.plist; sourceTree = "<group>"; };
13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = videoplayer/main.m; sourceTree = "<group>"; };
19F6CBCC0A4E27FBF8BF4A61 /* libPods-videoplayer-videoplayerTests.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-videoplayer-videoplayerTests.a"; sourceTree = BUILT_PRODUCTS_DIR; };
3B4392A12AC88292D35C810B /* 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 = "<group>"; };
5709B34CF0A7D63546082F79 /* 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 = "<group>"; };
5B7EB9410499542E8C5724F5 /* 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 = "<group>"; };
5DCACB8F33CDC322A6C60F78 /* libPods-videoplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-videoplayer.a"; sourceTree = BUILT_PRODUCTS_DIR; };
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = videoplayer/LaunchScreen.storyboard; sourceTree = "<group>"; };
89C6BE57DB24E9ADA2F236DE /* 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 = "<group>"; };
ED297162215061F000B7C4FE /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = JavaScriptCore.framework; path = System/Library/Frameworks/JavaScriptCore.framework; sourceTree = SDKROOT; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00E356EB1AD99517003FC87E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
7699B88040F8A987B510C191 /* libPods-videoplayer-videoplayerTests.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0C80B921A6F3F58F76C31292 /* libPods-videoplayer.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00E356EF1AD99517003FC87E /* videoplayerTests */ = {
isa = PBXGroup;
children = (
00E356F21AD99517003FC87E /* videoplayerTests.m */,
00E356F01AD99517003FC87E /* Supporting Files */,
);
path = videoplayerTests;
sourceTree = "<group>";
};
00E356F01AD99517003FC87E /* Supporting Files */ = {
isa = PBXGroup;
children = (
00E356F11AD99517003FC87E /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* videoplayer */ = {
isa = PBXGroup;
children = (
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */,
13B07FB71A68108700A75B9A /* main.m */,
);
name = videoplayer;
sourceTree = "<group>";
};
2D16E6871FA4F8E400B85C8A /* Frameworks */ = {
isa = PBXGroup;
children = (
ED297162215061F000B7C4FE /* JavaScriptCore.framework */,
5DCACB8F33CDC322A6C60F78 /* libPods-videoplayer.a */,
19F6CBCC0A4E27FBF8BF4A61 /* libPods-videoplayer-videoplayerTests.a */,
);
name = Frameworks;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
);
name = Libraries;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* videoplayer */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* videoplayerTests */,
83CBBA001A601CBA00E9B192 /* Products */,
2D16E6871FA4F8E400B85C8A /* Frameworks */,
BBD78D7AC51CEA395F1C20DB /* Pods */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
usesTabs = 0;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* videoplayer.app */,
00E356EE1AD99517003FC87E /* videoplayerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
BBD78D7AC51CEA395F1C20DB /* Pods */ = {
isa = PBXGroup;
children = (
3B4392A12AC88292D35C810B /* Pods-videoplayer.debug.xcconfig */,
5709B34CF0A7D63546082F79 /* Pods-videoplayer.release.xcconfig */,
5B7EB9410499542E8C5724F5 /* Pods-videoplayer-videoplayerTests.debug.xcconfig */,
89C6BE57DB24E9ADA2F236DE /* Pods-videoplayer-videoplayerTests.release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* videoplayerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "videoplayerTests" */;
buildPhases = (
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */,
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* Resources */,
C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */,
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
00E356F51AD99517003FC87E /* PBXTargetDependency */,
);
name = videoplayerTests;
productName = videoplayerTests;
productReference = 00E356EE1AD99517003FC87E /* videoplayerTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
13B07F861A680F5B00A75B9A /* videoplayer */ = {
isa = PBXNativeTarget;
buildConfigurationList = 13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "videoplayer" */;
buildPhases = (
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */,
FD10A7F022414F080027D42C /* Start Packager */,
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */,
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = videoplayer;
productName = videoplayer;
productReference = 13B07F961A680F5B00A75B9A /* videoplayer.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1210;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
13B07F861A680F5B00A75B9A = {
LastSwiftMigration = 1120;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "videoplayer" */;
compatibilityVersion = "Xcode 12.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* videoplayer */,
00E356ED1AD99517003FC87E /* videoplayerTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */,
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"$(SRCROOT)/.xcode.env.local",
"$(SRCROOT)/.xcode.env",
);
name = "Bundle React Native code and images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "set -e\n\nWITH_ENVIRONMENT=\"../node_modules/react-native/scripts/xcode/with-environment.sh\"\nREACT_NATIVE_XCODE=\"../node_modules/react-native/scripts/react-native-xcode.sh\"\n\n/bin/sh -c \"$WITH_ENVIRONMENT $REACT_NATIVE_XCODE\"\n";
};
00EEFC60759A1932668264C0 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-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",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
A55EABD7B0C7F3A422A6CC61 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-videoplayer-videoplayerTests-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;
};
C38B50BA6285516D6DCD4F65 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(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;
};
C59DA0FBD6956966B86A3779 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${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-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer-videoplayerTests/Pods-videoplayer-videoplayerTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
E235C05ADACE081382539298 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-input-files.xcfilelist",
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources-${CONFIGURATION}-output-files.xcfilelist",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-videoplayer/Pods-videoplayer-resources.sh\"\n";
showEnvVarsInLog = 0;
};
F6A41C54EA430FDDC6A6ED99 /* [CP] Copy Pods Resources */ = {
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";
outputFileListPaths = (
"${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-resources.sh\"\n";
showEnvVarsInLog = 0;
};
FD10A7F022414F080027D42C /* Start Packager */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Start Packager";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export RCT_METRO_PORT=\"${RCT_METRO_PORT:=8081}\"\necho \"export RCT_METRO_PORT=${RCT_METRO_PORT}\" > \"${SRCROOT}/../node_modules/react-native/scripts/.packager.env\"\nif [ -z \"${RCT_NO_LAUNCH_PACKAGER+xxx}\" ] ; then\n if nc -w 5 -z localhost ${RCT_METRO_PORT} ; then\n if ! curl -s \"http://localhost:${RCT_METRO_PORT}/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port ${RCT_METRO_PORT} already in use, packager is either not running or not running correctly\"\n exit 2\n fi\n else\n open \"$SRCROOT/../node_modules/react-native/scripts/launchPackager.command\" || echo \"Can't start packager automatically\"\n fi\nfi\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
00E356EA1AD99517003FC87E /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
00E356F31AD99517003FC87E /* videoplayerTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F871A680F5B00A75B9A /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */,
13B07FC11A68108700A75B9A /* main.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
00E356F51AD99517003FC87E /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 13B07F861A680F5B00A75B9A /* videoplayer */;
targetProxy = 00E356F41AD99517003FC87E /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5B7EB9410499542E8C5724F5 /* Pods-videoplayer-videoplayerTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = videoplayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/videoplayer.app/videoplayer";
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 89C6BE57DB24E9ADA2F236DE /* Pods-videoplayer-videoplayerTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
INFOPLIST_FILE = videoplayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
OTHER_LDFLAGS = (
"-ObjC",
"-lc++",
"$(inherited)",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/videoplayer.app/videoplayer";
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3B4392A12AC88292D35C810B /* Pods-videoplayer.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = videoplayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = videoplayer;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 5709B34CF0A7D63546082F79 /* Pods-videoplayer.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CURRENT_PROJECT_VERSION = 1;
INFOPLIST_FILE = videoplayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
"-lc++",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = videoplayer;
SWIFT_VERSION = 5.0;
VERSIONING_SYSTEM = "apple-generic";
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(SDKROOT)/usr/lib/swift\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "";
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 12.4;
LD_RUNPATH_SEARCH_PATHS = (
/usr/lib/swift,
"$(inherited)",
);
LIBRARY_SEARCH_PATHS = (
"\"$(SDKROOT)/usr/lib/swift\"",
"\"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)\"",
"\"$(inherited)\"",
);
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_CPLUSPLUSFLAGS = (
"$(OTHER_CFLAGS)",
"-DFOLLY_NO_CONFIG",
"-DFOLLY_MOBILE=1",
"-DFOLLY_USE_LIBCPP=1",
);
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "videoplayerTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
00E356F61AD99517003FC87E /* Debug */,
00E356F71AD99517003FC87E /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
13B07F931A680F5B00A75B9A /* Build configuration list for PBXNativeTarget "videoplayer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
13B07F941A680F5B00A75B9A /* Debug */,
13B07F951A680F5B00A75B9A /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "videoplayer" */ = {
isa = XCConfigurationList;
buildConfigurations = (
83CBBA201A601CBA00E9B192 /* Debug */,
83CBBA211A601CBA00E9B192 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 83CBB9F71A601CBA00E9B192 /* Project object */;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "1130" LastUpgradeVersion = "1210"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -15,9 +15,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "VideoPlayer.app" BuildableName = "videoplayer.app"
BlueprintName = "VideoPlayer" BlueprintName = "videoplayer"
ReferencedContainer = "container:VideoPlayer.xcodeproj"> ReferencedContainer = "container:videoplayer.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildActionEntry> </BuildActionEntry>
</BuildActionEntries> </BuildActionEntries>
@ -33,9 +33,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "00E356ED1AD99517003FC87E" BlueprintIdentifier = "00E356ED1AD99517003FC87E"
BuildableName = "VideoPlayerTests.xctest" BuildableName = "videoplayerTests.xctest"
BlueprintName = "VideoPlayerTests" BlueprintName = "videoplayerTests"
ReferencedContainer = "container:VideoPlayer.xcodeproj"> ReferencedContainer = "container:videoplayer.xcodeproj">
</BuildableReference> </BuildableReference>
</TestableReference> </TestableReference>
</Testables> </Testables>
@ -55,9 +55,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "VideoPlayer.app" BuildableName = "videoplayer.app"
BlueprintName = "VideoPlayer" BlueprintName = "videoplayer"
ReferencedContainer = "container:VideoPlayer.xcodeproj"> ReferencedContainer = "container:videoplayer.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</LaunchAction> </LaunchAction>
@ -72,9 +72,9 @@
<BuildableReference <BuildableReference
BuildableIdentifier = "primary" BuildableIdentifier = "primary"
BlueprintIdentifier = "13B07F861A680F5B00A75B9A" BlueprintIdentifier = "13B07F861A680F5B00A75B9A"
BuildableName = "VideoPlayer.app" BuildableName = "videoplayer.app"
BlueprintName = "VideoPlayer" BlueprintName = "videoplayer"
ReferencedContainer = "container:VideoPlayer.xcodeproj"> ReferencedContainer = "container:videoplayer.xcodeproj">
</BuildableReference> </BuildableReference>
</BuildableProductRunnable> </BuildableProductRunnable>
</ProfileAction> </ProfileAction>

View File

@ -0,0 +1,8 @@
#import <React/RCTBridgeDelegate.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate, RCTBridgeDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

View File

@ -0,0 +1,133 @@
#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <React/RCTAppSetupUtils.h>
#if RCT_NEW_ARCH_ENABLED
#import <React/CoreModulesPlugins.h>
#import <React/RCTCxxBridgeDelegate.h>
#import <React/RCTFabricSurfaceHostingProxyRootView.h>
#import <React/RCTSurfacePresenter.h>
#import <React/RCTSurfacePresenterBridgeAdapter.h>
#import <ReactCommon/RCTTurboModuleManager.h>
#import <react/config/ReactNativeConfig.h>
static NSString *const kRNConcurrentRoot = @"concurrentRoot";
@interface AppDelegate () <RCTCxxBridgeDelegate, RCTTurboModuleManagerDelegate> {
RCTTurboModuleManager *_turboModuleManager;
RCTSurfacePresenterBridgeAdapter *_bridgeAdapter;
std::shared_ptr<const facebook::react::ReactNativeConfig> _reactNativeConfig;
facebook::react::ContextContainer::Shared _contextContainer;
}
@end
#endif
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
RCTAppSetupPrepareApp(application);
RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
#if RCT_NEW_ARCH_ENABLED
_contextContainer = std::make_shared<facebook::react::ContextContainer const>();
_reactNativeConfig = std::make_shared<facebook::react::EmptyReactNativeConfig const>();
_contextContainer->insert("ReactNativeConfig", _reactNativeConfig);
_bridgeAdapter = [[RCTSurfacePresenterBridgeAdapter alloc] initWithBridge:bridge contextContainer:_contextContainer];
bridge.surfacePresenter = _bridgeAdapter.surfacePresenter;
#endif
NSDictionary *initProps = [self prepareInitialProps];
UIView *rootView = RCTAppSetupDefaultRootView(bridge, @"videoplayer", initProps);
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;
}
- (NSDictionary *)prepareInitialProps
{
NSMutableDictionary *initProps = [NSMutableDictionary new];
#ifdef RCT_NEW_ARCH_ENABLED
initProps[kRNConcurrentRoot] = @([self concurrentRootEnabled]);
#endif
return initProps;
}
- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index"];
#else
return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
#endif
}
#if RCT_NEW_ARCH_ENABLED
#pragma mark - RCTCxxBridgeDelegate
- (std::unique_ptr<facebook::react::JSExecutorFactory>)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<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
jsInvoker:(std::shared_ptr<facebook::react::CallInvoker>)jsInvoker
{
return nullptr;
}
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:(const std::string &)name
initParams:
(const facebook::react::ObjCTurboModule::InitParams &)params
{
return nullptr;
}
- (id<RCTTurboModule>)getModuleInstanceFromClass:(Class)moduleClass
{
return RCTAppSetupDefaultModuleFromClass(moduleClass);
}
#endif
@end

View File

@ -0,0 +1,53 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -4,6 +4,8 @@
<dict> <dict>
<key>CFBundleDevelopmentRegion</key> <key>CFBundleDevelopmentRegion</key>
<string>en</string> <string>en</string>
<key>CFBundleDisplayName</key>
<string>videoplayer</string>
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>

View File

@ -16,32 +16,21 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="obG-Y5-kRd"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="videoplayer" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="647" width="375" height="0.0"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="VideoPlayer" textAlignment="center" lineBreakMode="middleTruncation" baselineAdjustment="alignBaselines" minimumFontSize="18" translatesAutoresizingMaskIntoConstraints="NO" id="GJd-Yh-RWb">
<rect key="frame" x="0.0" y="202" width="375" height="43"/> <rect key="frame" x="0.0" y="202" width="375" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/> <fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu"> <label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Powered by React Native" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="MN2-I3-ftu">
<rect key="frame" x="0.0" y="626" width="375" height="21"/> <rect key="frame" x="0.0" y="626" width="375" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<constraints> <constraints>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="obG-Y5-kRd" secondAttribute="centerX" id="5cz-MP-9tL"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/> <constraint firstItem="Bcu-3y-fUS" firstAttribute="bottom" secondItem="MN2-I3-ftu" secondAttribute="bottom" constant="20" id="OZV-Vh-mqD"/>
<constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/> <constraint firstItem="Bcu-3y-fUS" firstAttribute="centerX" secondItem="GJd-Yh-RWb" secondAttribute="centerX" id="Q3B-4B-g5h"/>
<constraint firstItem="obG-Y5-kRd" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" symbolic="YES" id="SfN-ll-jLj"/>
<constraint firstAttribute="bottom" secondItem="obG-Y5-kRd" secondAttribute="bottom" constant="20" id="Y44-ml-fuU"/>
<constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/> <constraint firstItem="MN2-I3-ftu" firstAttribute="centerX" secondItem="Bcu-3y-fUS" secondAttribute="centerX" id="akx-eg-2ui"/>
<constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/> <constraint firstItem="MN2-I3-ftu" firstAttribute="leading" secondItem="Bcu-3y-fUS" secondAttribute="leading" id="i1E-0Y-4RG"/>
<constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/> <constraint firstItem="GJd-Yh-RWb" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="bottom" multiplier="1/3" constant="1" id="moa-c2-u7t"/>

View File

@ -0,0 +1,10 @@
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char *argv[])
{
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@ -7,13 +7,13 @@
#define TIMEOUT_SECONDS 600 #define TIMEOUT_SECONDS 600
#define TEXT_TO_LOOK_FOR @"Welcome to React" #define TEXT_TO_LOOK_FOR @"Welcome to React"
@interface VideoPlayerTests : XCTestCase @interface videoplayerTests : XCTestCase
@end @end
@implementation VideoPlayerTests @implementation videoplayerTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test - (BOOL)findSubviewInView:(UIView *)view matching:(BOOL (^)(UIView *view))test
{ {
if (test(view)) { if (test(view)) {
return YES; return YES;
@ -34,23 +34,25 @@
__block NSString *redboxError = nil; __block NSString *redboxError = nil;
#ifdef DEBUG #ifdef DEBUG
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) { RCTSetLogFunction(
if (level >= RCTLogLevelError) { ^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
redboxError = message; if (level >= RCTLogLevelError) {
} redboxError = message;
}); }
});
#endif #endif
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) { while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; [[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]]; [[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) { foundElement = [self findSubviewInView:vc.view
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) { matching:^BOOL(UIView *view) {
return YES; if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
} return YES;
return NO; }
}]; return NO;
}];
} }
#ifdef DEBUG #ifdef DEBUG
@ -61,5 +63,4 @@
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS); XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
} }
@end @end

View File

@ -23,7 +23,7 @@ module.exports = {
getTransformOptions: async () => ({ getTransformOptions: async () => ({
transform: { transform: {
experimentalImportSupport: false, experimentalImportSupport: false,
inlineRequires: false, inlineRequires: true,
}, },
}), }),
}, },

View File

@ -4,31 +4,31 @@
"private": true, "private": true,
"scripts": { "scripts": {
"android": "react-native run-android", "android": "react-native run-android",
"ios": "cd ios && pod install && cd .. && react-native run-ios", "ios": "react-native run-ios",
"windows": "react-native run-windows", "windows": "react-native run-windows",
"start": "node node_modules/react-native/local-cli/cli.js start", "start": "react-native start",
"test": "jest", "test": "jest",
"lint": "eslint ." "lint": "eslint ."
}, },
"dependencies": { "dependencies": {
"@react-native-picker/picker": "^1.9.11", "@react-native-picker/picker": "^1.9.11",
"babel-plugin-module-resolver": "^4.1.0", "react": "18.1.0",
"react": "16.13.1", "react-native": "0.70.6",
"react-native": "0.63.4",
"react-native-video": "../..", "react-native-video": "../..",
"react-native-windows": "0.63.41" "react-native-windows": "0.63.41"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.8.4", "@babel/core": "^7.12.9",
"@babel/runtime": "^7.8.4", "@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^1.1.0", "@react-native-community/eslint-config": "^2.0.0",
"@types/react": "^18.0.6", "@types/react": "^18.0.6",
"@types/react-native": "^0.67.6", "@types/react-native": "^0.67.6",
"babel-jest": "^25.1.0", "babel-plugin-module-resolver": "^4.1.0",
"eslint": "^6.5.1", "babel-jest": "^26.6.3",
"jest": "^25.1.0", "eslint": "^7.32.0",
"metro-react-native-babel-preset": "^0.59.0", "jest": "^26.6.3",
"react-test-renderer": "16.13.1" "metro-react-native-babel-preset": "0.72.3",
"react-test-renderer": "18.1.0"
}, },
"jest": { "jest": {
"preset": "react-native" "preset": "react-native"

View File

@ -714,6 +714,7 @@ class VideoPlayer extends Component {
paused={this.state.paused} paused={this.state.paused}
volume={this.state.volume} volume={this.state.volume}
muted={this.state.muted} muted={this.state.muted}
fullscreen={this.state.fullscreen}
controls={this.state.showRNVControls} controls={this.state.showRNVControls}
resizeMode={this.state.resizeMode} resizeMode={this.state.resizeMode}
onLoad={this.onLoad} onLoad={this.onLoad}

File diff suppressed because it is too large Load Diff

View File

@ -237,7 +237,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES; MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES; ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -271,7 +271,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES; GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 7.0; IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO; MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos; SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;

View File

@ -0,0 +1,187 @@
import Foundation
import GoogleInteractiveMediaAds
class RCTIMAAdsManager: NSObject, IMAAdsLoaderDelegate, IMAAdsManagerDelegate {
private var _video:RCTVideo
/* Entry point for the SDK. Used to make ad requests. */
private var adsLoader: IMAAdsLoader!
/* Main point of interaction with the SDK. Created by the SDK as the result of an ad request. */
private var adsManager: IMAAdsManager!
init(video:RCTVideo!) {
_video = video
super.init()
}
func setUpAdsLoader() {
adsLoader = IMAAdsLoader(settings: nil)
adsLoader.delegate = self
}
func requestAds() {
// Create ad display container for ad rendering.
let adDisplayContainer = IMAAdDisplayContainer(adContainer: _video, viewController: _video.reactViewController())
let adTagUrl = _video.getAdTagUrl()
let contentPlayhead = _video.getContentPlayhead()
if adTagUrl != nil && contentPlayhead != nil {
// Create an ad request with our ad tag, display container, and optional user context.
let request = IMAAdsRequest(
adTagUrl: adTagUrl!,
adDisplayContainer: adDisplayContainer,
contentPlayhead: contentPlayhead,
userContext: nil)
adsLoader.requestAds(with: request)
}
}
// MARK: - Getters
func getAdsLoader() -> IMAAdsLoader? {
return adsLoader
}
func getAdsManager() -> IMAAdsManager? {
return adsManager
}
// MARK: - IMAAdsLoaderDelegate
func adsLoader(_ loader: IMAAdsLoader, adsLoadedWith adsLoadedData: IMAAdsLoadedData) {
// Grab the instance of the IMAAdsManager and set yourself as the delegate.
adsManager = adsLoadedData.adsManager
adsManager?.delegate = self
// Create ads rendering settings and tell the SDK to use the in-app browser.
let adsRenderingSettings: IMAAdsRenderingSettings = IMAAdsRenderingSettings();
adsRenderingSettings.linkOpenerPresentingController = _video.reactViewController();
adsManager.initialize(with: adsRenderingSettings)
}
func adsLoader(_ loader: IMAAdsLoader, failedWith adErrorData: IMAAdLoadingErrorData) {
if adErrorData.adError.message != nil {
print("Error loading ads: " + adErrorData.adError.message!)
}
_video.setPaused(false)
}
// MARK: - IMAAdsManagerDelegate
func adsManager(_ adsManager: IMAAdsManager, didReceive event: IMAAdEvent) {
// Play each ad once it has been loaded
if event.type == IMAAdEventType.LOADED {
adsManager.start()
}
if _video.onReceiveAdEvent != nil {
let type = convertEventToString(event: event.type)
_video.onReceiveAdEvent?([
"event": type,
"target": _video.reactTag!
]);
}
}
func adsManager(_ adsManager: IMAAdsManager, didReceive error: IMAAdError) {
if error.message != nil {
print("AdsManager error: " + error.message!)
}
// Fall back to playing content
_video.setPaused(false)
}
func adsManagerDidRequestContentPause(_ adsManager: IMAAdsManager) {
// Pause the content for the SDK to play ads.
_video.setPaused(true)
_video.setAdPlaying(true)
}
func adsManagerDidRequestContentResume(_ adsManager: IMAAdsManager) {
// Resume the content since the SDK is done playing ads (at least for now).
_video.setAdPlaying(false)
_video.setPaused(false)
}
// MARK: - Helpers
func convertEventToString(event: IMAAdEventType!) -> String {
var result = "UNKNOWN";
switch(event) {
case .AD_BREAK_READY:
result = "AD_BREAK_READY";
break;
case .AD_BREAK_ENDED:
result = "AD_BREAK_ENDED";
break;
case .AD_BREAK_STARTED:
result = "AD_BREAK_STARTED";
break;
case .AD_PERIOD_ENDED:
result = "AD_PERIOD_ENDED";
break;
case .AD_PERIOD_STARTED:
result = "AD_PERIOD_STARTED";
break;
case .ALL_ADS_COMPLETED:
result = "ALL_ADS_COMPLETED";
break;
case .CLICKED:
result = "CLICK";
break;
case .COMPLETE:
result = "COMPLETE";
break;
case .CUEPOINTS_CHANGED:
result = "CUEPOINTS_CHANGED";
break;
case .FIRST_QUARTILE:
result = "FIRST_QUARTILE";
break;
case .LOADED:
result = "LOADED";
break;
case .LOG:
result = "LOG";
break;
case .MIDPOINT:
result = "MIDPOINT";
break;
case .PAUSE:
result = "PAUSED";
break;
case .RESUME:
result = "RESUMED";
break;
case .SKIPPED:
result = "SKIPPED";
break;
case .STARTED:
result = "STARTED";
break;
case .STREAM_LOADED:
result = "STREAM_LOADED";
break;
case .TAPPED:
result = "TAPPED";
break;
case .THIRD_QUARTILE:
result = "THIRD_QUARTILE";
break;
default:
result = "UNKNOWN";
}
return result;
}
}

View File

@ -133,6 +133,8 @@ enum RCTPlayerOperations {
let group:AVMediaSelectionGroup! = player?.currentItem?.asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) let group:AVMediaSelectionGroup! = player?.currentItem?.asset.mediaSelectionGroup(forMediaCharacteristic: characteristic)
var mediaOption:AVMediaSelectionOption! var mediaOption:AVMediaSelectionOption!
guard group != nil else { return }
if (type == "disabled") { if (type == "disabled") {
// Do nothing. We want to ensure option is nil // Do nothing. We want to ensure option is nil
} else if (type == "language") || (type == "title") { } else if (type == "language") || (type == "title") {

View File

@ -1,6 +1,7 @@
import AVFoundation import AVFoundation
import AVKit import AVKit
import Foundation import Foundation
import GoogleInteractiveMediaAds
import React import React
import Promises import Promises
@ -60,6 +61,14 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
private var _filterEnabled:Bool = false private var _filterEnabled:Bool = false
private var _presentingViewController:UIViewController? private var _presentingViewController:UIViewController?
/* IMA Ads */
private var _adTagUrl:String?
private var _imaAdsManager: RCTIMAAdsManager!
private var _didRequestAds:Bool = false
private var _adPlaying:Bool = false
/* Playhead used by the SDK to track content video progress and insert mid-rolls. */
private var _contentPlayhead: IMAAVPlayerContentPlayhead?
private var _resouceLoaderDelegate: RCTResourceLoaderDelegate? private var _resouceLoaderDelegate: RCTResourceLoaderDelegate?
private var _playerObserver: RCTPlayerObserver = RCTPlayerObserver() private var _playerObserver: RCTPlayerObserver = RCTPlayerObserver()
@ -94,10 +103,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc var onPictureInPictureStatusChanged: RCTDirectEventBlock? @objc var onPictureInPictureStatusChanged: RCTDirectEventBlock?
@objc var onRestoreUserInterfaceForPictureInPictureStop: RCTDirectEventBlock? @objc var onRestoreUserInterfaceForPictureInPictureStop: RCTDirectEventBlock?
@objc var onGetLicense: RCTDirectEventBlock? @objc var onGetLicense: RCTDirectEventBlock?
@objc var onReceiveAdEvent: RCTDirectEventBlock?
init(eventDispatcher:RCTEventDispatcher!) { init(eventDispatcher:RCTEventDispatcher!) {
super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100)) super.init(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
_imaAdsManager = RCTIMAAdsManager(video: self)
_eventDispatcher = eventDispatcher _eventDispatcher = eventDispatcher
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
@ -135,6 +147,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
required init?(coder aDecoder: NSCoder) { required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder) super.init(coder: aDecoder)
_imaAdsManager = RCTIMAAdsManager(video: self)
} }
deinit { deinit {
@ -203,6 +217,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
]) ])
if currentTimeSecs >= 0 { if currentTimeSecs >= 0 {
if !_didRequestAds && currentTimeSecs >= 0.0001 && _adTagUrl != nil {
_imaAdsManager.requestAds()
_didRequestAds = true
}
onVideoProgress?([ onVideoProgress?([
"currentTime": NSNumber(value: Float(currentTimeSecs)), "currentTime": NSNumber(value: Float(currentTimeSecs)),
"playableDuration": RCTVideoUtils.calculatePlayableDuration(_player), "playableDuration": RCTVideoUtils.calculatePlayableDuration(_player),
@ -215,95 +233,99 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
} }
// MARK: - Player and source // MARK: - Player and source
@objc @objc
func setSrc(_ source:NSDictionary!) { func setSrc(_ source:NSDictionary!) {
_source = VideoSource(source) DispatchQueue.global(qos: .default).async {
if (_source?.uri == nil || _source?.uri == "") { self._source = VideoSource(source)
DispatchQueue.global(qos: .default).async { if (self._source?.uri == nil || self._source?.uri == "") {
self._player?.replaceCurrentItem(with: nil) self._player?.replaceCurrentItem(with: nil)
return;
} }
return; self.removePlayerLayer()
} self._playerObserver.player = nil
removePlayerLayer() self._playerObserver.playerItem = nil
_playerObserver.player = nil
_playerObserver.playerItem = nil
// perform on next run loop, otherwise other passed react-props may not be set // perform on next run loop, otherwise other passed react-props may not be set
RCTVideoUtils.delay() RCTVideoUtils.delay()
.then{ [weak self] in .then{ [weak self] in
guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)} guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)}
guard let source = self._source else { guard let source = self._source else {
DebugLog("The source not exist") DebugLog("The source not exist")
throw NSError(domain: "", code: 0, userInfo: nil) throw NSError(domain: "", code: 0, userInfo: nil)
} }
if let uri = source.uri, uri.starts(with: "ph://") { if let uri = source.uri, uri.starts(with: "ph://") {
return Promise { return Promise {
RCTVideoUtils.preparePHAsset(uri: uri).then { asset in RCTVideoUtils.preparePHAsset(uri: uri).then { asset in
return self.playerItemPrepareText(asset:asset, assetOptions:nil) return self.playerItemPrepareText(asset:asset, assetOptions:nil)
}
} }
} }
} guard let assetResult = RCTVideoUtils.prepareAsset(source: source),
guard let assetResult = RCTVideoUtils.prepareAsset(source: source), let asset = assetResult.asset,
let asset = assetResult.asset, let assetOptions = assetResult.assetOptions else {
let assetOptions = assetResult.assetOptions else { DebugLog("Could not find video URL in source '\(self._source)'")
DebugLog("Could not find video URL in source '\(self._source)'") throw NSError(domain: "", code: 0, userInfo: nil)
throw NSError(domain: "", code: 0, userInfo: nil) }
}
#if canImport(RCTVideoCache) #if canImport(RCTVideoCache)
if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) { if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) {
return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions) return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions)
} }
#endif #endif
if self._drm != nil || self._localSourceEncryptionKeyScheme != nil { if self._drm != nil || self._localSourceEncryptionKeyScheme != nil {
self._resouceLoaderDelegate = RCTResourceLoaderDelegate( self._resouceLoaderDelegate = RCTResourceLoaderDelegate(
asset: asset, asset: asset,
drm: self._drm, drm: self._drm,
localSourceEncryptionKeyScheme: self._localSourceEncryptionKeyScheme, localSourceEncryptionKeyScheme: self._localSourceEncryptionKeyScheme,
onVideoError: self.onVideoError, onVideoError: self.onVideoError,
onGetLicense: self.onGetLicense, onGetLicense: self.onGetLicense,
reactTag: self.reactTag reactTag: self.reactTag
) )
} }
return Promise{self.playerItemPrepareText(asset: asset, assetOptions:assetOptions)} return Promise{self.playerItemPrepareText(asset: asset, assetOptions:assetOptions)}
}.then{[weak self] (playerItem:AVPlayerItem!) in }.then{[weak self] (playerItem:AVPlayerItem!) in
guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)} guard let self = self else {throw NSError(domain: "", code: 0, userInfo: nil)}
self._player?.pause() self._player?.pause()
self._playerItem = playerItem self._playerItem = playerItem
self._playerObserver.playerItem = self._playerItem self._playerObserver.playerItem = self._playerItem
self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration) self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration)
self.setFilter(self._filterName) self.setFilter(self._filterName)
if let maxBitRate = self._maxBitRate { if let maxBitRate = self._maxBitRate {
self._playerItem?.preferredPeakBitRate = Double(maxBitRate) self._playerItem?.preferredPeakBitRate = Double(maxBitRate)
} }
self._player = AVPlayer() self._player = self._player ?? AVPlayer()
DispatchQueue.global(qos: .default).async {
self._player?.replaceCurrentItem(with: playerItem) self._player?.replaceCurrentItem(with: playerItem)
} self._playerObserver.player = self._player
self._playerObserver.player = self._player self.applyModifiers()
self.applyModifiers() self._player?.actionAtItemEnd = .none
self._player?.actionAtItemEnd = .none
if #available(iOS 10.0, *) { if #available(iOS 10.0, *) {
self.setAutomaticallyWaitsToMinimizeStalling(self._automaticallyWaitsToMinimizeStalling) self.setAutomaticallyWaitsToMinimizeStalling(self._automaticallyWaitsToMinimizeStalling)
} }
//Perform on next run loop, otherwise onVideoLoadStart is nil if self._adTagUrl != nil {
self.onVideoLoadStart?([ // Set up your content playhead and contentComplete callback.
"src": [ self._contentPlayhead = IMAAVPlayerContentPlayhead(avPlayer: self._player!)
"uri": self._source?.uri ?? NSNull(),
"type": self._source?.type ?? NSNull(), self._imaAdsManager.setUpAdsLoader()
"isNetwork": NSNumber(value: self._source?.isNetwork ?? false) }
],
"drm": self._drm?.json ?? NSNull(), //Perform on next run loop, otherwise onVideoLoadStart is nil
"target": self.reactTag self.onVideoLoadStart?([
]) "src": [
}.catch{_ in } "uri": self._source?.uri ?? NSNull(),
_videoLoadStarted = true "type": self._source?.type ?? NSNull(),
"isNetwork": NSNumber(value: self._source?.isNetwork ?? false)
],
"drm": self._drm?.json ?? NSNull(),
"target": self.reactTag
])
}.catch{_ in }
self._videoLoadStarted = true
}
} }
@objc @objc
@ -400,18 +422,26 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc @objc
func setPaused(_ paused:Bool) { func setPaused(_ paused:Bool) {
if paused { if paused {
_player?.pause() if _adPlaying {
_player?.rate = 0.0 _imaAdsManager.getAdsManager()?.pause()
} else {
_player?.pause()
_player?.rate = 0.0
}
} else { } else {
RCTPlayerOperations.configureAudio(ignoreSilentSwitch:_ignoreSilentSwitch, mixWithOthers:_mixWithOthers) RCTPlayerOperations.configureAudio(ignoreSilentSwitch:_ignoreSilentSwitch, mixWithOthers:_mixWithOthers)
if #available(iOS 10.0, *), !_automaticallyWaitsToMinimizeStalling { if _adPlaying {
_player?.playImmediately(atRate: _rate) _imaAdsManager.getAdsManager()?.resume()
} else { } else {
_player?.play() if #available(iOS 10.0, *), !_automaticallyWaitsToMinimizeStalling {
_player?.playImmediately(atRate: _rate)
} else {
_player?.play()
_player?.rate = _rate
}
_player?.rate = _rate _player?.rate = _rate
} }
_player?.rate = _rate
} }
_paused = paused _paused = paused
@ -605,14 +635,16 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
self.onVideoFullscreenPlayerWillPresent?(["target": reactTag as Any]) self.onVideoFullscreenPlayerWillPresent?(["target": reactTag as Any])
viewController.present(viewController, animated:true, completion:{ if let playerViewController = _playerViewController {
self._playerViewController?.showsPlaybackControls = true viewController.present(playerViewController, animated:true, completion:{
self._fullscreenPlayerPresented = fullscreen self._playerViewController?.showsPlaybackControls = true
self._playerViewController?.autorotate = self._fullscreenAutorotate self._fullscreenPlayerPresented = fullscreen
self._playerViewController?.autorotate = self._fullscreenAutorotate
self.onVideoFullscreenPlayerDidPresent?(["target": self.reactTag]) self.onVideoFullscreenPlayerDidPresent?(["target": self.reactTag])
}) })
}
} }
} else if !fullscreen && _fullscreenPlayerPresented, let _playerViewController = _playerViewController { } else if !fullscreen && _fullscreenPlayerPresented, let _playerViewController = _playerViewController {
self.videoPlayerViewControllerWillDismiss(playerViewController: _playerViewController) self.videoPlayerViewControllerWillDismiss(playerViewController: _playerViewController)
@ -652,7 +684,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
if _controls { if _controls {
let viewController:UIViewController! = self.reactViewController() let viewController:UIViewController! = self.reactViewController()
viewController.addChild(_playerViewController) viewController?.addChild(_playerViewController)
self.addSubview(_playerViewController.view) self.addSubview(_playerViewController.view)
} }
@ -704,6 +736,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
else else
{ {
_playerViewController?.view.removeFromSuperview() _playerViewController?.view.removeFromSuperview()
_playerViewController?.removeFromParent()
_playerViewController = nil _playerViewController = nil
_playerObserver.playerViewController = nil _playerObserver.playerViewController = nil
self.usePlayerLayer() self.usePlayerLayer()
@ -781,6 +814,25 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
_filterEnabled = filterEnabled _filterEnabled = filterEnabled
} }
// MARK: - RCTIMAAdsManager
func getAdTagUrl() -> String? {
return _adTagUrl
}
@objc
func setAdTagUrl(_ adTagUrl:String!) {
_adTagUrl = adTagUrl
}
func getContentPlayhead() -> IMAAVPlayerContentPlayhead? {
return _contentPlayhead
}
func setAdPlaying(_ adPlaying:Bool) {
_adPlaying = adPlaying
}
// MARK: - React View Management // MARK: - React View Management
func insertReactSubview(view:UIView!, atIndex:Int) { func insertReactSubview(view:UIView!, atIndex:Int) {
@ -836,6 +888,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
if let _playerViewController = _playerViewController { if let _playerViewController = _playerViewController {
_playerViewController.view.removeFromSuperview() _playerViewController.view.removeFromSuperview()
_playerViewController.removeFromParent()
_playerViewController.rctDelegate = nil _playerViewController.rctDelegate = nil
_playerViewController.player = nil _playerViewController.player = nil
self._playerViewController = nil self._playerViewController = nil
@ -1057,9 +1110,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
@objc func handlePlayerItemDidReachEnd(notification:NSNotification!) { @objc func handlePlayerItemDidReachEnd(notification:NSNotification!) {
onVideoEnd?(["target": reactTag as Any]) onVideoEnd?(["target": reactTag as Any])
if notification.object as? AVPlayerItem == _player?.currentItem {
_imaAdsManager.getAdsLoader()?.contentComplete()
}
if _repeat { if _repeat {
let item:AVPlayerItem! = notification.object as? AVPlayerItem let item:AVPlayerItem! = notification.object as? AVPlayerItem
item.seek(to: CMTime.zero) item.seek(to: CMTime.zero, completionHandler: nil)
self.applyModifiers() self.applyModifiers()
} else { } else {
self.setPaused(true); self.setPaused(true);

View File

@ -5,6 +5,7 @@
RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(src, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(drm, NSDictionary); RCT_EXPORT_VIEW_PROPERTY(drm, NSDictionary);
RCT_EXPORT_VIEW_PROPERTY(adTagUrl, NSString);
RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float); RCT_EXPORT_VIEW_PROPERTY(maxBitRate, float);
RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString); RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
@ -59,6 +60,7 @@ RCT_EXPORT_VIEW_PROPERTY(onVideoExternalPlaybackChange, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onGetLicense, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onPictureInPictureStatusChanged, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onPictureInPictureStatusChanged, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onRestoreUserInterfaceForPictureInPictureStop, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onRestoreUserInterfaceForPictureInPictureStop, RCTDirectEventBlock);
RCT_EXPORT_VIEW_PROPERTY(onReceiveAdEvent, RCTDirectEventBlock);
RCT_EXTERN_METHOD(save:(NSDictionary *)options RCT_EXTERN_METHOD(save:(NSDictionary *)options
reactTag:(nonnull NSNumber *)reactTag reactTag:(nonnull NSNumber *)reactTag

View File

@ -1,6 +1,6 @@
{ {
"name": "react-native-video", "name": "react-native-video",
"version": "6.0.0-alpha.3", "version": "6.0.0-alpha.4",
"description": "A <Video /> element for react-native", "description": "A <Video /> element for react-native",
"main": "Video.js", "main": "Video.js",
"license": "MIT", "license": "MIT",
@ -34,6 +34,7 @@
"DRMType.js", "DRMType.js",
"TextTrackType.js", "TextTrackType.js",
"VideoResizeMode.js", "VideoResizeMode.js",
"react-native-video.podspec" "react-native-video.podspec",
"docs"
] ]
} }

View File

@ -18,6 +18,9 @@ Pod::Spec.new do |s|
s.subspec "Video" do |ss| s.subspec "Video" do |ss|
ss.source_files = "ios/Video/**/*.{h,m,swift}" ss.source_files = "ios/Video/**/*.{h,m,swift}"
ss.dependency "PromisesSwift" ss.dependency "PromisesSwift"
ss.ios.dependency 'GoogleAds-IMA-iOS-SDK', '~> 3.18.1'
ss.tvos.dependency 'GoogleAds-IMA-tvOS-SDK', '~> 4.2'
end end
s.subspec "VideoCaching" do |ss| s.subspec "VideoCaching" do |ss|