Merge remote-tracking branch 'upstream/master'

This commit is contained in:
tobias 2016-04-14 13:51:11 +02:00
commit 1df54554dc
48 changed files with 2157 additions and 644 deletions

4
.eslintrc Normal file
View File

@ -0,0 +1,4 @@
{
"extends": "airbnb",
"parser": "babel-eslint"
}

View File

@ -14,17 +14,21 @@
# Ignore react and fbjs where there are overlaps, but don't ignore # Ignore react and fbjs where there are overlaps, but don't ignore
# anything that react-native relies on # anything that react-native relies on
.*/node_modules/fbjs-haste/.*/__tests__/.* .*/node_modules/fbjs/lib/Map.js
.*/node_modules/fbjs-haste/__forks__/Map.js .*/node_modules/fbjs/lib/fetch.js
.*/node_modules/fbjs-haste/__forks__/Promise.js .*/node_modules/fbjs/lib/ExecutionEnvironment.js
.*/node_modules/fbjs-haste/__forks__/fetch.js .*/node_modules/fbjs/lib/ErrorUtils.js
.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js
.*/node_modules/fbjs-haste/core/isEmpty.js # Flow has a built-in definition for the 'react' module which we prefer to use
.*/node_modules/fbjs-haste/crypto/crc32.js # over the currently-untyped source
.*/node_modules/fbjs-haste/stubs/ErrorUtils.js .*/node_modules/react/react.js
.*/node_modules/react-haste/React.js .*/node_modules/react/lib/React.js
.*/node_modules/react-haste/renderers/dom/ReactDOM.js .*/node_modules/react/lib/ReactDOM.js
.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js
.*/__mocks__/.*
.*/__tests__/.*
.*/commoner/test/source/widget/share.js
# Ignore commoner tests # Ignore commoner tests
.*/node_modules/commoner/test/.* .*/node_modules/commoner/test/.*
@ -38,26 +42,48 @@
# Ignore Website # Ignore Website
.*/website/.* .*/website/.*
.*/node_modules/is-my-json-valid/test/.*\.json
.*/node_modules/iconv-lite/encodings/tables/.*\.json
.*/node_modules/y18n/test/.*\.json
.*/node_modules/spdx-license-ids/spdx-license-ids.json
.*/node_modules/spdx-exceptions/index.json
.*/node_modules/resolve/test/subdirs/node_modules/a/b/c/x.json
.*/node_modules/resolve/lib/core.json
.*/node_modules/jsonparse/samplejson/.*\.json
.*/node_modules/json5/test/.*\.json
.*/node_modules/ua-parser-js/test/.*\.json
.*/node_modules/builtin-modules/builtin-modules.json
.*/node_modules/binary-extensions/binary-extensions.json
.*/node_modules/url-regex/tlds.json
.*/node_modules/joi/.*\.json
.*/node_modules/isemail/.*\.json
.*/node_modules/tr46/.*\.json
[include] [include]
[libs] [libs]
node_modules/react-native/Libraries/react-native/react-native-interface.js node_modules/react-native/Libraries/react-native/react-native-interface.js
node_modules/react-native/flow
flow/
[options] [options]
module.system=haste module.system=haste
esproposal.class_static_fields=enable
esproposal.class_instance_fields=enable
munge_underscores=true munge_underscores=true
module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub' module.name_mapper='^image![a-zA-Z0-9$_-]+$' -> 'GlobalImageStub'
module.name_mapper='^[./a-zA-Z0-9$_-]+\.png$' -> 'RelativeImageStub' 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\)$' -> 'RelativeImageStub'
suppress_type=$FlowIssue suppress_type=$FlowIssue
suppress_type=$FlowFixMe suppress_type=$FlowFixMe
suppress_type=$FixMe suppress_type=$FixMe
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\) suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
[version] [version]
0.18.1 0.22.0

View File

@ -1 +1,37 @@
node_modules/**/* VideoPlayer.xcodeproj/project.xcworkspace/**/*
VideoPlayer.xcodeproj/xcuserdata/**/*
# 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
project.xcworkspace
# Android/IJ
#
.idea
.gradle
local.properties
# node.js
#
node_modules/
npm-debug.log

View File

@ -302,7 +302,7 @@
83CBB9F71A601CBA00E9B192 /* Project object */ = { 83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0610; LastUpgradeCheck = 0720;
ORGANIZATIONNAME = Facebook; ORGANIZATIONNAME = Facebook;
}; };
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "VideoPlayer" */; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "VideoPlayer" */;
@ -487,8 +487,10 @@
"$(SRCROOT)/node_modules/react-native/React/**", "$(SRCROOT)/node_modules/react-native/React/**",
); );
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = VideoPlayer; PRODUCT_NAME = VideoPlayer;
}; };
name = Debug; name = Debug;
@ -503,8 +505,10 @@
"$(SRCROOT)/node_modules/react-native/React/**", "$(SRCROOT)/node_modules/react-native/React/**",
); );
INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "-ObjC"; OTHER_LDFLAGS = "-ObjC";
PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_NAME = VideoPlayer; PRODUCT_NAME = VideoPlayer;
}; };
name = Release; name = Release;
@ -529,6 +533,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;

View File

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

View File

@ -1,41 +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>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>9B1B824B-5918-47F5-B27A-FA559B781ACC</string>
<key>IDESourceControlProjectName</key>
<string>VideoPlayer</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>D05F265D0E65FFE673B2E9F5A4680A7F46E27F31</key>
<string>github.com:johanneslumpe/react-native-video.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>Examples/VideoPlayer/VideoPlayer.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>D05F265D0E65FFE673B2E9F5A4680A7F46E27F31</key>
<string>../../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:johanneslumpe/react-native-video.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>D05F265D0E65FFE673B2E9F5A4680A7F46E27F31</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>D05F265D0E65FFE673B2E9F5A4680A7F46E27F31</string>
<key>IDESourceControlWCCName</key>
<string>react-native-video</string>
</dict>
</array>
</dict>
</plist>

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<Scheme <Scheme
LastUpgradeVersion = "0620" LastUpgradeVersion = "0720"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "YES" parallelizeBuildables = "YES"
@ -23,10 +23,10 @@
</BuildActionEntries> </BuildActionEntries>
</BuildAction> </BuildAction>
<TestAction <TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES">
buildConfiguration = "Debug">
<Testables> <Testables>
</Testables> </Testables>
<MacroExpansion> <MacroExpansion>
@ -38,15 +38,18 @@
ReferencedContainer = "container:VideoPlayer.xcodeproj"> ReferencedContainer = "container:VideoPlayer.xcodeproj">
</BuildableReference> </BuildableReference>
</MacroExpansion> </MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction> </TestAction>
<LaunchAction <LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0" launchStyle = "0"
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO" ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES" debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES"> allowLocationSimulation = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">
@ -62,10 +65,10 @@
</AdditionalOptions> </AdditionalOptions>
</LaunchAction> </LaunchAction>
<ProfileAction <ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES" shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = "" savedToolIdentifier = ""
useCustomWorkingDirectory = "NO" useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES"> debugDocumentVersioning = "YES">
<BuildableProductRunnable <BuildableProductRunnable
runnableDebuggingMode = "0"> runnableDebuggingMode = "0">

View File

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "iOS/main.m"
timestampString = "450209799.468907"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "9"
endingLineNumber = "9">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -1,22 +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>SchemeUserState</key>
<dict>
<key>VideoPlayer.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>0</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>13B07F861A680F5B00A75B9A</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@ -1,5 +1,7 @@
apply plugin: "com.android.application" apply plugin: "com.android.application"
import com.android.build.OutputFile
/** /**
* The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets.
* These basically call `react-native bundle` with the correct arguments during the Android build * These basically call `react-native bundle` with the correct arguments during the Android build
@ -49,6 +51,22 @@ apply plugin: "com.android.application"
apply from: "react.gradle" apply from: "react.gradle"
/**
* Set this to true to create three separate APKs instead of one:
* - A universal APK that works on all devices
* - An APK that only works on ARM devices
* - An APK that only works on x86 devices
* The advantage is the size of the APK is reduced by about 4MB.
* Upload all the APKs to the Play Store and people will download
* the correct one based on the CPU architecture of their device.
*/
def enableSeparateBuildPerCPUArchitecture = false
/**
* Run Proguard to shrink the Java bytecode in release builds.
*/
def enableProguardInReleaseBuilds = false
android { android {
compileSdkVersion 23 compileSdkVersion 23
buildToolsVersion "23.0.1" buildToolsVersion "23.0.1"
@ -63,17 +81,38 @@ android {
abiFilters "armeabi-v7a", "x86" abiFilters "armeabi-v7a", "x86"
} }
} }
splits {
abi {
enable enableSeparateBuildPerCPUArchitecture
universalApk true
reset()
include "armeabi-v7a", "x86"
}
}
buildTypes { buildTypes {
release { release {
minifyEnabled false // Set this to true to enable Proguard minifyEnabled enableProguardInReleaseBuilds
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro" proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
} }
} }
// applicationVariants are e.g. debug, release
applicationVariants.all { variant ->
variant.outputs.each { output ->
// For each separate APK per architecture, set a unique version code as described here:
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
def versionCodes = ["armeabi-v7a":1, "x86":2]
def abi = output.getFilter(OutputFile.ABI)
if (abi != null) { // null for the universal-debug, universal-release variants
output.versionCodeOverride =
versionCodes.get(abi) * 1048576 + defaultConfig.versionCode
}
}
}
} }
dependencies { dependencies {
compile project(':react-native-video')
compile fileTree(dir: "libs", include: ["*.jar"]) compile fileTree(dir: "libs", include: ["*.jar"])
compile "com.android.support:appcompat-v7:23.0.1" compile "com.android.support:appcompat-v7:23.0.1"
compile "com.facebook.react:react-native:0.16.+" compile "com.facebook.react:react-native:0.19.+"
compile project(':RCTVideo')
} }

View File

@ -40,10 +40,13 @@
-keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; }
-keep class * extends com.facebook.react.bridge.NativeModule { *; } -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.UIProp <fields>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactProp <methods>; } -keepclassmembers class * { @com.facebook.react.uimanager.ReactProp <methods>; }
-keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup <methods>; } -keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup <methods>; }
-dontwarn com.facebook.react.**
# okhttp # okhttp
-keepattributes Signature -keepattributes Signature
@ -58,3 +61,7 @@
-dontwarn java.nio.file.* -dontwarn java.nio.file.*
-dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement
-dontwarn okio.** -dontwarn okio.**
# stetho
-dontwarn com.facebook.stetho.**

View File

