diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..949fb3c7 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": "airbnb", + "parser": "babel-eslint" +} diff --git a/Examples/VideoPlayer/.flowconfig b/Examples/VideoPlayer/.flowconfig index 8eadd339..66b57e09 100644 --- a/Examples/VideoPlayer/.flowconfig +++ b/Examples/VideoPlayer/.flowconfig @@ -14,17 +14,21 @@ # Ignore react and fbjs where there are overlaps, but don't ignore # anything that react-native relies on -.*/node_modules/fbjs-haste/.*/__tests__/.* -.*/node_modules/fbjs-haste/__forks__/Map.js -.*/node_modules/fbjs-haste/__forks__/Promise.js -.*/node_modules/fbjs-haste/__forks__/fetch.js -.*/node_modules/fbjs-haste/core/ExecutionEnvironment.js -.*/node_modules/fbjs-haste/core/isEmpty.js -.*/node_modules/fbjs-haste/crypto/crc32.js -.*/node_modules/fbjs-haste/stubs/ErrorUtils.js -.*/node_modules/react-haste/React.js -.*/node_modules/react-haste/renderers/dom/ReactDOM.js -.*/node_modules/react-haste/renderers/shared/event/eventPlugins/ResponderEventPlugin.js +.*/node_modules/fbjs/lib/Map.js +.*/node_modules/fbjs/lib/fetch.js +.*/node_modules/fbjs/lib/ExecutionEnvironment.js +.*/node_modules/fbjs/lib/ErrorUtils.js + +# Flow has a built-in definition for the 'react' module which we prefer to use +# over the currently-untyped source +.*/node_modules/react/react.js +.*/node_modules/react/lib/React.js +.*/node_modules/react/lib/ReactDOM.js + +.*/__mocks__/.* +.*/__tests__/.* + +.*/commoner/test/source/widget/share.js # Ignore commoner tests .*/node_modules/commoner/test/.* @@ -38,26 +42,48 @@ # Ignore 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] [libs] node_modules/react-native/Libraries/react-native/react-native-interface.js +node_modules/react-native/flow +flow/ [options] module.system=haste +esproposal.class_static_fields=enable +esproposal.class_instance_fields=enable + munge_underscores=true 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=$FlowFixMe 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\\)*\\$FlowIssue\\((\\(>=0\\.\\(1[0-8]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)? #[0-9]+ +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\\.\\(2[0-2]\\|1[0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+ suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy [version] -0.18.1 +0.22.0 diff --git a/Examples/VideoPlayer/.gitignore b/Examples/VideoPlayer/.gitignore index 07e4fe72..54a65557 100644 --- a/Examples/VideoPlayer/.gitignore +++ b/Examples/VideoPlayer/.gitignore @@ -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 diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.pbxproj b/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.pbxproj index 2a8de0fc..f40c2d81 100644 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.pbxproj +++ b/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.pbxproj @@ -302,7 +302,7 @@ 83CBB9F71A601CBA00E9B192 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = Facebook; }; buildConfigurationList = 83CBB9FA1A601CBA00E9B192 /* Build configuration list for PBXProject "VideoPlayer" */; @@ -487,8 +487,10 @@ "$(SRCROOT)/node_modules/react-native/React/**", ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = VideoPlayer; }; name = Debug; @@ -503,8 +505,10 @@ "$(SRCROOT)/node_modules/react-native/React/**", ); INFOPLIST_FILE = "$(SRCROOT)/iOS/Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; OTHER_LDFLAGS = "-ObjC"; + PRODUCT_BUNDLE_IDENTIFIER = "org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = VideoPlayer; }; name = Release; @@ -529,6 +533,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 4ac4c91f..00000000 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcshareddata/VideoPlayer.xccheckout b/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcshareddata/VideoPlayer.xccheckout deleted file mode 100644 index 6ce4fd2f..00000000 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcshareddata/VideoPlayer.xccheckout +++ /dev/null @@ -1,41 +0,0 @@ - - - - - IDESourceControlProjectFavoriteDictionaryKey - - IDESourceControlProjectIdentifier - 9B1B824B-5918-47F5-B27A-FA559B781ACC - IDESourceControlProjectName - VideoPlayer - IDESourceControlProjectOriginsDictionary - - D05F265D0E65FFE673B2E9F5A4680A7F46E27F31 - github.com:johanneslumpe/react-native-video.git - - IDESourceControlProjectPath - Examples/VideoPlayer/VideoPlayer.xcodeproj - IDESourceControlProjectRelativeInstallPathDictionary - - D05F265D0E65FFE673B2E9F5A4680A7F46E27F31 - ../../../.. - - IDESourceControlProjectURL - github.com:johanneslumpe/react-native-video.git - IDESourceControlProjectVersion - 111 - IDESourceControlProjectWCCIdentifier - D05F265D0E65FFE673B2E9F5A4680A7F46E27F31 - IDESourceControlProjectWCConfigurations - - - IDESourceControlRepositoryExtensionIdentifierKey - public.vcs.git - IDESourceControlWCCIdentifierKey - D05F265D0E65FFE673B2E9F5A4680A7F46E27F31 - IDESourceControlWCCName - react-native-video - - - - diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcuserdata/brentvatne.xcuserdatad/UserInterfaceState.xcuserstate b/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcuserdata/brentvatne.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index 01791fee..00000000 Binary files a/Examples/VideoPlayer/VideoPlayer.xcodeproj/project.xcworkspace/xcuserdata/brentvatne.xcuserdatad/UserInterfaceState.xcuserstate and /dev/null differ diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme b/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme index b089e027..a328632b 100644 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme +++ b/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> @@ -38,15 +38,18 @@ ReferencedContainer = "container:VideoPlayer.xcodeproj"> + + @@ -62,10 +65,10 @@ diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist deleted file mode 100644 index b1a4c519..00000000 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - diff --git a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcschemes/xcschememanagement.plist b/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index bc98ef59..00000000 --- a/Examples/VideoPlayer/VideoPlayer.xcodeproj/xcuserdata/brentvatne.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - SchemeUserState - - VideoPlayer.xcscheme_^#shared#^_ - - orderHint - 0 - - - SuppressBuildableAutocreation - - 13B07F861A680F5B00A75B9A - - primary - - - - - diff --git a/Examples/VideoPlayer/android/app/build.gradle b/Examples/VideoPlayer/android/app/build.gradle index 1c09ff66..2afbba5c 100644 --- a/Examples/VideoPlayer/android/app/build.gradle +++ b/Examples/VideoPlayer/android/app/build.gradle @@ -1,5 +1,7 @@ apply plugin: "com.android.application" +import com.android.build.OutputFile + /** * The react.gradle file registers two tasks: bundleDebugJsAndAssets and bundleReleaseJsAndAssets. * 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" +/** + * 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 { compileSdkVersion 23 buildToolsVersion "23.0.1" @@ -63,17 +81,38 @@ android { abiFilters "armeabi-v7a", "x86" } } + splits { + abi { + enable enableSeparateBuildPerCPUArchitecture + universalApk true + reset() + include "armeabi-v7a", "x86" + } + } buildTypes { release { - minifyEnabled false // Set this to true to enable Proguard + minifyEnabled enableProguardInReleaseBuilds 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 { + compile project(':react-native-video') compile fileTree(dir: "libs", include: ["*.jar"]) compile "com.android.support:appcompat-v7:23.0.1" - compile "com.facebook.react:react-native:0.16.+" - compile project(':RCTVideo') + compile "com.facebook.react:react-native:0.19.+" } diff --git a/Examples/VideoPlayer/android/app/proguard-rules.pro b/Examples/VideoPlayer/android/app/proguard-rules.pro index ffa8c9f6..35840261 100644 --- a/Examples/VideoPlayer/android/app/proguard-rules.pro +++ b/Examples/VideoPlayer/android/app/proguard-rules.pro @@ -40,10 +40,13 @@ -keep class * extends com.facebook.react.bridge.JavaScriptModule { *; } -keep class * extends com.facebook.react.bridge.NativeModule { *; } +-keepclassmembers,includedescriptorclasses class * { native ; } -keepclassmembers class * { @com.facebook.react.uimanager.UIProp ; } -keepclassmembers class * { @com.facebook.react.uimanager.ReactProp ; } -keepclassmembers class * { @com.facebook.react.uimanager.ReactPropGroup ; } +-dontwarn com.facebook.react.** + # okhttp -keepattributes Signature @@ -58,3 +61,7 @@ -dontwarn java.nio.file.* -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement -dontwarn okio.** + +# stetho + +-dontwarn com.facebook.stetho.** diff --git a/Examples/VideoPlayer/android/app/react.gradle b/Examples/VideoPlayer/android/app/react.gradle index 1e08b00f..f2152d1f 100644 --- a/Examples/VideoPlayer/android/app/react.gradle +++ b/Examples/VideoPlayer/android/app/react.gradle @@ -74,14 +74,33 @@ task bundleReleaseJsAndAssets(type: Exec) { enabled config.bundleInRelease ?: true } +void runBefore(String dependentTaskName, Task task) { + Task dependentTask = tasks.findByPath(dependentTaskName); + if (dependentTask != null) { + dependentTask.dependsOn task + } +} + gradle.projectsEvaluated { + // hook bundleDebugJsAndAssets into the android build process + bundleDebugJsAndAssets.dependsOn mergeDebugResources 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 + bundleReleaseJsAndAssets.dependsOn mergeReleaseResources bundleReleaseJsAndAssets.dependsOn mergeReleaseAssets - processReleaseResources.dependsOn bundleReleaseJsAndAssets + + runBefore('processArmeabi-v7aReleaseResources', bundleReleaseJsAndAssets) + runBefore('processX86ReleaseResources', bundleReleaseJsAndAssets) + runBefore('processUniversalReleaseResources', bundleReleaseJsAndAssets) + runBefore('processReleaseResources', bundleReleaseJsAndAssets) + } diff --git a/Examples/VideoPlayer/android/app/src/main/java/com/videoplayer/MainActivity.java b/Examples/VideoPlayer/android/app/src/main/java/com/videoplayer/MainActivity.java index bb84c0e5..ba386ade 100644 --- a/Examples/VideoPlayer/android/app/src/main/java/com/videoplayer/MainActivity.java +++ b/Examples/VideoPlayer/android/app/src/main/java/com/videoplayer/MainActivity.java @@ -1,80 +1,41 @@ package com.videoplayer; -import android.app.Activity; -import android.os.Bundle; -import android.view.KeyEvent; - +import com.facebook.react.ReactActivity; import com.brentvatne.react.ReactVideoPackage; -import com.facebook.react.LifecycleState; -import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactRootView; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; +import com.facebook.react.ReactPackage; 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; - private ReactRootView mReactRootView; +public class MainActivity extends ReactActivity { + /** + * Returns the name of the main component registered from JavaScript. + * This is used to schedule rendering of the component. + */ @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - 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); + protected String getMainComponentName() { + return "VideoPlayer"; } + /** + * Returns whether dev mode should be enabled. + * This enables e.g. the dev menu. + */ @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { - mReactInstanceManager.showDevOptionsDialog(); - return true; - } - return super.onKeyUp(keyCode, event); + protected boolean getUseDeveloperSupport() { + return BuildConfig.DEBUG; } + /** + * 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 - public void onBackPressed() { - if (mReactInstanceManager != null) { - mReactInstanceManager.onBackPressed(); - } else { - 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); - } + protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new ReactVideoPackage()); } } diff --git a/Examples/VideoPlayer/android/settings.gradle b/Examples/VideoPlayer/android/settings.gradle index 4c6aa278..941ffdb9 100644 --- a/Examples/VideoPlayer/android/settings.gradle +++ b/Examples/VideoPlayer/android/settings.gradle @@ -1,5 +1,7 @@ rootProject.name = 'VideoPlayer' include ':app' +include ':react-native-video' +project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') include ':RCTVideo', ':app' project(':RCTVideo').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android') diff --git a/Examples/VideoPlayer/iOS/Info.plist b/Examples/VideoPlayer/iOS/Info.plist index e4b8e7c8..45532a3a 100644 --- a/Examples/VideoPlayer/iOS/Info.plist +++ b/Examples/VideoPlayer/iOS/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -15,11 +15,11 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 1.0.0 CFBundleSignature ???? CFBundleVersion - 1 + 2 LSApplicationCategoryType LSRequiresIPhoneOS diff --git a/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/project.pbxproj b/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/project.pbxproj new file mode 100644 index 00000000..86221d3b --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/project.pbxproj @@ -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 = ""; }; + 00C302A71ABCB8CE00DB3ED1 /* RCTActionSheet.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTActionSheet.xcodeproj; path = ../node_modules/react-native/Libraries/ActionSheetIOS/RCTActionSheet.xcodeproj; sourceTree = ""; }; + 00C302B51ABCB90400DB3ED1 /* RCTGeolocation.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTGeolocation.xcodeproj; path = ../node_modules/react-native/Libraries/Geolocation/RCTGeolocation.xcodeproj; sourceTree = ""; }; + 00C302BB1ABCB91800DB3ED1 /* RCTImage.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTImage.xcodeproj; path = ../node_modules/react-native/Libraries/Image/RCTImage.xcodeproj; sourceTree = ""; }; + 00C302D31ABCB9D200DB3ED1 /* RCTNetwork.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTNetwork.xcodeproj; path = ../node_modules/react-native/Libraries/Network/RCTNetwork.xcodeproj; sourceTree = ""; }; + 00C302DF1ABCB9EE00DB3ED1 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../node_modules/react-native/Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = ""; }; + 00E356EE1AD99517003FC87E /* VideoPlayerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = VideoPlayerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 00E356F11AD99517003FC87E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 00E356F21AD99517003FC87E /* VideoPlayerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = VideoPlayerTests.m; sourceTree = ""; }; + 139105B61AF99BAD00B5F7CC /* RCTSettings.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTSettings.xcodeproj; path = ../node_modules/react-native/Libraries/Settings/RCTSettings.xcodeproj; sourceTree = ""; }; + 139FDEE61B06529A00C62182 /* RCTWebSocket.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTWebSocket.xcodeproj; path = ../node_modules/react-native/Libraries/WebSocket/RCTWebSocket.xcodeproj; sourceTree = ""; }; + 13B07F961A680F5B00A75B9A /* VideoPlayer.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VideoPlayer.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 13B07FAF1A68108700A75B9A /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = VideoPlayer/AppDelegate.h; sourceTree = ""; }; + 13B07FB01A68108700A75B9A /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = VideoPlayer/AppDelegate.m; sourceTree = ""; }; + 13B07FB21A68108700A75B9A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 13B07FB51A68108700A75B9A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = VideoPlayer/Images.xcassets; sourceTree = ""; }; + 13B07FB61A68108700A75B9A /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = VideoPlayer/Info.plist; sourceTree = ""; }; + 13B07FB71A68108700A75B9A /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = VideoPlayer/main.m; sourceTree = ""; }; + 146833FF1AC3E56700842450 /* React.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = React.xcodeproj; path = ../node_modules/react-native/React/React.xcodeproj; sourceTree = ""; }; + 78C398B01ACF4ADC00677621 /* RCTLinking.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTLinking.xcodeproj; path = ../node_modules/react-native/Libraries/LinkingIOS/RCTLinking.xcodeproj; sourceTree = ""; }; + 832341B01AAA6A8300B99B32 /* RCTText.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTText.xcodeproj; path = ../node_modules/react-native/Libraries/Text/RCTText.xcodeproj; sourceTree = ""; }; + 1AAB246A2EAD48DC803233C0 /* RCTVideo.xcodeproj */ = {isa = PBXFileReference; name = "RCTVideo.xcodeproj"; path = "../node_modules/react-native-video/RCTVideo.xcodeproj"; sourceTree = ""; fileEncoding = undefined; lastKnownFileType = wrapper.pb-project; explicitFileType = undefined; includeInIndex = 0; }; + E6D74A42E295462FBFFFB2F5 /* libRCTVideo.a */ = {isa = PBXFileReference; name = "libRCTVideo.a"; path = "libRCTVideo.a"; sourceTree = ""; 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 = ""; + }; + 00C302B61ABCB90400DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302BA1ABCB90400DB3ED1 /* libRCTGeolocation.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302BC1ABCB91800DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302C01ABCB91800DB3ED1 /* libRCTImage.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302D41ABCB9D200DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302DC1ABCB9D200DB3ED1 /* libRCTNetwork.a */, + ); + name = Products; + sourceTree = ""; + }; + 00C302E01ABCB9EE00DB3ED1 /* Products */ = { + isa = PBXGroup; + children = ( + 00C302E41ABCB9EE00DB3ED1 /* libRCTVibration.a */, + ); + name = Products; + sourceTree = ""; + }; + 00E356EF1AD99517003FC87E /* VideoPlayerTests */ = { + isa = PBXGroup; + children = ( + 00E356F21AD99517003FC87E /* VideoPlayerTests.m */, + 00E356F01AD99517003FC87E /* Supporting Files */, + ); + path = VideoPlayerTests; + sourceTree = ""; + }; + 00E356F01AD99517003FC87E /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 00E356F11AD99517003FC87E /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 139105B71AF99BAD00B5F7CC /* Products */ = { + isa = PBXGroup; + children = ( + 139105C11AF99BAD00B5F7CC /* libRCTSettings.a */, + ); + name = Products; + sourceTree = ""; + }; + 139FDEE71B06529A00C62182 /* Products */ = { + isa = PBXGroup; + children = ( + 139FDEF41B06529B00C62182 /* libRCTWebSocket.a */, + ); + name = Products; + sourceTree = ""; + }; + 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 = ""; + }; + 146834001AC3E56700842450 /* Products */ = { + isa = PBXGroup; + children = ( + 146834041AC3E56700842450 /* libReact.a */, + ); + name = Products; + sourceTree = ""; + }; + 78C398B11ACF4ADC00677621 /* Products */ = { + isa = PBXGroup; + children = ( + 78C398B91ACF4ADC00677621 /* libRCTLinking.a */, + ); + name = Products; + sourceTree = ""; + }; + 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 = ""; + }; + 832341B11AAA6A8300B99B32 /* Products */ = { + isa = PBXGroup; + children = ( + 832341B51AAA6A8300B99B32 /* libRCTText.a */, + ); + name = Products; + sourceTree = ""; + }; + 83CBB9F61A601CBA00E9B192 = { + isa = PBXGroup; + children = ( + 13B07FAE1A68108700A75B9A /* VideoPlayer */, + 832341AE1AAA6A7D00B99B32 /* Libraries */, + 00E356EF1AD99517003FC87E /* VideoPlayerTests */, + 83CBBA001A601CBA00E9B192 /* Products */, + ); + indentWidth = 2; + sourceTree = ""; + tabWidth = 2; + }; + 83CBBA001A601CBA00E9B192 /* Products */ = { + isa = PBXGroup; + children = ( + 13B07F961A680F5B00A75B9A /* VideoPlayer.app */, + 00E356EE1AD99517003FC87E /* VideoPlayerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; +/* 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 = ""; + }; +/* 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 */; +} diff --git a/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme b/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme new file mode 100644 index 00000000..f277fa26 --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer.xcodeproj/xcshareddata/xcschemes/VideoPlayer.xcscheme @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.h b/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.h new file mode 100644 index 00000000..a9654d5e --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.h @@ -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 + +@interface AppDelegate : UIResponder + +@property (nonatomic, strong) UIWindow *window; + +@end diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.m b/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.m new file mode 100644 index 00000000..9c9c0490 --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/AppDelegate.m @@ -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 diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/Base.lproj/LaunchScreen.xib b/Examples/VideoPlayer/iOS/VideoPlayer/Base.lproj/LaunchScreen.xib new file mode 100644 index 00000000..9d8b0c89 --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/Base.lproj/LaunchScreen.xib @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/Images.xcassets/AppIcon.appiconset/Contents.json b/Examples/VideoPlayer/iOS/VideoPlayer/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000..118c98f7 --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/Images.xcassets/AppIcon.appiconset/Contents.json @@ -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" + } +} \ No newline at end of file diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/Info.plist b/Examples/VideoPlayer/iOS/VideoPlayer/Info.plist new file mode 100644 index 00000000..91963b26 --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/Info.plist @@ -0,0 +1,48 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + NSLocationWhenInUseUsageDescription + + NSAppTransportSecurity + + + NSAllowsArbitraryLoads + + + + diff --git a/Examples/VideoPlayer/iOS/VideoPlayer/main.m b/Examples/VideoPlayer/iOS/VideoPlayer/main.m new file mode 100644 index 00000000..3d767fcb --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayer/main.m @@ -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 + +#import "AppDelegate.h" + +int main(int argc, char * argv[]) { + @autoreleasepool { + return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); + } +} diff --git a/Examples/VideoPlayer/iOS/VideoPlayerTests/Info.plist b/Examples/VideoPlayer/iOS/VideoPlayerTests/Info.plist new file mode 100644 index 00000000..886825cc --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayerTests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Examples/VideoPlayer/iOS/VideoPlayerTests/VideoPlayerTests.m b/Examples/VideoPlayer/iOS/VideoPlayerTests/VideoPlayerTests.m new file mode 100644 index 00000000..e5ef148e --- /dev/null +++ b/Examples/VideoPlayer/iOS/VideoPlayerTests/VideoPlayerTests.m @@ -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 +#import + +#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 diff --git a/Examples/VideoPlayer/index.android.js b/Examples/VideoPlayer/index.android.js index c2533f28..21ee336a 100644 --- a/Examples/VideoPlayer/index.android.js +++ b/Examples/VideoPlayer/index.android.js @@ -1,35 +1,39 @@ 'use strict'; -var React = require('react-native'); -var { +import React, { AppRegistry, + Component, StyleSheet, Text, - View, TouchableOpacity, -} = React; + View, +} from 'react-native'; -var Video = require('react-native-video'); +import Video from 'react-native-video'; -var VideoPlayer = React.createClass({ - getInitialState() { - return { - rate: 1, - volume: 1, - muted: false, - resizeMode: 'contain', - duration: 0.0, - currentTime: 0.0, - } - }, +class VideoPlayer extends Component { + constructor(props) { + super(props); + this.onLoad = this.onLoad.bind(this); + this.onProgress = this.onProgress.bind(this); + } + + state = { + rate: 1, + volume: 1, + muted: false, + resizeMode: 'contain', + duration: 0.0, + currentTime: 0.0, + }; onLoad(data) { this.setState({duration: data.duration}); - }, + } onProgress(data) { this.setState({currentTime: data.currentTime}); - }, + } getCurrentTimePercentage() { if (this.state.currentTime > 0) { @@ -37,10 +41,10 @@ var VideoPlayer = React.createClass({ } else { return 0; } - }, + } renderRateControl(rate) { - var isSelected = (this.state.rate == rate); + const isSelected = (this.state.rate == rate); return ( { this.setState({rate: rate}) }}> @@ -49,10 +53,10 @@ var VideoPlayer = React.createClass({ ) - }, + } renderResizeModeControl(resizeMode) { - var isSelected = (this.state.resizeMode == resizeMode); + const isSelected = (this.state.resizeMode == resizeMode); return ( { this.setState({resizeMode: resizeMode}) }}> @@ -61,10 +65,10 @@ var VideoPlayer = React.createClass({ ) - }, + } renderVolumeControl(volume) { - var isSelected = (this.state.volume == volume); + const isSelected = (this.state.volume == volume); return ( { this.setState({volume: volume}) }}> @@ -73,11 +77,11 @@ var VideoPlayer = React.createClass({ ) - }, + } render() { - var flexCompleted = this.getCurrentTimePercentage() * 100; - var flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; + const flexCompleted = this.getCurrentTimePercentage() * 100; + const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; return ( @@ -128,10 +132,10 @@ var VideoPlayer = React.createClass({ ); } -}); +} -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', diff --git a/Examples/VideoPlayer/index.ios.js b/Examples/VideoPlayer/index.ios.js index c77f53d5..e6e5f838 100644 --- a/Examples/VideoPlayer/index.ios.js +++ b/Examples/VideoPlayer/index.ios.js @@ -1,36 +1,42 @@ 'use strict'; -var React = require('react-native'); -var { +import React, { + AlertIOS, AppRegistry, + Component, StyleSheet, Text, - View, TouchableOpacity, - AlertIOS, -} = React; + View, +} from 'react-native'; -var Video = require('react-native-video'); +import Video from 'react-native-video'; -var VideoPlayer = React.createClass({ - getInitialState() { - return { - rate: 1, - volume: 1, - muted: false, - resizeMode: 'contain', - duration: 0.0, - currentTime: 0.0, - } - }, +class VideoPlayer extends Component { + constructor(props) { + super(props); + this.onLoad = this.onLoad.bind(this); + this.onProgress = this.onProgress.bind(this); + } + state = { + rate: 1, + volume: 1, + muted: false, + resizeMode: 'contain', + duration: 0.0, + currentTime: 0.0, + controls: false, + paused: true, + skin: 'custom' + }; onLoad(data) { this.setState({duration: data.duration}); - }, + } onProgress(data) { this.setState({currentTime: data.currentTime}); - }, + } getCurrentTimePercentage() { if (this.state.currentTime > 0) { @@ -38,10 +44,25 @@ var VideoPlayer = React.createClass({ } else { return 0; } - }, + } + + renderSkinControl(skin) { + const isSelected = this.state.skin == skin; + const selectControls = skin == 'native' || skin == 'embed'; + return ( + { this.setState({ + controls: selectControls, + skin: skin + }) }}> + + {skin} + + + ); + } renderRateControl(rate) { - var isSelected = (this.state.rate == rate); + const isSelected = (this.state.rate == rate); return ( { this.setState({rate: rate}) }}> @@ -50,10 +71,10 @@ var VideoPlayer = React.createClass({ ) - }, + } renderResizeModeControl(resizeMode) { - var isSelected = (this.state.resizeMode == resizeMode); + const isSelected = (this.state.resizeMode == resizeMode); return ( { this.setState({resizeMode: resizeMode}) }}> @@ -62,10 +83,10 @@ var VideoPlayer = React.createClass({ ) - }, + } renderVolumeControl(volume) { - var isSelected = (this.state.volume == volume); + const isSelected = (this.state.volume == volume); return ( { this.setState({volume: volume}) }}> @@ -74,35 +95,42 @@ var VideoPlayer = React.createClass({ ) - }, + } - render() { - var flexCompleted = this.getCurrentTimePercentage() * 100; - var flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; + renderCustomSkin() { + const flexCompleted = this.getCurrentTimePercentage() * 100; + const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100; return ( {this.setState({paused: !this.state.paused})}}> - + + + {this.renderSkinControl('custom')} + {this.renderSkinControl('native')} + {this.renderSkinControl('embed')} + + - {this.renderRateControl(0.25)} {this.renderRateControl(0.5)} {this.renderRateControl(1.0)} - {this.renderRateControl(1.5)} {this.renderRateControl(2.0)} @@ -129,10 +157,66 @@ var VideoPlayer = React.createClass({ ); } -}); + renderNativeSkin() { + const videoStyle = this.state.skin == 'embed' ? styles.nativeVideoControls : styles.fullScreen; + return ( + + + + + + + {this.renderSkinControl('custom')} + {this.renderSkinControl('native')} + {this.renderSkinControl('embed')} + + + + + {this.renderRateControl(0.5)} + {this.renderRateControl(1.0)} + {this.renderRateControl(2.0)} + -var styles = StyleSheet.create({ + + {this.renderVolumeControl(0.5)} + {this.renderVolumeControl(1)} + {this.renderVolumeControl(1.5)} + + + + {this.renderResizeModeControl('cover')} + {this.renderResizeModeControl('contain')} + {this.renderResizeModeControl('stretch')} + + + + + + ); + } + + render() { + return this.state.controls ? this.renderNativeSkin() : this.renderCustomSkin(); + } +} + +const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', @@ -150,9 +234,9 @@ var styles = StyleSheet.create({ backgroundColor: "transparent", borderRadius: 5, position: 'absolute', - bottom: 20, - left: 20, - right: 20, + bottom: 44, + left: 4, + right: 4, }, progress: { flex: 1, @@ -171,10 +255,14 @@ var styles = StyleSheet.create({ generalControls: { flex: 1, flexDirection: 'row', - borderRadius: 4, overflow: 'hidden', paddingBottom: 10, }, + skinControl: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + }, rateControl: { flex: 1, flexDirection: 'row', @@ -189,7 +277,7 @@ var styles = StyleSheet.create({ flex: 1, flexDirection: 'row', alignItems: 'center', - justifyContent: 'center', + justifyContent: 'center' }, controlOption: { alignSelf: 'center', @@ -199,6 +287,10 @@ var styles = StyleSheet.create({ paddingRight: 2, lineHeight: 12, }, + nativeVideoControls: { + top: 184, + height: 300 + } }); AppRegistry.registerComponent('VideoPlayer', () => VideoPlayer); diff --git a/Examples/VideoPlayer/node_modules/react-native-video/RCTVideo.xcodeproj/project.pbxproj b/Examples/VideoPlayer/node_modules/react-native-video/RCTVideo.xcodeproj/project.pbxproj deleted file mode 100644 index e6ddaaf1..00000000 --- a/Examples/VideoPlayer/node_modules/react-native-video/RCTVideo.xcodeproj/project.pbxproj +++ /dev/null @@ -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 = ""; }; - BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = ""; }; - BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = ""; }; - BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideoManager.m; sourceTree = ""; }; -/* 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 = ""; - }; - 58B511D21A9E6C8500147676 = { - isa = PBXGroup; - children = ( - BBD49E391AC8DEF000610F8E /* RCTVideo.h */, - BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */, - BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */, - BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */, - 134814211AA4EA7D00B7C361 /* Products */, - ); - sourceTree = ""; - }; -/* 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 */; -} diff --git a/Examples/VideoPlayer/package.json b/Examples/VideoPlayer/package.json index 2d097498..b343603e 100644 --- a/Examples/VideoPlayer/package.json +++ b/Examples/VideoPlayer/package.json @@ -1,12 +1,13 @@ { "name": "VideoPlayer", - "version": "0.0.1", + "version": "1.0.0", "private": true, "scripts": { "start": "node_modules/react-native/packager/packager.sh" }, "dependencies": { - "react-native": "^0.16.0", - "react-native-video": "brentvatne/react-native-video#feature/android-support" + "react": "^0.14.8", + "react-native": "0.23.0", + "react-native-video": "../../" } } diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..dc7f43c8 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/RCTVideo.h b/RCTVideo.h index 1fc82e43..6f8aeab2 100644 --- a/RCTVideo.h +++ b/RCTVideo.h @@ -1,9 +1,16 @@ #import "RCTView.h" +#import +#import "AVKit/AVKit.h" +#import "UIView+FindUIViewController.h" +#import "RCTVideoPlayerViewController.h" +#import "RCTVideoPlayerViewControllerDelegate.h" @class RCTEventDispatcher; -@interface RCTVideo : UIView +@interface RCTVideo : UIView - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER; +- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem; + @end diff --git a/RCTVideo.m b/RCTVideo.m index 11e74428..11ae0798 100644 --- a/RCTVideo.m +++ b/RCTVideo.m @@ -3,17 +3,19 @@ #import "RCTBridgeModule.h" #import "RCTEventDispatcher.h" #import "UIView+React.h" -#import static NSString *const statusKeyPath = @"status"; static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp"; +static NSString *const playbackBufferEmptyKeyPath = @"playbackBufferEmpty"; @implementation RCTVideo { AVPlayer *_player; AVPlayerItem *_playerItem; BOOL _playerItemObserversSet; + BOOL _playerBufferEmpty; AVPlayerLayer *_playerLayer; + AVPlayerViewController *_playerViewController; NSURL *_videoURL; /* Required to publish events */ @@ -24,9 +26,9 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" float _lastSeekTime; /* For sending videoProgress events */ - id _progressUpdateTimer; - int _progressUpdateInterval; - NSDate *_prevProgressUpdateTime; + Float64 _progressUpdateInterval; + BOOL _controls; + id _timeObserver; /* Keep track of any modifiers, need to be applied after each play */ float _volume; @@ -36,6 +38,8 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" BOOL _repeat; BOOL _playInBackground; NSString * _resizeMode; + BOOL _fullscreenPlayerPresented; + UIViewController * _presentingViewController; } - (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher @@ -49,7 +53,10 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" _pendingSeek = false; _pendingSeekTime = 0.0f; _lastSeekTime = 0.0f; - _playInBackground = false; + _progressUpdateInterval = 250; + _controls = NO; + _playerBufferEmpty = YES; + _playInBackground = false; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillResignActive:) @@ -65,6 +72,44 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" 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 { [[NSNotificationCenter defaultCenter] removeObserver:self]; @@ -74,15 +119,14 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" - (void)applicationWillResignActive:(NSNotification *)notification { - if (!_paused && !_playInBackground) { - [self stopProgressTimer]; + if (!_paused && !_playInBackground) { + [_player pause]; [_player setRate:0.0]; } } - (void)applicationWillEnterForeground:(NSNotification *)notification { - [self startProgressTimer]; [self applyModifiers]; } @@ -90,18 +134,29 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" - (void)sendProgressUpdate { - AVPlayerItem *video = [_player currentItem]; - if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) { - return; - } + AVPlayerItem *video = [_player currentItem]; + if (video == nil || video.status != AVPlayerItemStatusReadyToPlay) { + return; + } + + CMTime playerDuration = [self playerItemDuration]; + if (CMTIME_IS_INVALID(playerDuration)) { + return; + } - if (_prevProgressUpdateTime == nil || (([_prevProgressUpdateTime timeIntervalSinceNow] * -1000.0) >= _progressUpdateInterval)) { - [_eventDispatcher sendInputEventWithName:@"onVideoProgress" - body:@{@"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(video.currentTime)], - @"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]; } -- (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 { [_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]; _playerItemObserversSet = YES; } @@ -159,6 +199,7 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" { if (_playerItemObserversSet) { [_playerItem removeObserver:self forKeyPath:statusKeyPath]; + [_playerItem removeObserver:self forKeyPath:playbackBufferEmptyKeyPath]; [_playerItem removeObserver:self forKeyPath:playbackLikelyToKeepUpKeyPath]; _playerItemObserversSet = NO; } @@ -168,25 +209,27 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" - (void)setSrc:(NSDictionary *)source { + [self removePlayerTimeObserver]; [self removePlayerItemObservers]; _playerItem = [self playerItemForSource:source]; [self addPlayerItemObservers]; [_player pause]; [_playerLayer removeFromSuperlayer]; + _playerLayer = nil; + [_playerViewController.view removeFromSuperview]; + _playerViewController = nil; _player = [AVPlayer playerWithPlayerItem:_playerItem]; _player.actionAtItemEnd = AVPlayerActionAtItemEndNone; - _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player]; - _playerLayer.frame = self.bounds; - _playerLayer.needsDisplayOnBoundsChange = YES; - - [self applyModifiers]; - - [self.layer addSublayer:_playerLayer]; - self.layer.needsDisplayOnBoundsChange = YES; - + const Float64 progressUpdateIntervalMS = _progressUpdateInterval / 1000; + // @see endScrubbing in AVPlayerDemoPlaybackViewController.m of https://developer.apple.com/library/ios/samplecode/AVPlayerDemo/Introduction/Intro.html + __weak RCTVideo *weakSelf = self; + _timeObserver = [_player addPeriodicTimeObserverForInterval:CMTimeMakeWithSeconds(progressUpdateIntervalMS, NSEC_PER_SEC) + queue:NULL + usingBlock:^(CMTime time) { [weakSelf sendProgressUpdate]; } + ]; [_eventDispatcher sendInputEventWithName:@"onVideoLoadStart" body:@{@"src": @{ @"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 { - if (object == _playerItem) { + if (object == _playerItem) { if ([keyPath isEqualToString:statusKeyPath]) { // Handle player item status change. @@ -226,6 +269,13 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" if (isnan(duration)) { 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" body:@{@"duration": [NSNumber numberWithFloat:duration], @@ -236,9 +286,12 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" @"canPlaySlowReverse": [NSNumber numberWithBool:_playerItem.canPlaySlowReverse], @"canStepBackward": [NSNumber numberWithBool:_playerItem.canStepBackward], @"canStepForward": [NSNumber numberWithBool:_playerItem.canStepForward], + @"naturalSize": @{ + @"width": width, + @"height": height + }, @"target": self.reactTag}]; - [self startProgressTimer]; [self attachListeners]; [self applyModifiers]; } else if(_playerItem.status == AVPlayerItemStatusFailed) { @@ -248,14 +301,17 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" @"domain": _playerItem.error.domain}, @"target": self.reactTag}]; } + } else if ([keyPath isEqualToString:playbackBufferEmptyKeyPath]) { + _playerBufferEmpty = YES; } else if ([keyPath isEqualToString:playbackLikelyToKeepUpKeyPath]) { // 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]; } + _playerBufferEmpty = NO; } } 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 { + if( _controls ) + { + _playerViewController.videoGravity = mode; + } + else + { + _playerLayer.videoGravity = mode; + } _resizeMode = mode; - _playerLayer.videoGravity = mode; } - (void)setPlayInBackground:(BOOL)playInBackground @@ -295,16 +358,26 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" - (void)setPaused:(BOOL)paused { if (paused) { - [self stopProgressTimer]; + [_player pause]; [_player setRate:0.0]; } else { - [self startProgressTimer]; + [_player play]; [_player setRate:_rate]; } - + _paused = paused; } +- (float)getCurrentTime +{ + return _playerItem != NULL ? CMTimeGetSeconds(_playerItem.currentTime) : 0; +} + +- (void)setCurrentTime:(float)currentTime +{ + [self setSeek: currentTime]; +} + - (void)setSeek:(float)seekTime { int timeScale = 10000; @@ -317,7 +390,7 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" CMTime current = item.currentTime; // TODO figure out a good tolerance level CMTime tolerance = CMTimeMake(1000, timeScale); - + if (CMTimeCompare(current, cmSeekTime) != 0) { [_player seekToTime:cmSeekTime toleranceBefore:tolerance toleranceAfter:tolerance completionHandler:^(BOOL finished) { [_eventDispatcher sendInputEventWithName:@"onVideoSeek" @@ -367,48 +440,195 @@ static NSString *const playbackLikelyToKeepUpKeyPath = @"playbackLikelyToKeepUp" [self setResizeMode:_resizeMode]; [self setRepeat:_repeat]; [self setPaused:_paused]; + [self setControls:_controls]; } - (void)setRepeat:(BOOL)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 - (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; } - (void)removeReactSubview:(UIView *)subview { - RCTLogError(@"video cannot have any subviews"); + if( _controls ) + { + [subview removeFromSuperview]; + } + else + { + RCTLogError(@"video cannot have any subviews"); + } return; } - (void)layoutSubviews { [super layoutSubviews]; - [CATransaction begin]; - [CATransaction setAnimationDuration:0]; - _playerLayer.frame = self.bounds; - [CATransaction commit]; + if( _controls ) + { + _playerViewController.view.frame = self.bounds; + + // 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 - (void)removeFromSuperview { - [_progressUpdateTimer invalidate]; - _prevProgressUpdateTime = nil; - [_player pause]; _player = nil; [_playerLayer removeFromSuperlayer]; _playerLayer = nil; + + [_playerViewController.view removeFromSuperview]; + _playerViewController = nil; + [self removePlayerTimeObserver]; [self removePlayerItemObservers]; _eventDispatcher = nil; diff --git a/RCTVideo.xcodeproj/project.pbxproj b/RCTVideo.xcodeproj/project.pbxproj index e6ddaaf1..502dd2a2 100644 --- a/RCTVideo.xcodeproj/project.pbxproj +++ b/RCTVideo.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* 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 */; }; BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */; }; /* End PBXBuildFile section */ @@ -25,6 +27,11 @@ /* Begin PBXFileReference section */ 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 = ""; }; + 31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+FindUIViewController.m"; sourceTree = ""; }; + 31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewController.h; sourceTree = ""; }; + 31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideoPlayerViewController.m; sourceTree = ""; }; + 31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoPlayerViewControllerDelegate.h; sourceTree = ""; }; BBD49E391AC8DEF000610F8E /* RCTVideo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideo.h; sourceTree = ""; }; BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTVideo.m; sourceTree = ""; }; BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTVideoManager.h; sourceTree = ""; }; @@ -55,8 +62,13 @@ children = ( BBD49E391AC8DEF000610F8E /* RCTVideo.h */, BBD49E3A1AC8DEF000610F8E /* RCTVideo.m */, + 31CAFB301CAE6B5F009BCF6F /* RCTVideoPlayerViewControllerDelegate.h */, + 31CAFB2D1CADC77F009BCF6F /* RCTVideoPlayerViewController.h */, + 31CAFB2E1CADC77F009BCF6F /* RCTVideoPlayerViewController.m */, BBD49E3B1AC8DEF000610F8E /* RCTVideoManager.h */, BBD49E3C1AC8DEF000610F8E /* RCTVideoManager.m */, + 31CAFB1F1CADA8CD009BCF6F /* UIView+FindUIViewController.h */, + 31CAFB201CADA8CD009BCF6F /* UIView+FindUIViewController.m */, 134814211AA4EA7D00B7C361 /* Products */, ); sourceTree = ""; @@ -87,7 +99,7 @@ 58B511D31A9E6C8500147676 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0610; + LastUpgradeCheck = 0720; ORGANIZATIONNAME = Facebook; TargetAttributes = { 58B511DA1A9E6C8500147676 = { @@ -117,6 +129,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 31CAFB211CADA8CD009BCF6F /* UIView+FindUIViewController.m in Sources */, + 31CAFB2F1CADC77F009BCF6F /* RCTVideoPlayerViewController.m in Sources */, BBD49E3F1AC8DEF000610F8E /* RCTVideo.m in Sources */, BBD49E401AC8DEF000610F8E /* RCTVideoManager.m in Sources */, ); @@ -144,6 +158,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -205,7 +220,6 @@ 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/**", ); @@ -222,7 +236,6 @@ 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/**", ); diff --git a/RCTVideoManager.m b/RCTVideoManager.m index 02d3ea6d..fcc1451d 100644 --- a/RCTVideoManager.m +++ b/RCTVideoManager.m @@ -24,7 +24,11 @@ RCT_EXPORT_MODULE(); @"onVideoError", @"onVideoProgress", @"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(paused, BOOL); RCT_EXPORT_VIEW_PROPERTY(muted, BOOL); +RCT_EXPORT_VIEW_PROPERTY(controls, BOOL); RCT_EXPORT_VIEW_PROPERTY(volume, float); RCT_EXPORT_VIEW_PROPERTY(playInBackground, BOOL); RCT_EXPORT_VIEW_PROPERTY(rate, float); RCT_EXPORT_VIEW_PROPERTY(seek, float); +RCT_EXPORT_VIEW_PROPERTY(currentTime, float); +RCT_EXPORT_VIEW_PROPERTY(fullscreen, BOOL); - (NSDictionary *)constantsToExport { diff --git a/RCTVideoPlayerViewController.h b/RCTVideoPlayerViewController.h new file mode 100644 index 00000000..d427b63d --- /dev/null +++ b/RCTVideoPlayerViewController.h @@ -0,0 +1,15 @@ +// +// RCTVideoPlayerViewController.h +// RCTVideo +// +// Created by Stanisław Chmiela on 31.03.2016. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import +#import "RCTVideo.h" +#import "RCTVideoPlayerViewControllerDelegate.h" + +@interface RCTVideoPlayerViewController : AVPlayerViewController +@property (nonatomic, weak) id rctDelegate; +@end diff --git a/RCTVideoPlayerViewController.m b/RCTVideoPlayerViewController.m new file mode 100644 index 00000000..b1b768d7 --- /dev/null +++ b/RCTVideoPlayerViewController.m @@ -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 diff --git a/RCTVideoPlayerViewControllerDelegate.h b/RCTVideoPlayerViewControllerDelegate.h new file mode 100644 index 00000000..ec6500af --- /dev/null +++ b/RCTVideoPlayerViewControllerDelegate.h @@ -0,0 +1,15 @@ +// +// RCTVideoPlayerViewControllerDelegate.h +// RCTVideo +// +// Created by Stanisław Chmiela on 01.04.2016. +// Copyright © 2016 Facebook. All rights reserved. +// + +#import +#import "AVKit/AVKit.h" + +@protocol RCTVideoPlayerViewControllerDelegate +- (void)videoPlayerViewControllerWillDismiss:(AVPlayerViewController *)playerViewController; +- (void)videoPlayerViewControllerDidDismiss:(AVPlayerViewController *)playerViewController; +@end diff --git a/README.md b/README.md index 4996d34e..d1d4df1f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A