@ -74,14 +74,33 @@ task bundleReleaseJsAndAssets(type: Exec) {
enabled config.bundleInRelease ?: true enabled config.bundleInRelease ?: true
} }
void runBefore(String dependentTaskName, Task task) {
Task dependentTask = tasks.findByPath(dependentTaskName);
if (dependentTask != null) {
dependentTask.dependsOn task
}
}
gradle.projectsEvaluated { gradle.projectsEvaluated {
// hook bundleDebugJsAndAssets into the android build process // hook bundleDebugJsAndAssets into the android build process
bundleDebugJsAndAssets.dependsOn mergeDebugResources bundleDebugJsAndAssets.dependsOn mergeDebugResources
bundleDebugJsAndAssets.dependsOn mergeDebugAssets bundleDebugJsAndAssets.dependsOn mergeDebugAssets
processDebugResources.dependsOn bundleDebugJsAndAssets
runBefore('processArmeabi-v7aDebugResources', bundleDebugJsAndAssets)
runBefore('processX86DebugResources', bundleDebugJsAndAssets)
runBefore('processUniversalDebugResources', bundleDebugJsAndAssets)
runBefore('processDebugResources', bundleDebugJsAndAssets)
// hook bundleReleaseJsAndAssets into the android build process // hook bundleReleaseJsAndAssets into the android build process
bundleReleaseJsAndAssets.dependsOn mergeReleaseResources bundleReleaseJsAndAssets.dependsOn mergeReleaseResources
bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets
processReleaseResources.dependsOn bundleReleaseJsAndAssets
runBefore('processArmeabi-v7aReleaseResources', bundleReleaseJsAndAssets)
runBefore('processX86ReleaseResources', bundleReleaseJsAndAssets)
runBefore('processUniversalReleaseResources', bundleReleaseJsAndAssets)
runBefore('processReleaseResources', bundleReleaseJsAndAssets)
} }

View File

@ -1,80 +1,41 @@
package com.videoplayer; package com.videoplayer;
import android.app.Activity; import com.facebook.react.ReactActivity;
import android.os.Bundle;
import android.view.KeyEvent;
import com.brentvatne.react.ReactVideoPackage; import com.brentvatne.react.ReactVideoPackage;
import com.facebook.react.LifecycleState; import com.facebook.react.ReactPackage;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactRootView;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.shell.MainReactPackage; import com.facebook.react.shell.MainReactPackage;
import com.facebook.soloader.SoLoader;
public class MainActivity extends Activity implements DefaultHardwareBackBtnHandler { import java.util.Arrays;
import java.util.List;
private ReactInstanceManager mReactInstanceManager; public class MainActivity extends ReactActivity {
private ReactRootView mReactRootView;
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected String getMainComponentName() {
super.onCreate(savedInstanceState); return "VideoPlayer";
mReactRootView = new ReactRootView(this);
mReactInstanceManager = ReactInstanceManager.builder()
.setApplication(getApplication())
.setBundleAssetName("index.android.bundle")
.setJSMainModuleName("index.android")
.addPackage(new MainReactPackage())
.addPackage(new ReactVideoPackage())
.setUseDeveloperSupport(BuildConfig.DEBUG)
.setInitialLifecycleState(LifecycleState.RESUMED)
.build();
mReactRootView.startReactApplication(mReactInstanceManager, "VideoPlayer", null);
setContentView(mReactRootView);
} }
/**
* Returns whether dev mode should be enabled.
* This enables e.g. the dev menu.
*/
@Override @Override
public boolean onKeyUp(int keyCode, KeyEvent event) { protected boolean getUseDeveloperSupport() {
if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { return BuildConfig.DEBUG;
mReactInstanceManager.showDevOptionsDialog();
return true;
}
return super.onKeyUp(keyCode, event);
} }
/**
* A list of packages used by the app. If the app uses additional views
* or modules besides the default ones, add more packages here.
*/
@Override @Override
public void onBackPressed() { protected List<ReactPackage> getPackages() {
if (mReactInstanceManager != null) { return Arrays.<ReactPackage>asList(
mReactInstanceManager.onBackPressed(); new MainReactPackage(),
} else { new ReactVideoPackage());
super.onBackPressed();
}
}
@Override
public void invokeDefaultOnBackPressed() {
super.onBackPressed();
}
@Override
protected void onPause() {
super.onPause();
if (mReactInstanceManager != null) {
mReactInstanceManager.onPause();
}
}
@Override
protected void onResume() {
super.onResume();
if (mReactInstanceManager != null) {
mReactInstanceManager.onResume(this, this);
}
} }
} }

View File

@ -1,5 +1,7 @@
rootProject.name = 'VideoPlayer' rootProject.name = 'VideoPlayer'
include ':app' include ':app'
include ':react-native-video'
project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')
include ':RCTVideo', ':app' include ':RCTVideo', ':app'
project(':RCTVideo').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') project(':RCTVideo').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android')

View File

@ -7,7 +7,7 @@
<key>CFBundleExecutable</key> <key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string> <string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key> <key>CFBundleIdentifier</key>
<string>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</string> <string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key> <key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string> <string>6.0</string>
<key>CFBundleName</key> <key>CFBundleName</key>
@ -15,11 +15,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>APPL</string> <string>APPL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>1.0</string> <string>1.0.0</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>1</string> <string>2</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string></string> <string></string>
<key>LSRequiresIPhoneOS</key> <key>LSRequiresIPhoneOS</key>

View File

@ -0,0 +1,779 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */; };
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */; };
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */; };
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */; };
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */; };
00E356F31AD99517003FC87E /* VideoPlayerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 00E356F21AD99517003FC87E /* VideoPlayerTests.m */; };
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78C398B91ACF4ADC00677621 /* libRCTLinking.a */; };
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */; };
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */; };
13B07FBC1A68108700A75B9A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB01A68108700A75B9A /* AppDelegate.m */; };
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB11A68108700A75B9A /* LaunchScreen.xib */; };
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 13B07FB51A68108700A75B9A /* Images.xcassets */; };
13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; };
146834051AC3E58100842450 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 146834041AC3E56700842450 /* libReact.a */; };
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 832341B51AAA6A8300B99B32 /* libRCTText.a */; };
F45119DCD4CB4566AA95CCBF /* libRCTVideo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = E6D74A42E295462FBFFFB2F5 /* libRCTVideo.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTActionSheet;
};
00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTGeolocation;
};
00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B5115D1A9E6B3D00147676;
remoteInfo = RCTImage;
};
00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B511DB1A9E6C8500147676;
remoteInfo = RCTNetwork;
};
00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 832C81801AAF6DEF007FA2F7;
remoteInfo = RCTVibration;
};
00E356F41AD99517003FC87E /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 83CBB9F71A601CBA00E9B192 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 13B07F861A680F5B00A75B9A;
remoteInfo = VideoPlayer;
};
139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTSettings;
};
139FDEF31B06529B00C62182 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 3C86DF461ADF2C930047B81A;
remoteInfo = RCTWebSocket;
};
146834031AC3E56700842450 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 146833FF1AC3E56700842450 /* React.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 83CBBA2E1A601D0E00E9B192;
remoteInfo = React;
};
78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 134814201AA4EA6300B7C361;
remoteInfo = RCTLinking;
};
832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 58B5119B1A9E6C1200147676;
remoteInfo = RCTText;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
008F07F21AC5B25A0029DE68 /* main.jsbundle */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = main.jsbundle; path = main.jsbundle; sourceTree = "<group>"; };
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = "<group>"; };
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = "<group>"; };
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = "<group>"; };
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = "<group>"; };
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
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>"; };
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = "<group>"; };
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; 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.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = VideoPlayer/AppDelegate.m; sourceTree = "<group>"; };
13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; 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>"; };
146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = "<group>"; };
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = "<group>"; };
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = "<group>"; };
1AAB246A2EAD48DC803233C0 /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; name = "RCTVideo.xcodeproj"; path = "../node_modules/react-native-video/RCTVideo.xcodeproj"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; };
E6D74A42E295462FBFFFB2F5 /* libRCTVideo.a */ = {isa = PBXFileReference; name = "libRCTVideo.a"; path = "libRCTVideo.a"; sourceTree = "<group>"; fileEncoding = undefined; lastKnownFileType = archive.ar; explicitFileType = undefined; includeInIndex = 0; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
00E356EB1AD99517003FC87E /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8C1A680F5B00A75B9A /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
146834051AC3E58100842450 /* libReact.a in Frameworks */,
00C302E51ABCBA2D00DB3ED1 /* libRCTActionSheet.a in Frameworks */,
00C302E71ABCBA2D00DB3ED1 /* libRCTGeolocation.a in Frameworks */,
00C302E81ABCBA2D00DB3ED1 /* libRCTImage.a in Frameworks */,
133E29F31AD74F7200F7D852 /* libRCTLinking.a in Frameworks */,
00C302E91ABCBA2D00DB3ED1 /* libRCTNetwork.a in Frameworks */,
139105C61AF99C1200B5F7CC /* libRCTSettings.a in Frameworks */,
832341BD1AAA6AB300B99B32 /* libRCTText.a in Frameworks */,
00C302EA1ABCBA2D00DB3ED1 /* libRCTVibration.a in Frameworks */,
139FDEF61B0652A700C62182 /* libRCTWebSocket.a in Frameworks */,
F45119DCD4CB4566AA95CCBF /* libRCTVideo.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
00C302A81ABCB8CE00DB3ED1 /* Products */ = {
isa = PBXGroup;
children = (
00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */,
);
name = Products;
sourceTree = "<group>";
};
00C302B61ABCB90400DB3ED1 /* Products */ = {
isa = PBXGroup;
children = (
00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */,
);
name = Products;
sourceTree = "<group>";
};
00C302BC1ABCB91800DB3ED1 /* Products */ = {
isa = PBXGroup;
children = (
00C302C01ABCB91800DB3ED1 /* libRCTImage.a */,
);
name = Products;
sourceTree = "<group>";
};
00C302D41ABCB9D200DB3ED1 /* Products */ = {
isa = PBXGroup;
children = (
00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */,
);
name = Products;
sourceTree = "<group>";
};
00C302E01ABCB9EE00DB3ED1 /* Products */ = {
isa = PBXGroup;
children = (
00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */,
);
name = Products;
sourceTree = "<group>";
};
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>";
};
139105B71AF99BAD00B5F7CC /* Products */ = {
isa = PBXGroup;
children = (
139105C11AF99BAD00B5F7CC /* libRCTSettings.a */,
);
name = Products;
sourceTree = "<group>";
};
139FDEE71B06529A00C62182 /* Products */ = {
isa = PBXGroup;
children = (
139FDEF41B06529B00C62182 /* libRCTWebSocket.a */,
);
name = Products;
sourceTree = "<group>";
};
13B07FAE1A68108700A75B9A /* VideoPlayer */ = {
isa = PBXGroup;
children = (
008F07F21AC5B25A0029DE68 /* main.jsbundle */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.m */,
13B07FB51A68108700A75B9A /* Images.xcassets */,
13B07FB61A68108700A75B9A /* Info.plist */,
13B07FB11A68108700A75B9A /* LaunchScreen.xib */,
13B07FB71A68108700A75B9A /* main.m */,
);
name = VideoPlayer;
sourceTree = "<group>";
};
146834001AC3E56700842450 /* Products */ = {
isa = PBXGroup;
children = (
146834041AC3E56700842450 /* libReact.a */,
);
name = Products;
sourceTree = "<group>";
};
78C398B11ACF4ADC00677621 /* Products */ = {
isa = PBXGroup;
children = (
78C398B91ACF4ADC00677621 /* libRCTLinking.a */,
);
name = Products;
sourceTree = "<group>";
};
832341AE1AAA6A7D00B99B32 /* Libraries */ = {
isa = PBXGroup;
children = (
146833FF1AC3E56700842450 /* React.xcodeproj */,
00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */,
00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */,
00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */,
78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */,
00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */,
139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */,
832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */,
00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */,
139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */,
1AAB246A2EAD48DC803233C0 /* RCTVideo.xcodeproj */,
);
name = Libraries;
sourceTree = "<group>";
};
832341B11AAA6A8300B99B32 /* Products */ = {
isa = PBXGroup;
children = (
832341B51AAA6A8300B99B32 /* libRCTText.a */,
);
name = Products;
sourceTree = "<group>";
};
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
13B07FAE1A68108700A75B9A /* VideoPlayer */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* VideoPlayerTests */,
83CBBA001A601CBA00E9B192 /* Products */,
);
indentWidth = 2;
sourceTree = "<group>";
tabWidth = 2;
};
83CBBA001A601CBA00E9B192 /* Products */ = {
isa = PBXGroup;
children = (
13B07F961A680F5B00A75B9A /* VideoPlayer.app */,
00E356EE1AD99517003FC87E /* VideoPlayerTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
00E356ED1AD99517003FC87E /* VideoPlayerTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 00E357021AD99517003FC87E /* Build configuration list for PBXNativeTarget "VideoPlayerTests" */;
buildPhases = (
00E356EA1AD99517003FC87E /* Sources */,
00E356EB1AD99517003FC87E /* Frameworks */,
00E356EC1AD99517003FC87E /* 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 = (
13B07F871A680F5B00A75B9A /* Sources */,
13B07F8C1A680F5B00A75B9A /* Frameworks */,
13B07F8E1A680F5B00A75B9A /* Resources */,
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */,
);
buildRules = (
);
dependencies = (
);
name = VideoPlayer;
productName = "Hello World";
productReference = 13B07F961A680F5B00A75B9A /* VideoPlayer.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
83CBB9F71A601CBA00E9B192 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
00E356ED1AD99517003FC87E = {
CreatedOnToolsVersion = 6.2;
TestTargetID = 13B07F861A680F5B00A75B9A;
};
};
};
buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "VideoPlayer" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 83CBB9F61A601CBA00E9B192;
productRefGroup = 83CBBA001A601CBA00E9B192 /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 00C302A81ABCB8CE00DB3ED1 /* Products */;
ProjectRef = 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */;
},
{
ProductGroup = 00C302B61ABCB90400DB3ED1 /* Products */;
ProjectRef = 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */;
},
{
ProductGroup = 00C302BC1ABCB91800DB3ED1 /* Products */;
ProjectRef = 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */;
},
{
ProductGroup = 78C398B11ACF4ADC00677621 /* Products */;
ProjectRef = 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */;
},
{
ProductGroup = 00C302D41ABCB9D200DB3ED1 /* Products */;
ProjectRef = 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */;
},
{
ProductGroup = 139105B71AF99BAD00B5F7CC /* Products */;
ProjectRef = 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */;
},
{
ProductGroup = 832341B11AAA6A8300B99B32 /* Products */;
ProjectRef = 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */;
},
{
ProductGroup = 00C302E01ABCB9EE00DB3ED1 /* Products */;
ProjectRef = 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */;
},
{
ProductGroup = 139FDEE71B06529A00C62182 /* Products */;
ProjectRef = 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */;
},
{
ProductGroup = 146834001AC3E56700842450 /* Products */;
ProjectRef = 146833FF1AC3E56700842450 /* React.xcodeproj */;
},
);
projectRoot = "";
targets = (
13B07F861A680F5B00A75B9A /* VideoPlayer */,
00E356ED1AD99517003FC87E /* VideoPlayerTests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
00C302AC1ABCB8CE00DB3ED1 /* libRCTActionSheet.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTActionSheet.a;
remoteRef = 00C302AB1ABCB8CE00DB3ED1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTGeolocation.a;
remoteRef = 00C302B91ABCB90400DB3ED1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
00C302C01ABCB91800DB3ED1 /* libRCTImage.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTImage.a;
remoteRef = 00C302BF1ABCB91800DB3ED1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTNetwork.a;
remoteRef = 00C302DB1ABCB9D200DB3ED1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTVibration.a;
remoteRef = 00C302E31ABCB9EE00DB3ED1 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
139105C11AF99BAD00B5F7CC /* libRCTSettings.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTSettings.a;
remoteRef = 139105C01AF99BAD00B5F7CC /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
139FDEF41B06529B00C62182 /* libRCTWebSocket.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTWebSocket.a;
remoteRef = 139FDEF31B06529B00C62182 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
146834041AC3E56700842450 /* libReact.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libReact.a;
remoteRef = 146834031AC3E56700842450 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
78C398B91ACF4ADC00677621 /* libRCTLinking.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTLinking.a;
remoteRef = 78C398B81ACF4ADC00677621 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
832341B51AAA6A8300B99B32 /* libRCTText.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libRCTText.a;
remoteRef = 832341B41AAA6A8300B99B32 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
00E356EC1AD99517003FC87E /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
13B07F8E1A680F5B00A75B9A /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
13B07FBF1A68108700A75B9A /* Images.xcassets in Resources */,
13B07FBD1A68108700A75B9A /* LaunchScreen.xib in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
00DD1BFF1BD5951E006B06BC /* Bundle React Native code and images */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "Bundle React Native code and images";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "export NODE_BINARY=node\n../node_modules/react-native/packager/react-native-xcode.sh";
showEnvVarsInLog = 1;
};
/* 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.m 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 PBXVariantGroup section */
13B07FB11A68108700A75B9A /* LaunchScreen.xib */ = {
isa = PBXVariantGroup;
children = (
13B07FB21A68108700A75B9A /* Base */,
);
name = LaunchScreen.xib;
path = VideoPlayer;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
00E356F61AD99517003FC87E /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
INFOPLIST_FILE = VideoPlayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VideoPlayer.app/VideoPlayer";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
};
name = Debug;
};
00E356F71AD99517003FC87E /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
INFOPLIST_FILE = VideoPlayerTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_NAME = "$(TARGET_NAME)";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/VideoPlayer.app/VideoPlayer";
LIBRARY_SEARCH_PATHS = (
"$(inherited)",
"\"$(SRCROOT)/$(TARGET_NAME)\"",
);
};
name = Release;
};
13B07F941A680F5B00A75B9A /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEAD_CODE_STRIPPING = NO;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-video",
);
INFOPLIST_FILE = "VideoPlayer/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = VideoPlayer;
};
name = Debug;
};
13B07F951A680F5B00A75B9A /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-video",
);
INFOPLIST_FILE = "VideoPlayer/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = VideoPlayer;
};
name = Release;
};
83CBBA201A601CBA00E9B192 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
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;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
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;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-video",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
83CBBA211A601CBA00E9B192 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
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;
GCC_C_LANGUAGE_STANDARD = gnu99;
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;
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../node_modules/react-native/React/**",
"$(SRCROOT)/../node_modules/react-native-video",
);
IPHONEOS_DEPLOYMENT_TARGET = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
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

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

View File

@ -0,0 +1,16 @@
/**
* 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>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) UIWindow *window;
@end

View File

@ -0,0 +1,59 @@
/**
* 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 "RCTRootView.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSURL *jsCodeLocation;
/**
* Loading JavaScript code - uncomment the one you want.
*
* OPTION 1
* Load from development server. Start the server from the repository root:
*
* $ npm start
*
* To run on device, change `localhost` to the IP address of your computer
* (you can get this by typing `ifconfig` into the terminal and selecting the
* `inet` value under `en0:`) and make sure your computer and iOS device are
* on the same Wi-Fi network.
*/
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];
/**
* OPTION 2
* Load from pre-bundled file on disk. The static bundle is automatically
* generated by the "Bundle React Native code and images" build step when
* running the project on an actual device or running the project on the
* simulator in the "Release" build configuration.
*/
// jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
moduleName:@"VideoPlayer"
initialProperties:nil
launchOptions:launchOptions];
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UIViewController *rootViewController = [UIViewController new];
rootViewController.view = rootView;
self.window.rootViewController = rootViewController;
[self.window makeKeyAndVisible];
return YES;
}
@end

View File

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7702" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7701"/>
<capability name="Constraints with non-1.0 multipliers" minToolsVersion="5.1"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<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="8ie-xW-0ye">
<rect key="frame" x="20" y="439" width="441" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<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="kId-c2-rCX">
<rect key="frame" x="20" y="140" width="441" height="43"/>
<fontDescription key="fontDescription" type="boldSystem" pointSize="36"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<constraints>
<constraint firstItem="kId-c2-rCX" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="bottom" multiplier="1/3" constant="1" id="5cJ-9S-tgC"/>
<constraint firstAttribute="centerX" secondItem="kId-c2-rCX" secondAttribute="centerX" id="Koa-jz-hwk"/>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Kzo-t9-V3l"/>
<constraint firstItem="8ie-xW-0ye" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="MfP-vx-nX0"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
<constraint firstItem="kId-c2-rCX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="20" symbolic="YES" id="fvb-Df-36g"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="548" y="455"/>
</view>
</objects>
</document>

View File

@ -0,0 +1,38 @@
{
"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

@ -0,0 +1,48 @@
<?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>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</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>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/>
<key>NSLocationWhenInUseUsageDescription</key>
<string></string>
<key>NSAppTransportSecurity</key>
<dict>
<!--See http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/ -->
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,18 @@
/**
* 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

@ -0,0 +1,24 @@
<?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>org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)</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,70 @@
/**
* 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 <XCTest/XCTest.h>
#import "RCTLog.h"
#import "RCTRootView.h"
#define TIMEOUT_SECONDS 240
#define TEXT_TO_LOOK_FOR @"Welcome to React Native!"
@interface VideoPlayerTests : XCTestCase
@end
@implementation VideoPlayerTests
- (BOOL)findSubviewInView:(UIView *)view matching:(BOOL(^)(UIView *view))test
{
if (test(view)) {
return YES;
}
for (UIView *subview in [view subviews]) {
if ([self findSubviewInView:subview matching:test]) {
return YES;
}
}
return NO;
}
- (void)testRendersWelcomeScreen
{
UIViewController *vc = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:TIMEOUT_SECONDS];
BOOL foundElement = NO;
__block NSString *redboxError = nil;
RCTSetLogFunction(^(RCTLogLevel level, RCTLogSource source, NSString *fileName, NSNumber *lineNumber, NSString *message) {
if (level >= RCTLogLevelError) {
redboxError = message;
}
});
while ([date timeIntervalSinceNow] > 0 && !foundElement && !redboxError) {
[[NSRunLoop mainRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
[[NSRunLoop mainRunLoop] runMode:NSRunLoopCommonModes beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1]];
foundElement = [self findSubviewInView:vc.view matching:^BOOL(UIView *view) {
if ([view.accessibilityLabel isEqualToString:TEXT_TO_LOOK_FOR]) {
return YES;
}
return NO;
}];
}
RCTSetLogFunction(RCTDefaultLogFunction);
XCTAssertNil(redboxError, @"RedBox error: %@", redboxError);
XCTAssertTrue(foundElement, @"Couldn't find element with text '%@' in %d seconds", TEXT_TO_LOOK_FOR, TIMEOUT_SECONDS);
}
@end

View File

@ -1,35 +1,39 @@
'use strict'; 'use strict';
var React = require('react-native'); import React, {
var {
AppRegistry, AppRegistry,
Component,
StyleSheet, StyleSheet,
Text, Text,
View,
TouchableOpacity, TouchableOpacity,
} = React; View,
} from 'react-native';
var Video = require('react-native-video'); import Video from 'react-native-video';
var VideoPlayer = React.createClass({ class VideoPlayer extends Component {
getInitialState() { constructor(props) {
return { super(props);
rate: 1, this.onLoad = this.onLoad.bind(this);
volume: 1, this.onProgress = this.onProgress.bind(this);
muted: false, }
resizeMode: 'contain',
duration: 0.0, state = {
currentTime: 0.0, rate: 1,
} volume: 1,
}, muted: false,
resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
};
onLoad(data) { onLoad(data) {
this.setState({duration: data.duration}); this.setState({duration: data.duration});
}, }
onProgress(data) { onProgress(data) {
this.setState({currentTime: data.currentTime}); this.setState({currentTime: data.currentTime});
}, }
getCurrentTimePercentage() { getCurrentTimePercentage() {
if (this.state.currentTime > 0) { if (this.state.currentTime > 0) {
@ -37,10 +41,10 @@ var VideoPlayer = React.createClass({
} else { } else {
return 0; return 0;
} }
}, }
renderRateControl(rate) { renderRateControl(rate) {
var isSelected = (this.state.rate == rate); const isSelected = (this.state.rate == rate);
return ( return (
<TouchableOpacity onPress={() => { this.setState({rate: rate}) }}> <TouchableOpacity onPress={() => { this.setState({rate: rate}) }}>
@ -49,10 +53,10 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
renderResizeModeControl(resizeMode) { renderResizeModeControl(resizeMode) {
var isSelected = (this.state.resizeMode == resizeMode); const isSelected = (this.state.resizeMode == resizeMode);
return ( return (
<TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}> <TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}>
@ -61,10 +65,10 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
renderVolumeControl(volume) { renderVolumeControl(volume) {
var isSelected = (this.state.volume == volume); const isSelected = (this.state.volume == volume);
return ( return (
<TouchableOpacity onPress={() => { this.setState({volume: volume}) }}> <TouchableOpacity onPress={() => { this.setState({volume: volume}) }}>
@ -73,11 +77,11 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
render() { render() {
var flexCompleted = this.getCurrentTimePercentage() * 100; const flexCompleted = this.getCurrentTimePercentage() * 100;
var flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
return ( return (
<View style={styles.container}> <View style={styles.container}>
@ -128,10 +132,10 @@ var VideoPlayer = React.createClass({
</View> </View>
); );
} }
}); }
var styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',

View File

@ -1,36 +1,42 @@
'use strict'; 'use strict';
var React = require('react-native'); import React, {
var { AlertIOS,
AppRegistry, AppRegistry,
Component,
StyleSheet, StyleSheet,
Text, Text,
View,
TouchableOpacity, TouchableOpacity,
AlertIOS, View,
} = React; } from 'react-native';
var Video = require('react-native-video'); import Video from 'react-native-video';
var VideoPlayer = React.createClass({ class VideoPlayer extends Component {
getInitialState() { constructor(props) {
return { super(props);
rate: 1, this.onLoad = this.onLoad.bind(this);
volume: 1, this.onProgress = this.onProgress.bind(this);
muted: false, }
resizeMode: 'contain', state = {
duration: 0.0, rate: 1,
currentTime: 0.0, volume: 1,
} muted: false,
}, resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
controls: false,
paused: true,
skin: 'custom'
};
onLoad(data) { onLoad(data) {
this.setState({duration: data.duration}); this.setState({duration: data.duration});
}, }
onProgress(data) { onProgress(data) {
this.setState({currentTime: data.currentTime}); this.setState({currentTime: data.currentTime});
}, }
getCurrentTimePercentage() { getCurrentTimePercentage() {
if (this.state.currentTime > 0) { if (this.state.currentTime > 0) {
@ -38,10 +44,25 @@ var VideoPlayer = React.createClass({
} else { } else {
return 0; return 0;
} }
}, }
renderSkinControl(skin) {
const isSelected = this.state.skin == skin;
const selectControls = skin == 'native' || skin == 'embed';
return (
<TouchableOpacity onPress={() => { this.setState({
controls: selectControls,
skin: skin
}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{skin}
</Text>
</TouchableOpacity>
);
}
renderRateControl(rate) { renderRateControl(rate) {
var isSelected = (this.state.rate == rate); const isSelected = (this.state.rate == rate);
return ( return (
<TouchableOpacity onPress={() => { this.setState({rate: rate}) }}> <TouchableOpacity onPress={() => { this.setState({rate: rate}) }}>
@ -50,10 +71,10 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
renderResizeModeControl(resizeMode) { renderResizeModeControl(resizeMode) {
var isSelected = (this.state.resizeMode == resizeMode); const isSelected = (this.state.resizeMode == resizeMode);
return ( return (
<TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}> <TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}>
@ -62,10 +83,10 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
renderVolumeControl(volume) { renderVolumeControl(volume) {
var isSelected = (this.state.volume == volume); const isSelected = (this.state.volume == volume);
return ( return (
<TouchableOpacity onPress={() => { this.setState({volume: volume}) }}> <TouchableOpacity onPress={() => { this.setState({volume: volume}) }}>
@ -74,35 +95,42 @@ var VideoPlayer = React.createClass({
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
) )
}, }
render() { renderCustomSkin() {
var flexCompleted = this.getCurrentTimePercentage() * 100; const flexCompleted = this.getCurrentTimePercentage() * 100;
var flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
return ( return (
<View style={styles.container}> <View style={styles.container}>
<TouchableOpacity style={styles.fullScreen} onPress={() => {this.setState({paused: !this.state.paused})}}> <TouchableOpacity style={styles.fullScreen} onPress={() => {this.setState({paused: !this.state.paused})}}>
<Video source={{uri: "broadchurch"}} <Video
style={styles.fullScreen} source={{uri: "broadchurch"}}
rate={this.state.rate} style={styles.fullScreen}
paused={this.state.paused} rate={this.state.rate}
volume={this.state.volume} paused={this.state.paused}
muted={this.state.muted} volume={this.state.volume}
resizeMode={this.state.resizeMode} muted={this.state.muted}
onLoad={this.onLoad} resizeMode={this.state.resizeMode}
onProgress={this.onProgress} onLoad={this.onLoad}
onEnd={() => { AlertIOS.alert('Done!') }} onProgress={this.onProgress}
repeat={true} /> onEnd={() => { AlertIOS.alert('Done!') }}
repeat={true}
/>
</TouchableOpacity> </TouchableOpacity>
<View style={styles.controls}> <View style={styles.controls}>
<View style={styles.generalControls}>
<View style={styles.skinControl}>
{this.renderSkinControl('custom')}
{this.renderSkinControl('native')}
{this.renderSkinControl('embed')}
</View>
</View>
<View style={styles.generalControls}> <View style={styles.generalControls}>
<View style={styles.rateControl}> <View style={styles.rateControl}>
{this.renderRateControl(0.25)}
{this.renderRateControl(0.5)} {this.renderRateControl(0.5)}
{this.renderRateControl(1.0)} {this.renderRateControl(1.0)}
{this.renderRateControl(1.5)}
{this.renderRateControl(2.0)} {this.renderRateControl(2.0)}
</View> </View>
@ -129,10 +157,66 @@ var VideoPlayer = React.createClass({
</View> </View>
); );
} }
});
renderNativeSkin() {
const videoStyle = this.state.skin == 'embed' ? styles.nativeVideoControls : styles.fullScreen;
return (
<View style={styles.container}>
<View style={styles.fullScreen}>
<Video
source={{uri: "broadchurch"}}
style={videoStyle}
rate={this.state.rate}
paused={this.state.paused}
volume={this.state.volume}
muted={this.state.muted}
resizeMode={this.state.resizeMode}
onLoad={this.onLoad}
onProgress={this.onProgress}
onEnd={() => { AlertIOS.alert('Done!') }}
repeat={true}
controls={this.state.controls}
/>
</View>
<View style={styles.controls}>
<View style={styles.generalControls}>
<View style={styles.skinControl}>
{this.renderSkinControl('custom')}
{this.renderSkinControl('native')}
{this.renderSkinControl('embed')}
</View>
</View>
<View style={styles.generalControls}>
<View style={styles.rateControl}>
{this.renderRateControl(0.5)}
{this.renderRateControl(1.0)}
{this.renderRateControl(2.0)}
</View>
var styles = StyleSheet.create({ <View style={styles.volumeControl}>
{this.renderVolumeControl(0.5)}
{this.renderVolumeControl(1)}
{this.renderVolumeControl(1.5)}
</View>
<View style={styles.resizeModeControl}>
{this.renderResizeModeControl('cover')}
{this.renderResizeModeControl('contain')}
{this.renderResizeModeControl('stretch')}
</View>
</View>
</View>
</View>
);
}
render() {
return this.state.controls ? this.renderNativeSkin() : this.renderCustomSkin();
}
}
const styles = StyleSheet.create({
container: { container: {
flex: 1, flex: 1,
justifyContent: 'center', justifyContent: 'center',
@ -150,9 +234,9 @@ var styles = StyleSheet.create({
backgroundColor: "transparent", backgroundColor: "transparent",
borderRadius: 5, borderRadius: 5,
position: 'absolute', position: 'absolute',
bottom: 20, bottom: 44,
left: 20, left: 4,
right: 20, right: 4,
}, },
progress: { progress: {
flex: 1, flex: 1,
@ -171,10 +255,14 @@ var styles = StyleSheet.create({
generalControls: { generalControls: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
borderRadius: 4,
overflow: 'hidden', overflow: 'hidden',
paddingBottom: 10, paddingBottom: 10,
}, },
skinControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
rateControl: { rateControl: {
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
@ -189,7 +277,7 @@ var styles = StyleSheet.create({
flex: 1, flex: 1,
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
justifyContent: 'center', justifyContent: 'center'
}, },
controlOption: { controlOption: {
alignSelf: 'center', alignSelf: 'center',
@ -199,6 +287,10 @@ var styles = StyleSheet.create({
paddingRight: 2, paddingRight: 2,
lineHeight: 12, lineHeight: 12,
}, },
nativeVideoControls: {
top: 184,
height: 300
}
}); });
AppRegistry.registerComponent('VideoPlayer', () => VideoPlayer); AppRegistry.registerComponent('VideoPlayer', () => VideoPlayer);

View File

@ -1,260 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */; };
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTVideo.a; sourceTree = BUILT_PRODUCTS_DIR; };
BBD49E391AC8DEF000610F8E /* RCTVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideo.h; sourceTree = "<group>"; };
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = "<group>"; };
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = "<group>"; };
BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideoManager.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRCTVideo.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
BBD49E391AC8DEF000610F8E /* RCTVideo.h */,
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */,
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */,
BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */,
134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RCTVideo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTVideo" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RCTVideo;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRCTVideo.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Facebook;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTVideo" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RCTVideo */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */,
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
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 = 7.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
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 = 7.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../react-native/React/**",
"$(SRCROOT)/node_modules/react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTVideo;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
HEADER_SEARCH_PATHS = (
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../react-native/React/**",
"$(SRCROOT)/node_modules/react-native/React/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = RCTVideo;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RCTVideo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RCTVideo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}

View File

@ -1,12 +1,13 @@
{ {
"name": "VideoPlayer", "name": "VideoPlayer",
"version": "0.0.1", "version": "1.0.0",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "node_modules/react-native/packager/packager.sh" "start": "node_modules/react-native/packager/packager.sh"
}, },
"dependencies": { "dependencies": {
"react-native": "^0.16.0", "react": "^0.14.8",
"react-native-video": "brentvatne/react-native-video#feature/android-support" "react-native": "0.23.0",
"react-native-video": "../../"
} }
} }

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2016 Brent Vatne, Baris Sencan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,9 +1,16 @@
#import "RCTView.h" #import "RCTView.h"
#import <AVFoundation/AVFoundation.h>
#import "AVKit/AVKit.h"
#import "UIView+FindUIViewController.h"
#import "RCTVideoPlayerViewController.h"
#import "RCTVideoPlayerViewControllerDelegate.h"
@class RCTEventDispatcher; @class RCTEventDispatcher;
@interface RCTVideo : UIView @interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate>
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem;
@end @end

View File

@ -3,17 +3,19 @@
#import "RCTBridgeModule.h" #import "RCTBridgeModule.h"
#import "RCTEventDispatcher.h" #import "RCTEventDispatcher.h"
#import "UIView+React.h" #import "UIView+React.h"
#import <AVFoundation/AVFoundation.h>
static NSString *const statusKeyPath = @"status"; static NSString *const statusKeyPath = @"status";
static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"; static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp";
static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty";
@implementation RCTVideo @implementation RCTVideo
{ {
AVPlayer *_player; AVPlayer *_player;
AVPlayerItem *_playerItem; AVPlayerItem *_playerItem;
BOOL _playerItemObserversSet; BOOL _playerItemObserversSet;
BOOL _playerBufferEmpty;
AVPlayerLayer *_playerLayer; AVPlayerLayer *_playerLayer;
AVPlayerViewController *_playerViewController;
NSURL *_videoURL; NSURL *_videoURL;
/* Required to publish events */ /* Required to publish events */
@ -24,9 +26,9 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
float _lastSeekTime; float _lastSeekTime;
/* For sending videoProgress events */ /* For sending videoProgress events */
id _progressUpdateTimer; Float64 _progressUpdateInterval;
int _progressUpdateInterval; BOOL _controls;
NSDate *_prevProgressUpdateTime; id _timeObserver;
/* Keep track of any modifiers, need to be applied after each play */ /* Keep track of any modifiers, need to be applied after each play */
float _volume; float _volume;
@ -36,6 +38,8 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
BOOL _repeat; BOOL _repeat;
BOOL _playInBackground; BOOL _playInBackground;
NSString * _resizeMode; NSString * _resizeMode;
BOOL _fullscreenPlayerPresented;
UIViewController * _presentingViewController;
} }
- (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
@ -49,7 +53,10 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
_pendingSeek = false; _pendingSeek = false;
_pendingSeekTime = 0.0f; _pendingSeekTime = 0.0f;
_lastSeekTime = 0.0f; _lastSeekTime = 0.0f;
_playInBackground = false; _progressUpdateInterval = 250;
_controls = NO;
_playerBufferEmpty = YES;
_playInBackground = false;
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:) selector:@selector(applicationWillResignActive:)
@ -65,6 +72,44 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
return self; return self;
} }
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem {
RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
playerLayer.showsPlaybackControls = NO;
playerLayer.rctDelegate = self;
playerLayer.view.frame = self.bounds;
playerLayer.player = _player;
playerLayer.view.frame = self.bounds;
return playerLayer;
}
/* ---------------------------------------------------------
** Get the duration for a AVPlayerItem.
** ------------------------------------------------------- */
- (CMTime)playerItemDuration
{
AVPlayerItem *playerItem = [_player currentItem];
if (playerItem.status == AVPlayerItemStatusReadyToPlay)
{
return([playerItem duration]);
}
return(kCMTimeInvalid);
}
/* Cancels the previously registered time observer. */
-(void)removePlayerTimeObserver
{
if (_timeObserver)
{
[_player removeTimeObserver:_timeObserver];
_timeObserver = nil;
}
}
#pragma mark - Progress
- (void)dealloc - (void)dealloc
{ {
[[NSNotificationCenter defaultCenter] removeObserver:self]; [[NSNotificationCenter defaultCenter] removeObserver:self];
@ -74,15 +119,14 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)applicationWillResignActive:(NSNotification *)notification - (void)applicationWillResignActive:(NSNotification *)notification
{ {
if (!_paused && !_playInBackground) { if (!_paused && !_playInBackground) {
[self stopProgressTimer]; [_player pause];
[_player setRate:0.0]; [_player setRate:0.0];
} }
} }
- (void)applicationWillEnterForeground:(NSNotification *)notification - (void)applicationWillEnterForeground:(NSNotification *)notification
{ {
[self startProgressTimer];
[self applyModifiers]; [self applyModifiers];
} }
@ -90,18 +134,29 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)sendProgressUpdate - (void)sendProgressUpdate
{ {
AVPlayerItem *video = [_player currentItem]; AVPlayerItem *video = [_player currentItem];
if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) { if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) {
return; return;
} }
if (_prevProgressUpdateTime == nil || (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) { CMTime playerDuration = [self playerItemDuration];
[_eventDispatcher sendInputEventWithName:@"onVideoProgress" if (CMTIME_IS_INVALID(playerDuration)) {
body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], return;
@"playableDuration": [self calculatePlayableDuration], }
@"target": self.reactTag}];
_prevProgressUpdateTime = [NSDate date]; CMTime currentTime = _player.currentTime;
} const Float64 duration = CMTimeGetSeconds(playerDuration);
const Float64 currentTimeSecs = CMTimeGetSeconds(currentTime);
if( currentTimeSecs >= 0 && currentTimeSecs <= duration) {
[_eventDispatcher sendInputEventWithName:@"onVideoProgress"
body:@{
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(currentTime)],
@"playableDuration": [self calculatePlayableDuration],
@"atValue": [NSNumber numberWithLongLong:currentTime.value],
@"atTimescale": [NSNumber numberWithInt:currentTime.timescale],
@"target": self.reactTag
}];
}
} }
/*! /*!
@ -129,25 +184,10 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
return [NSNumber numberWithInteger:0]; return [NSNumber numberWithInteger:0];
} }
- (void)stopProgressTimer
{
[_progressUpdateTimer invalidate];
}
- (void)startProgressTimer
{
_progressUpdateInterval = 250;
_prevProgressUpdateTime = nil;
[self stopProgressTimer];
_progressUpdateTimer = [CADisplayLink displayLinkWithTarget:self selector:@selector(sendProgressUpdate)];
[_progressUpdateTimer addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)addPlayerItemObservers - (void)addPlayerItemObservers
{ {
[_playerItem addObserver:self forKeyPath:statusKeyPath options:0 context:nil]; [_playerItem addObserver:self forKeyPath:statusKeyPath options:0 context:nil];
[_playerItem addObserver:self forKeyPath:playbackBufferEmptyKeyPath options:0 context:nil];
[_playerItem addObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath options:0 context:nil]; [_playerItem addObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath options:0 context:nil];
_playerItemObserversSet = YES; _playerItemObserversSet = YES;
} }
@ -159,6 +199,7 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
{ {
if (_playerItemObserversSet) { if (_playerItemObserversSet) {
[_playerItem removeObserver:self forKeyPath:statusKeyPath]; [_playerItem removeObserver:self forKeyPath:statusKeyPath];
[_playerItem removeObserver:self forKeyPath:playbackBufferEmptyKeyPath];
[_playerItem removeObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath]; [_playerItem removeObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath];
_playerItemObserversSet = NO; _playerItemObserversSet = NO;
} }
@ -168,25 +209,27 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)setSrc:(NSDictionary *)source - (void)setSrc:(NSDictionary *)source
{ {
[self removePlayerTimeObserver];
[self removePlayerItemObservers]; [self removePlayerItemObservers];
_playerItem = [self playerItemForSource:source]; _playerItem = [self playerItemForSource:source];
[self addPlayerItemObservers]; [self addPlayerItemObservers];
[_player pause]; [_player pause];
[_playerLayer removeFromSuperlayer]; [_playerLayer removeFromSuperlayer];
_playerLayer = nil;
[_playerViewController.view removeFromSuperview];
_playerViewController = nil;
_player = [AVPlayer playerWithPlayerItem:_playerItem]; _player = [AVPlayer playerWithPlayerItem:_playerItem];
_player.actionAtItemEnd = AVPlayerActionAtItemEndNone; _player.actionAtItemEnd = AVPlayerActionAtItemEndNone;
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player]; const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000;
_playerLayer.frame = self.bounds; // @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html
_playerLayer.needsDisplayOnBoundsChange = YES; __weak RCTVideo *weakSelf = self;
_timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(progressUpdateIntervalMS, NSEC_PER_SEC)
[self applyModifiers]; queue:NULL
usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; }
[self.layer addSublayer:_playerLayer]; ];
self.layer.needsDisplayOnBoundsChange = YES;
[_eventDispatcher sendInputEventWithName:@"onVideoLoadStart" [_eventDispatcher sendInputEventWithName:@"onVideoLoadStart"
body:@{@"src": @{ body:@{@"src": @{
@"uri": [source objectForKey:@"uri"], @"uri": [source objectForKey:@"uri"],
@ -216,7 +259,7 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{ {
if (object == _playerItem) { if (object == _playerItem) {
if ([keyPath isEqualToString:statusKeyPath]) { if ([keyPath isEqualToString:statusKeyPath]) {
// Handle player item status change. // Handle player item status change.
@ -227,6 +270,13 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
duration = 0.0; duration = 0.0;
} }
NSObject *width = @"undefined";
NSObject *height = @"undefined";
if ([_playerItem.asset tracksWithMediaType:AVMediaTypeVideo].count > 0) {
width = [NSNumber numberWithFloat:[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo][0].naturalSize.width];
height = [NSNumber numberWithFloat:[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo][0].naturalSize.height];
}
[_eventDispatcher sendInputEventWithName:@"onVideoLoad" [_eventDispatcher sendInputEventWithName:@"onVideoLoad"
body:@{@"duration": [NSNumber numberWithFloat:duration], body:@{@"duration": [NSNumber numberWithFloat:duration],
@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)], @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
@ -236,9 +286,12 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
@"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse], @"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse],
@"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward], @"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward],
@"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward], @"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward],
@"naturalSize": @{
@"width": width,
@"height": height
},
@"target": self.reactTag}]; @"target": self.reactTag}];
[self startProgressTimer];
[self attachListeners]; [self attachListeners];
[self applyModifiers]; [self applyModifiers];
} else if(_playerItem.status == AVPlayerItemStatusFailed) { } else if(_playerItem.status == AVPlayerItemStatusFailed) {
@ -248,14 +301,17 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
@"domain": _playerItem.error.domain}, @"domain": _playerItem.error.domain},
@"target": self.reactTag}]; @"target": self.reactTag}];
} }
} else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) {
_playerBufferEmpty = YES;
} else if ([keyPath isEqualToString:playbackLikelyToKeepUpKeyPath]) { } else if ([keyPath isEqualToString:playbackLikelyToKeepUpKeyPath]) {
// Continue playing (or not if paused) after being paused due to hitting an unbuffered zone. // Continue playing (or not if paused) after being paused due to hitting an unbuffered zone.
if (_playerItem.playbackLikelyToKeepUp) { if ((!_controls || _playerBufferEmpty) && _playerItem.playbackLikelyToKeepUp) {
[self setPaused:_paused]; [self setPaused:_paused];
} }
_playerBufferEmpty = NO;
} }
} else { } else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
} }
} }
@ -283,8 +339,15 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)setResizeMode:(NSString*)mode - (void)setResizeMode:(NSString*)mode
{ {
if( _controls )
{
_playerViewController.videoGravity = mode;
}
else
{
_playerLayer.videoGravity = mode;
}
_resizeMode = mode; _resizeMode = mode;
_playerLayer.videoGravity = mode;
} }
- (void)setPlayInBackground:(BOOL)playInBackground - (void)setPlayInBackground:(BOOL)playInBackground
@ -295,16 +358,26 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
- (void)setPaused:(BOOL)paused - (void)setPaused:(BOOL)paused
{ {
if (paused) { if (paused) {
[self stopProgressTimer]; [_player pause];
[_player setRate:0.0]; [_player setRate:0.0];
} else { } else {
[self startProgressTimer]; [_player play];
[_player setRate:_rate]; [_player setRate:_rate];
} }
_paused = paused; _paused = paused;
} }
- (float)getCurrentTime
{
return _playerItem != NULL ? CMTimeGetSeconds(_playerItem.currentTime) : 0;
}
- (void)setCurrentTime:(float)currentTime
{
[self setSeek: currentTime];
}
- (void)setSeek:(float)seekTime - (void)setSeek:(float)seekTime
{ {
int timeScale = 10000; int timeScale = 10000;
@ -367,48 +440,195 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"
[self setResizeMode:_resizeMode]; [self setResizeMode:_resizeMode];
[self setRepeat:_repeat]; [self setRepeat:_repeat];
[self setPaused:_paused]; [self setPaused:_paused];
[self setControls:_controls];
} }
- (void)setRepeat:(BOOL)repeat { - (void)setRepeat:(BOOL)repeat {
_repeat = repeat; _repeat = repeat;
} }
- (BOOL)getFullscreen
{
return _fullscreenPlayerPresented;
}
- (void)setFullscreen:(BOOL)fullscreen
{
if( fullscreen && !_fullscreenPlayerPresented )
{
// Ensure player view controller is not null
if( !_playerViewController )
{
[self usePlayerViewController];
}
// Set presentation style to fullscreen
[_playerViewController setModalPresentationStyle:UIModalPresentationFullScreen];
// Find the nearest view controller
UIViewController *viewController = [self firstAvailableUIViewController];
if( !viewController )
{
UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
viewController = keyWindow.rootViewController;
if( viewController.childViewControllers.count > 0 )
{
viewController = viewController.childViewControllers.lastObject;
}
}
if( viewController )
{
_presentingViewController = viewController;
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillPresent" body:@{@"target": self.reactTag}];
[viewController presentViewController:_playerViewController animated:true completion:^{
_playerViewController.showsPlaybackControls = YES;
_fullscreenPlayerPresented = fullscreen;
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidPresent" body:@{@"target": self.reactTag}];
}];
}
}
else if ( !fullscreen && _fullscreenPlayerPresented )
{
[self videoPlayerViewControllerWillDismiss:_playerViewController];
[_presentingViewController dismissViewControllerAnimated:true completion:^{
[self videoPlayerViewControllerDidDismiss:_playerViewController];
}];
}
}
- (void)usePlayerViewController
{
if( _player )
{
_playerViewController = [self createPlayerViewController:_player withPlayerItem:_playerItem];
[self addSubview:_playerViewController.view];
}
}
- (void)usePlayerLayer
{
if( _player )
{
_playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
_playerLayer.frame = self.bounds;
_playerLayer.needsDisplayOnBoundsChange = YES;
[self.layer addSublayer:_playerLayer];
self.layer.needsDisplayOnBoundsChange = YES;
}
}
- (void)setControls:(BOOL)controls
{
if( _controls != controls || (!_playerLayer && !_playerViewController) )
{
_controls = controls;
if( _controls )
{
[_playerLayer removeFromSuperlayer];
_playerLayer = nil;
[self usePlayerViewController];
}
else
{
[_playerViewController.view removeFromSuperview];
_playerViewController = nil;
[self usePlayerLayer];
}
}
}
#pragma mark - RCTVideoPlayerViewControllerDelegate
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController
{
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
{
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerWillDismiss" body:@{@"target": self.reactTag}];
}
}
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController
{
if (_playerViewController == playerViewController && _fullscreenPlayerPresented)
{
_fullscreenPlayerPresented = false;
_presentingViewController = nil;
[self applyModifiers];
[_eventDispatcher sendInputEventWithName:@"onVideoFullscreenPlayerDidDismiss" body:@{@"target": self.reactTag}];
}
}
#pragma mark - React View Management #pragma mark - React View Management
- (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex - (void)insertReactSubview:(UIView *)view atIndex:(NSInteger)atIndex
{ {
RCTLogError(@"video cannot have any subviews"); // We are early in the game and somebody wants to set a subview.
// That can only be in the context of playerViewController.
if( !_controls && !_playerLayer && !_playerViewController )
{
[self setControls:true];
}
if( _controls )
{
view.frame = self.bounds;
[_playerViewController.contentOverlayView insertSubview:view atIndex:atIndex];
}
else
{
RCTLogError(@"video cannot have any subviews");
}
return; return;
} }
- (void)removeReactSubview:(UIView *)subview - (void)removeReactSubview:(UIView *)subview
{ {
RCTLogError(@"video cannot have any subviews"); if( _controls )
{
[subview removeFromSuperview];
}
else
{
RCTLogError(@"video cannot have any subviews");
}
return; return;
} }
- (void)layoutSubviews - (void)layoutSubviews
{ {
[super layoutSubviews]; [super layoutSubviews];
[CATransaction begin]; if( _controls )
[CATransaction setAnimationDuration:0]; {
_playerLayer.frame = self.bounds; _playerViewController.view.frame = self.bounds;
[CATransaction commit];
// also adjust all subviews of contentOverlayView
for (UIView* subview in _playerViewController.contentOverlayView.subviews) {
subview.frame = self.bounds;
}
}
else
{
[CATransaction begin];
[CATransaction setAnimationDuration:0];
_playerLayer.frame = self.bounds;
[CATransaction commit];
}
} }
#pragma mark - Lifecycle #pragma mark - Lifecycle
- (void)removeFromSuperview - (void)removeFromSuperview
{ {
[_progressUpdateTimer invalidate];
_prevProgressUpdateTime = nil;
[_player pause]; [_player pause];
_player = nil; _player = nil;
[_playerLayer removeFromSuperlayer]; [_playerLayer removeFromSuperlayer];
_playerLayer = nil; _playerLayer = nil;
[_playerViewController.view removeFromSuperview];
_playerViewController = nil;
[self removePlayerTimeObserver];
[self removePlayerItemObservers]; [self removePlayerItemObservers];
_eventDispatcher = nil; _eventDispatcher = nil;

View File

@ -7,6 +7,8 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
31CAFB211CADA8CD009BCF6F /* UIView+FindUIViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */; };
31CAFB2F1CADC77F009BCF6F /* RCTVideoPlayerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */; };
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */; }; BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */; };
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */; }; BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
@ -25,6 +27,11 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTVideo.a; sourceTree = BUILT_PRODUCTS_DIR; }; 134814201AA4EA6300B7C361 /* libRCTVideo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTVideo.a; sourceTree = BUILT_PRODUCTS_DIR; };
31CAFB1F1CADA8CD009BCF6F /* UIView+FindUIViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+FindUIViewController.h"; sourceTree = "<group>"; };
31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+FindUIViewController.m"; sourceTree = "<group>"; };
31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewController.h; sourceTree = "<group>"; };
31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideoPlayerViewController.m; sourceTree = "<group>"; };
31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewControllerDelegate.h; sourceTree = "<group>"; };
BBD49E391AC8DEF000610F8E /* RCTVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideo.h; sourceTree = "<group>"; }; BBD49E391AC8DEF000610F8E /* RCTVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideo.h; sourceTree = "<group>"; };
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = "<group>"; }; BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = "<group>"; };
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = "<group>"; }; BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = "<group>"; };
@ -55,8 +62,13 @@
children = ( children = (
BBD49E391AC8DEF000610F8E /* RCTVideo.h */, BBD49E391AC8DEF000610F8E /* RCTVideo.h */,
BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */, BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */,
31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */,
31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */,
31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */,
BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */, BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */,
BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */, BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */,
31CAFB1F1CADA8CD009BCF6F /* UIView+FindUIViewController.h */,
31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */,
134814211AA4EA7D00B7C361 /* Products */, 134814211AA4EA7D00B7C361 /* Products */,
); );
sourceTree = "<group>"; sourceTree = "<group>";
@ -87,7 +99,7 @@
58B511D31A9E6C8500147676 /* Project object */ = { 58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject; isa = PBXProject;
attributes = { attributes = {
LastUpgradeCheck = 0610; LastUpgradeCheck = 0720;
ORGANIZATIONNAME = Facebook; ORGANIZATIONNAME = Facebook;
TargetAttributes = { TargetAttributes = {
58B511DA1A9E6C8500147676 = { 58B511DA1A9E6C8500147676 = {
@ -117,6 +129,8 @@
isa = PBXSourcesBuildPhase; isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
31CAFB211CADA8CD009BCF6F /* UIView+FindUIViewController.m in Sources */,
31CAFB2F1CADC77F009BCF6F /* RCTVideoPlayerViewController.m in Sources */,
BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */, BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */,
BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */, BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */,
); );
@ -144,6 +158,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO; COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99; GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO; GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0; GCC_OPTIMIZATION_LEVEL = 0;
@ -205,7 +220,6 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../react-native/React/**", "$(SRCROOT)/../react-native/React/**",
"$(SRCROOT)/node_modules/react-native/React/**", "$(SRCROOT)/node_modules/react-native/React/**",
); );
@ -222,7 +236,6 @@
HEADER_SEARCH_PATHS = ( HEADER_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../react-native/React/**", "$(SRCROOT)/../react-native/React/**",
"$(SRCROOT)/node_modules/react-native/React/**", "$(SRCROOT)/node_modules/react-native/React/**",
); );

View File

@ -24,7 +24,11 @@ RCT_EXPORT_MODULE();
@"onVideoError", @"onVideoError",
@"onVideoProgress", @"onVideoProgress",
@"onVideoSeek", @"onVideoSeek",
@"onVideoEnd" @"onVideoEnd",
@"onVideoFullscreenPlayerWillPresent",
@"onVideoFullscreenPlayerDidPresent",
@"onVideoFullscreenPlayerWillDismiss",
@"onVideoFullscreenPlayerDidDismiss"
]; ];
} }
@ -38,10 +42,13 @@ RCT_EXPORT_VIEW_PROPERTY(resizeMode, NSString);
RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL); RCT_EXPORT_VIEW_PROPERTY(repeat, BOOL);
RCT_EXPORT_VIEW_PROPERTY(paused, BOOL); RCT_EXPORT_VIEW_PROPERTY(paused, BOOL);
RCT_EXPORT_VIEW_PROPERTY(muted, BOOL); RCT_EXPORT_VIEW_PROPERTY(muted, BOOL);
RCT_EXPORT_VIEW_PROPERTY(controls, BOOL);
RCT_EXPORT_VIEW_PROPERTY(volume, float); RCT_EXPORT_VIEW_PROPERTY(volume, float);
RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL); RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL);
RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(rate, float);
RCT_EXPORT_VIEW_PROPERTY(seek, float); RCT_EXPORT_VIEW_PROPERTY(seek, float);
RCT_EXPORT_VIEW_PROPERTY(currentTime, float);
RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL);
- (NSDictionary *)constantsToExport - (NSDictionary *)constantsToExport
{ {

View File

@ -0,0 +1,15 @@
//
// RCTVideoPlayerViewController.h
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <AVKit/AVKit.h>
#import "RCTVideo.h"
#import "RCTVideoPlayerViewControllerDelegate.h"
@interface RCTVideoPlayerViewController : AVPlayerViewController
@property (nonatomic, weak) id<RCTVideoPlayerViewControllerDelegate> rctDelegate;
@end

View File

@ -0,0 +1,28 @@
//
// RCTVideoPlayerViewController.m
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import "RCTVideoPlayerViewController.h"
@interface RCTVideoPlayerViewController ()
@end
@implementation RCTVideoPlayerViewController
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[_rctDelegate videoPlayerViewControllerDidDismiss:self];
}
- (void)viewWillDisappear:(BOOL)animated {
[_rctDelegate videoPlayerViewControllerWillDismiss:self];
[super viewWillDisappear:animated];
}
@end

View File

@ -0,0 +1,15 @@
//
// RCTVideoPlayerViewControllerDelegate.h
// RCTVideo
//
// Created by Stanisław Chmiela on 01.04.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "AVKit/AVKit.h"
@protocol RCTVideoPlayerViewControllerDelegate <NSObject>
- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController;
- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController;
@end

View File

@ -3,7 +3,7 @@
A <Video> component for react-native, as seen in A <Video> component for react-native, as seen in
[react-native-login](https://github.com/brentvatne/react-native-login)! [react-native-login](https://github.com/brentvatne/react-native-login)!
Requires react-native >= 0.4.4 Requires react-native >= 0.19.0
### Add it to your project ### Add it to your project
@ -11,17 +11,12 @@ Run `npm install react-native-video --save`
#### iOS #### iOS
1. Open your project in XCode, right click on `Libraries` and click `Add Files to "Your Project Name"` Install [rnpm](https://github.com/rnpm/rnpm) and run `rnpm link react-native-video`
* ![Screenshot](http://url.brentvatne.ca/jQp8.png) ![Screenshot](http://url.brentvatne.ca/1gqUD.png) (use the RCTVideo project rather than the one pictured in screenshot).
2. Add `libRTCVideo.a` to `Build Phases -> Link Binary With Libraries`
![(Screenshot)](http://url.brentvatne.ca/g9Wp.png).
3. Add `.mp4` video file to project and to `Build Phases -> Copy Bundle Resources`
4. Whenever you want to use it within React code now you can: `var Video =
require('react-native-video');`
#### Android #### Android
Make the following additions to the given files. First, copy your video file to `android/app/src/main/res/raw/`, then
make the following additions to the given files:
**android/settings.gradle** **android/settings.gradle**
``` ```
@ -70,7 +65,7 @@ Under `.addPackage(new MainReactPackage())`:
style={styles.backgroundVideo} /> style={styles.backgroundVideo} />
// Later on in your styles.. // Later on in your styles..
var styles = Stylesheet.create({ var styles = StyleSheet.create({
backgroundVideo: { backgroundVideo: {
position: 'absolute', position: 'absolute',
top: 0, top: 0,
@ -89,7 +84,7 @@ Seeks the video to the specified time (in seconds). Access using a ref to the co
## Examples ## Examples
- See an [Example integration][1] in `react-native-login`. - See an [Example integration][1] in `react-native-login` *note that this example uses an older version of this library, before we used `export default` -- if you use `require` you will need to do `require('react-native-video').default` as per instructions above.
- Try the included [VideoPlayer example][2] yourself: - Try the included [VideoPlayer example][2] yourself:
```sh ```sh
@ -102,12 +97,9 @@ Seeks the video to the specified time (in seconds). Access using a ref to the co
Then `Cmd+R` to start the React Packager, build and run the project in the simulator. Then `Cmd+R` to start the React Packager, build and run the project in the simulator.
## TODOS ## TODOS
- [ ] Add some way to interface with `seekToTime`
- [ ] Add support for captions - [ ] Add support for captions
- [ ] Support `require('video!...')`
- [ ] Add support for playing multiple videos in a sequence (will interfere with current `repeat` implementation) - [ ] Add support for playing multiple videos in a sequence (will interfere with current `repeat` implementation)
- [ ] Callback to get buffering progress for remote videos - [ ] Callback to get buffering progress for remote videos
- [ ] Bring API closer to HTML5 `<Video>` [reference](http://www.w3schools.com/tags/ref_av_dom.asp) - [ ] Bring API closer to HTML5 `<Video>` [reference](http://www.w3schools.com/tags/ref_av_dom.asp)

View File

@ -0,0 +1,15 @@
//
// UIView+FindUIViewController.h
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
// Source: http://stackoverflow.com/a/3732812/1123156
#import <UIKit/UIKit.h>
@interface UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController;
- (id) traverseResponderChainForUIViewController;
@end

View File

@ -0,0 +1,28 @@
//
// UIView+FindUIViewController.m
// RCTVideo
//
// Created by Stanisław Chmiela on 31.03.2016.
// Copyright © 2016 Facebook. All rights reserved.
//
// Source: http://stackoverflow.com/a/3732812/1123156
#import "UIView+FindUIViewController.h"
@implementation UIView (FindUIViewController)
- (UIViewController *) firstAvailableUIViewController {
// convenience function for casting and to "mask" the recursive function
return (UIViewController *)[self traverseResponderChainForUIViewController];
}
- (id) traverseResponderChainForUIViewController {
id nextResponder = [self nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return nextResponder;
} else if ([nextResponder isKindOfClass:[UIView class]]) {
return [nextResponder traverseResponderChainForUIViewController];
} else {
return nil;
}
}
@end

106
Video.js
View File

@ -1,4 +1,6 @@
const React = require('react-native'); import React from 'react-native';
import VideoResizeMode from './VideoResizeMode.js';
const { const {
Component, Component,
StyleSheet, StyleSheet,
@ -8,25 +10,30 @@ const {
View, View,
} = React; } = React;
const VideoResizeMode = require('./VideoResizeMode');
const styles = StyleSheet.create({ const styles = StyleSheet.create({
base: { base: {
overflow: 'hidden', overflow: 'hidden',
}, },
}); });
class Video extends Component { export default class Video extends Component {
constructor(props, context) { constructor(props, context) {
super(props, context); super(props, context);
this.seek = this.seek.bind(this); this.seek = this.seek.bind(this);
this.presentFullscreenPlayer = this.presentFullscreenPlayer.bind(this);
this.dismissFullscreenPlayer = this.dismissFullscreenPlayer.bind(this);
this._assignRoot = this._assignRoot.bind(this);
this._onLoadStart = this._onLoadStart.bind(this); this._onLoadStart = this._onLoadStart.bind(this);
this._onLoad = this._onLoad.bind(this); this._onLoad = this._onLoad.bind(this);
this._onError = this._onError.bind(this); this._onError = this._onError.bind(this);
this._onProgress = this._onProgress.bind(this); this._onProgress = this._onProgress.bind(this);
this._onSeek = this._onSeek.bind(this); this._onSeek = this._onSeek.bind(this);
this._onEnd = this._onEnd.bind(this); this._onEnd = this._onEnd.bind(this);
this._onFullscreenPlayerWillPresent = this._onFullscreenPlayerWillPresent.bind(this);
this._onFullscreenPlayerDidPresent = this._onFullscreenPlayerDidPresent.bind(this);
this._onFullscreenPlayerWillDismiss = this._onFullscreenPlayerWillDismiss.bind(this);
this._onFullscreenPlayerDidDismiss = this._onFullscreenPlayerDidDismiss.bind(this);
} }
setNativeProps(nativeProps) { setNativeProps(nativeProps) {
@ -34,48 +41,94 @@ class Video extends Component {
} }
seek(time) { seek(time) {
this.setNativeProps({ seek: parseFloat(time) }); this.setNativeProps({ seek: time });
}
presentFullscreenPlayer() {
this.setNativeProps({ fullscreen: true });
}
dismissFullscreenPlayer() {
this.setNativeProps({ fullscreen: false });
}
_assignRoot(component) {
this._root = component;
} }
_onLoadStart(event) { _onLoadStart(event) {
this.props.onLoadStart && this.props.onLoadStart(event.nativeEvent); if (this.props.onLoadStart) {
this.props.onLoadStart(event.nativeEvent);
}
} }
_onLoad(event) { _onLoad(event) {
this.props.onLoad && this.props.onLoad(event.nativeEvent); if (this.props.onLoad) {
this.props.onLoad(event.nativeEvent);
}
} }
_onError(event) { _onError(event) {
this.props.onError && this.props.onError(event.nativeEvent); if (this.props.onError) {
this.props.onError(event.nativeEvent);
}
} }
_onProgress(event) { _onProgress(event) {
this.props.onProgress && this.props.onProgress(event.nativeEvent); if (this.props.onProgress) {
this.props.onProgress(event.nativeEvent);
}
} }
_onSeek(event) { _onSeek(event) {
this.props.onSeek && this.props.onSeek(event.nativeEvent); if (this.props.onSeek) {
this.props.onSeek(event.nativeEvent);
}
} }
_onEnd(event) { _onEnd(event) {
this.props.onEnd && this.props.onEnd(event.nativeEvent); if (this.props.onEnd) {
this.props.onEnd(event.nativeEvent);
}
}
_onFullscreenPlayerWillPresent(event) {
if (this.props.onFullscreenPlayerWillPresent) {
this.props.onFullscreenPlayerWillPresent(event.nativeEvent);
}
}
_onFullscreenPlayerDidPresent(event) {
if (this.props.onFullscreenPlayerDidPresent) {
this.props.onFullscreenPlayerDidPresent(event.nativeEvent);
}
}
_onFullscreenPlayerWillDismiss(event) {
if (this.props.onFullscreenPlayerWillDismiss) {
this.props.onFullscreenPlayerWillDismiss(event.nativeEvent);
}
}
_onFullscreenPlayerDidDismiss(event) {
if (this.props.onFullscreenPlayerDidDismiss) {
this.props.onFullscreenPlayerDidDismiss(event.nativeEvent);
}
} }
render() { render() {
const { const {
style,
source, source,
ref,
resizeMode, resizeMode,
} = this.props; } = this.props;
let uri = source.uri; let uri = source.uri;
if (uri && uri.match(/^\//)) { if (uri && uri.match(/^\//)) {
uri = 'file://' + uri; uri = `file://${uri}`;
} }
const isNetwork = !!(uri && uri.match(/^https?:/)); const isNetwork = !!(uri && uri.match(/^https?:/));
const isAsset = !!(uri && uri.match(/^(assets-library|file):/)); const isAsset = !!(uri && uri.match(/^(assets-library|file|content):/));
let nativeResizeMode; let nativeResizeMode;
if (resizeMode === VideoResizeMode.stretch) { if (resizeMode === VideoResizeMode.stretch) {
@ -90,10 +143,10 @@ class Video extends Component {
const nativeProps = Object.assign({}, this.props); const nativeProps = Object.assign({}, this.props);
Object.assign(nativeProps, { Object.assign(nativeProps, {
style: [styles.base, style], style: [styles.base, nativeProps.style],
resizeMode: nativeResizeMode, resizeMode: nativeResizeMode,
src: { src: {
uri: uri, uri,
isNetwork, isNetwork,
isAsset, isAsset,
type: source.type || 'mp4', type: source.type || 'mp4',
@ -104,12 +157,17 @@ class Video extends Component {
onVideoProgress: this._onProgress, onVideoProgress: this._onProgress,
onVideoSeek: this._onSeek, onVideoSeek: this._onSeek,
onVideoEnd: this._onEnd, onVideoEnd: this._onEnd,
onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent,
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
}); });
return ( return (
<RCTVideo <RCTVideo
ref={ component => this._root = component } ref={this._assignRoot}
{...nativeProps} /> {...nativeProps}
/>
); );
} }
} }
@ -118,6 +176,7 @@ Video.propTypes = {
/* Native only */ /* Native only */
src: PropTypes.object, src: PropTypes.object,
seek: PropTypes.number, seek: PropTypes.number,
fullscreen: PropTypes.bool,
/* Wrapper component */ /* Wrapper component */
source: PropTypes.object, source: PropTypes.object,
@ -128,12 +187,18 @@ Video.propTypes = {
volume: PropTypes.number, volume: PropTypes.number,
rate: PropTypes.number, rate: PropTypes.number,
playInBackground: PropTypes.bool, playInBackground: PropTypes.bool,
controls: PropTypes.bool,
currentTime: PropTypes.number,
onLoadStart: PropTypes.func, onLoadStart: PropTypes.func,
onLoad: PropTypes.func, onLoad: PropTypes.func,
onError: PropTypes.func, onError: PropTypes.func,
onProgress: PropTypes.func, onProgress: PropTypes.func,
onSeek: PropTypes.func, onSeek: PropTypes.func,
onEnd: PropTypes.func, onEnd: PropTypes.func,
onFullscreenPlayerWillPresent: PropTypes.func,
onFullscreenPlayerDidPresent: PropTypes.func,
onFullscreenPlayerWillDismiss: PropTypes.func,
onFullscreenPlayerDidDismiss: PropTypes.func,
/* Required by react-native */ /* Required by react-native */
scaleX: React.PropTypes.number, scaleX: React.PropTypes.number,
@ -148,7 +213,6 @@ const RCTVideo = requireNativeComponent('RCTVideo', Video, {
nativeOnly: { nativeOnly: {
src: true, src: true,
seek: true, seek: true,
fullscreen: true,
}, },
}); });
module.exports = Video;

View File

@ -1,11 +1,7 @@
'use strict'; import keyMirror from 'keymirror';
var keyMirror = require('keymirror'); export default keyMirror({
var VideoResizeMode = keyMirror({
contain: null, contain: null,
cover: null, cover: null,
stretch: null, stretch: null,
}); });
module.exports = VideoResizeMode;

View File

@ -16,6 +16,6 @@ android {
} }
dependencies { dependencies {
compile 'com.facebook.react:react-native:0.13.+' compile 'com.facebook.react:react-native:0.19.+'
compile 'com.yqritc:android-scalablevideoview:1.0.1' compile 'com.yqritc:android-scalablevideoview:1.0.1'
} }

View File

@ -58,6 +58,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
private String mSrcUriString = null; private String mSrcUriString = null;
private String mSrcType = "mp4"; private String mSrcType = "mp4";
private boolean mSrcIsNetwork = false; private boolean mSrcIsNetwork = false;
private boolean mSrcIsAsset = false;
private ScalableType mResizeMode = ScalableType.LEFT_TOP; private ScalableType mResizeMode = ScalableType.LEFT_TOP;
private boolean mRepeat = false; private boolean mRepeat = false;
private boolean mPaused = false; private boolean mPaused = false;
@ -107,10 +108,11 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
} }
} }
public void setSrc(final String uriString, final String type, final boolean isNetwork) { public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset) {
mSrcUriString = uriString; mSrcUriString = uriString;
mSrcType = type; mSrcType = type;
mSrcIsNetwork = isNetwork; mSrcIsNetwork = isNetwork;
mSrcIsAsset = isAsset;
mMediaPlayerValid = false; mMediaPlayerValid = false;
mVideoDuration = 0; mVideoDuration = 0;
@ -120,7 +122,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
mMediaPlayer.reset(); mMediaPlayer.reset();
try { try {
if (isNetwork) { if (isNetwork || isAsset) {
setDataSource(uriString); setDataSource(uriString);
} else { } else {
setRawData(mThemedReactContext.getResources().getIdentifier( setRawData(mThemedReactContext.getResources().getIdentifier(
@ -281,6 +283,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
@Override @Override
protected void onAttachedToWindow() { protected void onAttachedToWindow() {
super.onAttachedToWindow(); super.onAttachedToWindow();
setSrc(mSrcUriString, mSrcType, mSrcIsNetwork); setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset);
} }
} }

View File

@ -5,7 +5,7 @@ import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReadableMap; import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableMap;
import com.facebook.react.common.MapBuilder; import com.facebook.react.common.MapBuilder;
import com.facebook.react.uimanager.ReactProp; import com.facebook.react.uimanager.annotations.ReactProp;
import com.facebook.react.uimanager.SimpleViewManager; import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext; import com.facebook.react.uimanager.ThemedReactContext;
import com.facebook.react.uimanager.events.RCTEventEmitter; import com.facebook.react.uimanager.events.RCTEventEmitter;
@ -22,6 +22,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
public static final String PROP_SRC_URI = "uri"; public static final String PROP_SRC_URI = "uri";
public static final String PROP_SRC_TYPE = "type"; public static final String PROP_SRC_TYPE = "type";
public static final String PROP_SRC_IS_NETWORK = "isNetwork"; public static final String PROP_SRC_IS_NETWORK = "isNetwork";
public static final String PROP_SRC_IS_ASSET = "isAsset";
public static final String PROP_RESIZE_MODE = "resizeMode"; public static final String PROP_RESIZE_MODE = "resizeMode";
public static final String PROP_REPEAT = "repeat"; public static final String PROP_REPEAT = "repeat";
public static final String PROP_PAUSED = "paused"; public static final String PROP_PAUSED = "paused";
@ -66,7 +67,8 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
videoView.setSrc( videoView.setSrc(
src.getString(PROP_SRC_URI), src.getString(PROP_SRC_URI),
src.getString(PROP_SRC_TYPE), src.getString(PROP_SRC_TYPE),
src.getBoolean(PROP_SRC_IS_NETWORK) src.getBoolean(PROP_SRC_IS_NETWORK),
src.getBoolean(PROP_SRC_IS_ASSET)
); );
} }

View File

@ -1,8 +1,9 @@
{ {
"name": "react-native-video", "name": "react-native-video",
"version": "0.6.1", "version": "0.8.0-beta",
"description": "A <Video /> element for react-native", "description": "A <Video /> element for react-native",
"main": "Video.js", "main": "Video.js",
"license": "MIT",
"author": "Brent Vatne <brentvatne@gmail.com> (https://github.com/brentvatne)", "author": "Brent Vatne <brentvatne@gmail.com> (https://github.com/brentvatne)",
"files": [ "files": [
"android/build.gradle", "android/build.gradle",
@ -18,9 +19,14 @@
"RCTVideoManager.h", "RCTVideoManager.h",
"RCTVideoManager.m", "RCTVideoManager.m",
"README.md", "README.md",
"UIView+FindUIViewController.h",
"UIView+FindUIViewController.m",
"RCTVideoPlayerViewController.h",
"RCTVideoPlayerViewController.m",
"RCTVideoPlayerViewControllerDelegate.h",
"Video.js", "Video.js",
"VideoResizeMode.js", "VideoResizeMode.js",
"VideoStylePropTypes.js" "react-native-video.podspec"
], ],
"contributors": [ "contributors": [
{ {
@ -37,9 +43,16 @@
"url": "git@github.com:brentvatne/react-native-video.git" "url": "git@github.com:brentvatne/react-native-video.git"
}, },
"devDependencies": { "devDependencies": {
"jest-cli": "0.2.1" "jest-cli": "0.2.1",
"eslint": "1.10.3",
"babel-eslint": "5.0.0-beta8",
"eslint-plugin-react": "3.16.1",
"eslint-config-airbnb": "4.0.0"
}, },
"dependencies": { "dependencies": {
"keymirror": "^0.1.1" "keymirror": "0.1.1"
},
"scripts": {
"test": "node_modules/.bin/eslint *.js"
} }
} }

View File

@ -0,0 +1,21 @@
require "json"
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
Pod::Spec.new do |s|
s.name = "react-native-video"
s.version = package["version"]
s.summary = "A <Video /> element for react-native"
s.author = "Brent Vatne <brentvatne@gmail.com> (https://github.com/brentvatne)"
s.homepage = "https://github.com/brentvatne/react-native-video"
s.license = "MIT"
s.platform = :ios, "7.0"
s.source = { :git => "https://github.com/brentvatne/react-native-video.git", :tag => "#{s.version}" }
s.source_files = "*.{h,m}"
s.dependency "React"
end