├── .gitignore ├── .npmignore ├── EZPlayerRNBase.gif ├── EZPlayerRNList.gif ├── LICENSE ├── README.md ├── index.js ├── ios ├── react-native-ezplayer.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── iqiyi.xcuserdatad │ │ └── xcschemes │ │ └── xcschememanagement.plist └── react-native-ezplayer │ ├── EZRNPlayerView.swift │ ├── EZRNPlayerViewBridge.h │ ├── EZRNPlayerViewBridge.m │ ├── EZRNPlayerViewManager.swift │ └── react-native-ezplayer-Bridging-Header.h ├── package.json └── src └── EZPlayer.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.ear 17 | *.zip 18 | *.tar.gz 19 | *.rar 20 | 21 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 22 | hs_err_pid* 23 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .idea 2 | Screenshots 3 | *.gif 4 | *.iml 5 | *.podspec 6 | EZPlayerExample_RN/ 7 | EZPlayerExample/ 8 | EZPlayer/ 9 | Examples/ 10 | 11 | 12 | # OSX 13 | # 14 | .DS_Store 15 | # Xcode 16 | # 17 | build/ 18 | *.pbxuser 19 | !default.pbxuser 20 | *.mode1v3 21 | !default.mode1v3 22 | *.mode2v3 23 | !default.mode2v3 24 | *.perspectivev3 25 | !default.perspectivev3 26 | xcuserdata 27 | *.xccheckout 28 | *.moved-aside 29 | DerivedData 30 | *.hmap 31 | *.ipa 32 | *.xcuserstate 33 | EZPlayer.xcodeproj 34 | 35 | 36 | -------------------------------------------------------------------------------- /EZPlayerRNBase.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyui/react-native-ezplayer/af00e4ac9530a5ec1e007566e29e2dc711011a29/EZPlayerRNBase.gif -------------------------------------------------------------------------------- /EZPlayerRNList.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/easyui/react-native-ezplayer/af00e4ac9530a5ec1e007566e29e2dc711011a29/EZPlayerRNList.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Yangjun 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-native-ezplayer 2 | ![License](https://img.shields.io/cocoapods/l/EZPlayer.svg?style=flat) [![NPM version][npm-image]][npm-url] 3 | 4 | EZPlayer component for react-native apps 5 | 6 | ## 预览 7 | 8 | ![EZPlayerRNBase](EZPlayerRNBase.gif) ![EZPlayerRNList](EZPlayerRNList.gif) 9 | 10 | 11 | ## 介绍 12 | 基于[EZPlayer](https://github.com/easyui/EZPlayer)封装的视频播放器,功能丰富,快速集成,可定制性强。 13 | 14 | ## 要求 15 | - iOS 9.0+ 16 | - Xcode 12.0+ 17 | - Swift 5.0+ 18 | - React Native 0.63.3+ 19 | 20 | ## 特性 21 | - 本地视频、网络视频播放(支持的格式请参考苹果AVPlayer文档) 22 | - [全屏模式/嵌入模式/浮动模式随意切换(支持根据设备自动旋转)](#DisplayMode) 23 | - [全屏模式支持横屏全屏和竖屏全屏](#DisplayMode) 24 | - [浮动模式支持系统PIP和window浮层](#FloatMode) 25 | - [定制手势:播放/暂停(全屏/嵌入模式双击,浮动模式单击),浮动和全屏切换(双击),音量/亮度调节(上下滑动),进度调节(左右滑动)](#GestureRecognizer) 26 | - [支持airPlay](#airPlay) 27 | - [支持UITableview自动管理嵌入和浮动模式切换](#tableview) 28 | - [视频比例填充(videoGravity)切换](#videoGravity) 29 | - [字幕/CC切换](#subtitle&cc&audio) 30 | - [音频切换](#subtitle&cc&audio) 31 | - [拖动进度显示预览图(m3u8不支持)](#preview) 32 | - [播放器控件皮肤自定义(自带一套浮动皮肤,嵌入和全屏用的一套皮肤)](#skin) 33 | - [支持广告功能](#ad) 34 | 35 | ## 使用 36 | 可以参考[EZPlayerExample_RN](https://github.com/easyui/EZPlayer/tree/master/EZPlayerExample_RN)项目, 37 | 38 | ### react-native-ezplayer 文件: 39 | 40 | EZRNPlayerView.swift : 对EZPlayer的封装,对接javascript 41 | 42 | EZRNPlayerViewManager.swift : EZPlayer组件管理器 43 | 44 | EZRNPlayerViewBridge.h & EZRNPlayerViewBridge.m : oc桥接 45 | 46 | EZPlayer.js : 对EZPlayer封装的js api 47 | 48 | ### 属性 49 | | key | description | value | 50 | | --- | --- | --- | 51 | | source | 视频数据源 | PropTypes.object | 52 | | autoPlay|设置数据源后自动播放| PropTypes.bool | 53 | | useDefaultUI|使用EZPlayer自带皮肤| PropTypes.bool | 54 | | videoGravity|视频画面比例| PropTypes.string(aspect,aspectFill,scaleFill) | 55 | | fullScreenMode|全屏模式是竖屏还是横屏| PropTypes.string(portrait,landscape) | 56 | | floatMode|浮动模式支持系统PIP和window浮层| PropTypes.string(none,auto,system,window) | 57 | | onPlayerHeartbeat|播放器声明周期心跳| PropTypes.func | 58 | | onPlayerPlaybackTimeDidChange|addPeriodicTimeObserver方法的触发| PropTypes.func | 59 | | onPlayerStatusDidChange|播放器状态改变| PropTypes.func | 60 | | onPlayerPlaybackDidFinish|视频结束| PropTypes.func | 61 | | onPlayerLoadingDidChange|loading状态改变| PropTypes.func | 62 | | onPlayerControlsHiddenDidChange|播放器控制条隐藏显示| PropTypes.func | 63 | | onPlayerDisplayModeDidChange|播放器显示模式改变了(全屏,嵌入屏,浮动)| PropTypes.object | 64 | | onPlayerDisplayModeChangedWillAppear |播放器显示模式动画开始| PropTypes.func | 65 | | onPlayerDisplayModeChangedDidAppear |播放器显示模式动画结束| PropTypes.func | 66 | | onPlayerTapGestureRecognizer |点击播放器手势通知| PropTypes.func | 67 | | onPlayerDidPersistContentKey |FairPlay DRM| PropTypes.func | 68 | | onPlayerPIPControllerWillStart |即将开启画中画| PropTypes.func | 69 | | onPlayerPIPControllerDidStart |已经开启画中画| PropTypes.func | 70 | | onPlayerPIPFailedToStart |开启画中画失败| PropTypes.func | 71 | | onPlayerPIPControllerWillEnd |即将关闭画中画| PropTypes.func | 72 | | onPlayerPIPControllerDidEnd |已经关闭画中画| PropTypes.func | 73 | | onPlayerPIPRestoreUserInterfaceForStop |关闭画中画且恢复播放界面| PropTypes.func | 74 | 75 | ### 方法 76 | | function | description | 77 | | --- | --- | 78 | | play() | 播放 | 79 | | pause() | 暂停 | 80 | | stop() | 结束 | 81 | | seek(time, callback) | 设置播放进度,单位秒 | 82 | | replaceToPlay(source) | 替换播放源 | 83 | | rate(rate) | 设置播放速率 | 84 | | autoPlay(autoPlay) | 设置自动播放,autoPlay是PropTypes.bool | 85 | | videoGravity(videoGravity) | 设置视频画面比例,videoGravity:aspect,aspectFill,scaleFill | 86 | | toEmbedded(animated = true, callback) | 进入嵌入屏模式 | 87 | | toFloat(animated = true, callback) | 进入悬浮屏模式 | 88 | | toFull(orientation = 'landscapeLeft', animated = true, callback) | 进入全屏模式,orientation: landscapeLeft , landscapeRight | 89 | | fullScreenMode(fullScreenMode)| 设置全屏的模式,fullScreenMode:portrait , landscape | 90 | | floatMode(floatMode)| 设置浮窗的模式,fullScreenMode:none , auto, system, window,默认值auto | 91 | 92 | ### demo文件: 93 | 94 | BasePlayerExample.js : EZPlayer的基础功能演示 95 | 96 | TablePlayerExample.js :EZPlayer 在列表中的演示 97 | 98 | TablePlayerCell.js : 列表的cell 99 | 100 | EZCustomPlayer.js : 对EZPlayer.js进行封装,使用自定义ui,自定义ui可参考 101 | 102 | Utils.js : 工具类 103 | 104 | #### 使用 105 | ```js 106 | //基本使用 107 | //BasePlayerExample.js 108 | this._ezPlayer = e} 110 | style={styles.player} 111 | source={this.state.source } 112 | 113 | autoPlay={true} 114 | videoGravity={'aspect'} 115 | fullScreenMode={'landscape'} 116 | /> 117 | ``` 118 | 119 | ```js 120 | //自定义ui 121 | //EZCustomPlayer.js 122 | 123 | 124 | this.player.ref = nativePlayer} 128 | style={this.props.style} 129 | onPlayerHeartbeat={this.events.onPlayerHeartbeat} 130 | onPlayerPlaybackTimeDidChange={this.events.onPlayerPlaybackTimeDidChange} 131 | onPlayerStatusDidChange={this.events.onPlayerStatusDidChange} 132 | onPlayerPlaybackDidFinish={this.events.onPlayerPlaybackDidFinish} 133 | onPlayerLoadingDidChange={this.events.onPlayerLoadingDidChange} 134 | onPlayerControlsHiddenDidChange={this.events.onPlayerControlsHiddenDidChange} 135 | onPlayerDisplayModeDidChange={this.events.onPlayerDisplayModeDidChange} 136 | onPlayerDisplayModeChangedWillAppear={this.events.onPlayerDisplayModeChangedWillAppear} 137 | onPlayerDisplayModeChangedDidAppear={this.events.onPlayerDisplayModeChangedDidAppear} 138 | onPlayerTapGestureRecognizer={this.events.onPlayerTapGestureRecognizer} 139 | onPlayerDidPersistContentKey={this.events.onPlayerDidPersistContentKey} 140 | /> 141 | {this.renderLoader()} 142 | {this.renderBottomControls()} 143 | 144 | 145 | ``` 146 | 147 | 148 | ## License 149 | EZPlayer遵守MIT协议,具体请参考MIT 150 | 151 | 152 | [react-native-wechat]: https://github.com/yorkie/react-native-wechat 153 | [npm-image]: https://img.shields.io/npm/v/react-native-ezplayer.svg?style=flat-square 154 | [npm-url]: https://npmjs.org/package/react-native-ezplayer 155 | [travis-image]: https://img.shields.io/travis/yorkie/react-native-ezplayer.svg?style=flat-square 156 | [travis-url]: https://travis-ci.org/yorkie/react-native-ezplayer 157 | [david-image]: http://img.shields.io/david/yorkie/react-native-ezplayer.svg?style=flat-square 158 | [david-url]: https://david-dm.org/yorkie/react-native-ezplayer 159 | [downloads-image]: http://img.shields.io/npm/dm/react-native-ezplayer.svg?style=flat-square 160 | [downloads-url]: https://npmjs.org/package/react-native-ezplayer 161 | [React Native]: https://github.com/facebook/react-native 162 | [react-native-cn]: https://github.com/reactnativecn 163 | [EZPlayer]: https://github.com/easyui/EZPlayer 164 | [Linking Libraries iOS Guidance]: https://developer.apple.com/library/ios/recipes/xcode_help-project_editor/Articles/AddingaLibrarytoaTarget.html 165 | 166 | 167 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./src/EZPlayer.js'); 2 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 48; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | A6C55B941FA4614D00876D6C /* EZRNPlayerViewManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C55B901FA4614C00876D6C /* EZRNPlayerViewManager.swift */; }; 11 | A6C55B951FA4614D00876D6C /* EZRNPlayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A6C55B911FA4614D00876D6C /* EZRNPlayerView.swift */; }; 12 | A6C55B961FA4614D00876D6C /* EZRNPlayerViewBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = A6C55B931FA4614D00876D6C /* EZRNPlayerViewBridge.m */; }; 13 | /* End PBXBuildFile section */ 14 | 15 | /* Begin PBXCopyFilesBuildPhase section */ 16 | A6C55B6A1FA43E8300876D6C /* CopyFiles */ = { 17 | isa = PBXCopyFilesBuildPhase; 18 | buildActionMask = 2147483647; 19 | dstPath = "include/$(PRODUCT_NAME)"; 20 | dstSubfolderSpec = 16; 21 | files = ( 22 | ); 23 | runOnlyForDeploymentPostprocessing = 0; 24 | }; 25 | /* End PBXCopyFilesBuildPhase section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | A6C55B6C1FA43E8300876D6C /* libreact-native-ezplayer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libreact-native-ezplayer.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 29 | A6C55B8F1FA4614C00876D6C /* react-native-ezplayer-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "react-native-ezplayer-Bridging-Header.h"; sourceTree = ""; }; 30 | A6C55B901FA4614C00876D6C /* EZRNPlayerViewManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EZRNPlayerViewManager.swift; sourceTree = ""; }; 31 | A6C55B911FA4614D00876D6C /* EZRNPlayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EZRNPlayerView.swift; sourceTree = ""; }; 32 | A6C55B921FA4614D00876D6C /* EZRNPlayerViewBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EZRNPlayerViewBridge.h; sourceTree = ""; }; 33 | A6C55B931FA4614D00876D6C /* EZRNPlayerViewBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = EZRNPlayerViewBridge.m; sourceTree = ""; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | A6C55B691FA43E8300876D6C /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | A6C55B631FA43E8300876D6C = { 48 | isa = PBXGroup; 49 | children = ( 50 | A6C55B6E1FA43E8300876D6C /* react-native-ezplayer */, 51 | A6C55B6D1FA43E8300876D6C /* Products */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | A6C55B6D1FA43E8300876D6C /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | A6C55B6C1FA43E8300876D6C /* libreact-native-ezplayer.a */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | A6C55B6E1FA43E8300876D6C /* react-native-ezplayer */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | A6C55B911FA4614D00876D6C /* EZRNPlayerView.swift */, 67 | A6C55B921FA4614D00876D6C /* EZRNPlayerViewBridge.h */, 68 | A6C55B931FA4614D00876D6C /* EZRNPlayerViewBridge.m */, 69 | A6C55B901FA4614C00876D6C /* EZRNPlayerViewManager.swift */, 70 | A6C55B8F1FA4614C00876D6C /* react-native-ezplayer-Bridging-Header.h */, 71 | ); 72 | path = "react-native-ezplayer"; 73 | sourceTree = ""; 74 | }; 75 | /* End PBXGroup section */ 76 | 77 | /* Begin PBXNativeTarget section */ 78 | A6C55B6B1FA43E8300876D6C /* react-native-ezplayer */ = { 79 | isa = PBXNativeTarget; 80 | buildConfigurationList = A6C55B751FA43E8300876D6C /* Build configuration list for PBXNativeTarget "react-native-ezplayer" */; 81 | buildPhases = ( 82 | A6C55B681FA43E8300876D6C /* Sources */, 83 | A6C55B691FA43E8300876D6C /* Frameworks */, 84 | A6C55B6A1FA43E8300876D6C /* CopyFiles */, 85 | ); 86 | buildRules = ( 87 | ); 88 | dependencies = ( 89 | ); 90 | name = "react-native-ezplayer"; 91 | productName = "react-native-ezplayer"; 92 | productReference = A6C55B6C1FA43E8300876D6C /* libreact-native-ezplayer.a */; 93 | productType = "com.apple.product-type.library.static"; 94 | }; 95 | /* End PBXNativeTarget section */ 96 | 97 | /* Begin PBXProject section */ 98 | A6C55B641FA43E8300876D6C /* Project object */ = { 99 | isa = PBXProject; 100 | attributes = { 101 | LastUpgradeCheck = 0900; 102 | ORGANIZATIONNAME = "Zhu yangjun"; 103 | TargetAttributes = { 104 | A6C55B6B1FA43E8300876D6C = { 105 | CreatedOnToolsVersion = 9.0.1; 106 | LastSwiftMigration = 0900; 107 | ProvisioningStyle = Automatic; 108 | }; 109 | }; 110 | }; 111 | buildConfigurationList = A6C55B671FA43E8300876D6C /* Build configuration list for PBXProject "react-native-ezplayer" */; 112 | compatibilityVersion = "Xcode 8.0"; 113 | developmentRegion = en; 114 | hasScannedForEncodings = 0; 115 | knownRegions = ( 116 | en, 117 | ); 118 | mainGroup = A6C55B631FA43E8300876D6C; 119 | productRefGroup = A6C55B6D1FA43E8300876D6C /* Products */; 120 | projectDirPath = ""; 121 | projectRoot = ""; 122 | targets = ( 123 | A6C55B6B1FA43E8300876D6C /* react-native-ezplayer */, 124 | ); 125 | }; 126 | /* End PBXProject section */ 127 | 128 | /* Begin PBXSourcesBuildPhase section */ 129 | A6C55B681FA43E8300876D6C /* Sources */ = { 130 | isa = PBXSourcesBuildPhase; 131 | buildActionMask = 2147483647; 132 | files = ( 133 | A6C55B941FA4614D00876D6C /* EZRNPlayerViewManager.swift in Sources */, 134 | A6C55B961FA4614D00876D6C /* EZRNPlayerViewBridge.m in Sources */, 135 | A6C55B951FA4614D00876D6C /* EZRNPlayerView.swift in Sources */, 136 | ); 137 | runOnlyForDeploymentPostprocessing = 0; 138 | }; 139 | /* End PBXSourcesBuildPhase section */ 140 | 141 | /* Begin XCBuildConfiguration section */ 142 | A6C55B731FA43E8300876D6C /* Debug */ = { 143 | isa = XCBuildConfiguration; 144 | buildSettings = { 145 | ALWAYS_SEARCH_USER_PATHS = NO; 146 | CLANG_ANALYZER_NONNULL = YES; 147 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 148 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 149 | CLANG_CXX_LIBRARY = "libc++"; 150 | CLANG_ENABLE_MODULES = YES; 151 | CLANG_ENABLE_OBJC_ARC = YES; 152 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 153 | CLANG_WARN_BOOL_CONVERSION = YES; 154 | CLANG_WARN_COMMA = YES; 155 | CLANG_WARN_CONSTANT_CONVERSION = YES; 156 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 157 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 158 | CLANG_WARN_EMPTY_BODY = YES; 159 | CLANG_WARN_ENUM_CONVERSION = YES; 160 | CLANG_WARN_INFINITE_RECURSION = YES; 161 | CLANG_WARN_INT_CONVERSION = YES; 162 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 163 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 164 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 165 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 166 | CLANG_WARN_STRICT_PROTOTYPES = YES; 167 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 168 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 169 | CLANG_WARN_UNREACHABLE_CODE = YES; 170 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 171 | CODE_SIGN_IDENTITY = "iPhone Developer"; 172 | COPY_PHASE_STRIP = NO; 173 | DEBUG_INFORMATION_FORMAT = dwarf; 174 | ENABLE_STRICT_OBJC_MSGSEND = YES; 175 | ENABLE_TESTABILITY = YES; 176 | GCC_C_LANGUAGE_STANDARD = gnu11; 177 | GCC_DYNAMIC_NO_PIC = NO; 178 | GCC_NO_COMMON_BLOCKS = YES; 179 | GCC_OPTIMIZATION_LEVEL = 0; 180 | GCC_PREPROCESSOR_DEFINITIONS = ( 181 | "DEBUG=1", 182 | "$(inherited)", 183 | ); 184 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 185 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 186 | GCC_WARN_UNDECLARED_SELECTOR = YES; 187 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 188 | GCC_WARN_UNUSED_FUNCTION = YES; 189 | GCC_WARN_UNUSED_VARIABLE = YES; 190 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 191 | MTL_ENABLE_DEBUG_INFO = YES; 192 | ONLY_ACTIVE_ARCH = YES; 193 | SDKROOT = iphoneos; 194 | }; 195 | name = Debug; 196 | }; 197 | A6C55B741FA43E8300876D6C /* Release */ = { 198 | isa = XCBuildConfiguration; 199 | buildSettings = { 200 | ALWAYS_SEARCH_USER_PATHS = NO; 201 | CLANG_ANALYZER_NONNULL = YES; 202 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 203 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 204 | CLANG_CXX_LIBRARY = "libc++"; 205 | CLANG_ENABLE_MODULES = YES; 206 | CLANG_ENABLE_OBJC_ARC = YES; 207 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 208 | CLANG_WARN_BOOL_CONVERSION = YES; 209 | CLANG_WARN_COMMA = YES; 210 | CLANG_WARN_CONSTANT_CONVERSION = YES; 211 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 212 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 213 | CLANG_WARN_EMPTY_BODY = YES; 214 | CLANG_WARN_ENUM_CONVERSION = YES; 215 | CLANG_WARN_INFINITE_RECURSION = YES; 216 | CLANG_WARN_INT_CONVERSION = YES; 217 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 218 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 219 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 220 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 221 | CLANG_WARN_STRICT_PROTOTYPES = YES; 222 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 223 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 224 | CLANG_WARN_UNREACHABLE_CODE = YES; 225 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 226 | CODE_SIGN_IDENTITY = "iPhone Developer"; 227 | COPY_PHASE_STRIP = NO; 228 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 229 | ENABLE_NS_ASSERTIONS = NO; 230 | ENABLE_STRICT_OBJC_MSGSEND = YES; 231 | GCC_C_LANGUAGE_STANDARD = gnu11; 232 | GCC_NO_COMMON_BLOCKS = YES; 233 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 234 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 235 | GCC_WARN_UNDECLARED_SELECTOR = YES; 236 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 237 | GCC_WARN_UNUSED_FUNCTION = YES; 238 | GCC_WARN_UNUSED_VARIABLE = YES; 239 | IPHONEOS_DEPLOYMENT_TARGET = 11.0; 240 | MTL_ENABLE_DEBUG_INFO = NO; 241 | SDKROOT = iphoneos; 242 | VALIDATE_PRODUCT = YES; 243 | }; 244 | name = Release; 245 | }; 246 | A6C55B761FA43E8300876D6C /* Debug */ = { 247 | isa = XCBuildConfiguration; 248 | buildSettings = { 249 | CLANG_ENABLE_MODULES = YES; 250 | CODE_SIGN_STYLE = Automatic; 251 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 252 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 253 | OTHER_LDFLAGS = "-ObjC"; 254 | PRODUCT_NAME = "$(TARGET_NAME)"; 255 | SKIP_INSTALL = YES; 256 | SWIFT_OBJC_BRIDGING_HEADER = "react-native-ezplayer/react-native-ezplayer-Bridging-Header.h"; 257 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 258 | SWIFT_VERSION = 5.0; 259 | TARGETED_DEVICE_FAMILY = "1,2"; 260 | }; 261 | name = Debug; 262 | }; 263 | A6C55B771FA43E8300876D6C /* Release */ = { 264 | isa = XCBuildConfiguration; 265 | buildSettings = { 266 | CLANG_ENABLE_MODULES = YES; 267 | CODE_SIGN_STYLE = Automatic; 268 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 269 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 270 | OTHER_LDFLAGS = "-ObjC"; 271 | PRODUCT_NAME = "$(TARGET_NAME)"; 272 | SKIP_INSTALL = YES; 273 | SWIFT_OBJC_BRIDGING_HEADER = "react-native-ezplayer/react-native-ezplayer-Bridging-Header.h"; 274 | SWIFT_VERSION = 5.0; 275 | TARGETED_DEVICE_FAMILY = "1,2"; 276 | }; 277 | name = Release; 278 | }; 279 | /* End XCBuildConfiguration section */ 280 | 281 | /* Begin XCConfigurationList section */ 282 | A6C55B671FA43E8300876D6C /* Build configuration list for PBXProject "react-native-ezplayer" */ = { 283 | isa = XCConfigurationList; 284 | buildConfigurations = ( 285 | A6C55B731FA43E8300876D6C /* Debug */, 286 | A6C55B741FA43E8300876D6C /* Release */, 287 | ); 288 | defaultConfigurationIsVisible = 0; 289 | defaultConfigurationName = Release; 290 | }; 291 | A6C55B751FA43E8300876D6C /* Build configuration list for PBXNativeTarget "react-native-ezplayer" */ = { 292 | isa = XCConfigurationList; 293 | buildConfigurations = ( 294 | A6C55B761FA43E8300876D6C /* Debug */, 295 | A6C55B771FA43E8300876D6C /* Release */, 296 | ); 297 | defaultConfigurationIsVisible = 0; 298 | defaultConfigurationName = Release; 299 | }; 300 | /* End XCConfigurationList section */ 301 | }; 302 | rootObject = A6C55B641FA43E8300876D6C /* Project object */; 303 | } 304 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer.xcodeproj/xcuserdata/iqiyi.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | react-native-ezplayer.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | react-native-ezplayer.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer/EZRNPlayerView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EZRNPlayerView.swift 3 | // EZPlayerExample_RN 4 | // 5 | // Created by Zhu yangjun on 2017/9/30. 6 | // Copyright © 2017年 Facebook. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | import EZPlayer 12 | 13 | @objcMembers 14 | open class EZRNPlayerView: UIView { 15 | var player: EZPlayer? 16 | 17 | public var source: [String: Any]? = nil { 18 | willSet { 19 | // if self.player != nil { 20 | // let newUri = newValue?["uri"] as? String 21 | // let oldUri = source?["uri"] as? String 22 | // if newUri == nil { 23 | // self.stop() 24 | // }else if newUri != nil && oldUri != nil && newUri! != oldUri! { 25 | // self.stop() 26 | // } 27 | // } 28 | 29 | // if self.player != nil { 30 | // self.stop() 31 | // } 32 | } 33 | didSet { 34 | // let oldUri = oldValue?["uri"] as? String 35 | // let newUri = source?["uri"] as? String 36 | // if newUri != nil && ( oldUri == nil || oldUri! != newUri!) { 37 | // self.initPlayerIfNeeded() 38 | // } 39 | if let newUri = source?["uri"] as? String { 40 | if self.player != nil{ 41 | self.player?.replaceToPlayWithURL(URL(string: newUri)!) 42 | }else{ 43 | self.initPlayerIfNeeded() 44 | } 45 | } 46 | 47 | } 48 | } 49 | 50 | public var autoPlay: Bool = true { 51 | didSet { 52 | self.player?.autoPlay = autoPlay 53 | } 54 | } 55 | 56 | public var useDefaultUI: Bool = true { 57 | didSet { 58 | if useDefaultUI{ 59 | self.player?.controlViewForIntercept = nil 60 | }else{ 61 | self.player?.controlViewForIntercept = UIView() 62 | } 63 | } 64 | } 65 | 66 | public var videoGravity: String = "aspect"{ 67 | didSet { 68 | self.player?.videoGravity = self.getEZPlayerVideoGravity(videoGravity: videoGravity) 69 | } 70 | } 71 | 72 | public var fullScreenMode: String = "landscape"{ 73 | didSet { 74 | self.player?.fullScreenMode = self.getEZPlayerFullScreenMode(fullScreenMode: fullScreenMode) 75 | } 76 | } 77 | 78 | public var floatMode: String = "auto"{ 79 | didSet { 80 | self.player?.floatMode = self.getEZPlayerFloatMode(floatMode: floatMode) 81 | } 82 | } 83 | 84 | 85 | 86 | 87 | 88 | public var onPlayerHeartbeat: RCTDirectEventBlock? 89 | public var onPlayerPlaybackTimeDidChange: RCTDirectEventBlock? 90 | public var onPlayerStatusDidChange: RCTDirectEventBlock? 91 | public var onPlayerPlaybackDidFinish: RCTDirectEventBlock? 92 | public var onPlayerLoadingDidChange: RCTDirectEventBlock? 93 | public var onPlayerControlsHiddenDidChange: RCTDirectEventBlock? 94 | public var onPlayerDisplayModeDidChange: RCTDirectEventBlock? 95 | public var onPlayerDisplayModeChangedWillAppear: RCTDirectEventBlock? 96 | public var onPlayerDisplayModeChangedDidAppear: RCTDirectEventBlock? 97 | public var onPlayerTapGestureRecognizer: RCTDirectEventBlock? 98 | public var onPlayerDidPersistContentKey: RCTDirectEventBlock? 99 | public var onPlayerPIPControllerWillStart: RCTDirectEventBlock? 100 | public var onPlayerPIPControllerDidStart: RCTDirectEventBlock? 101 | public var onPlayerPIPFailedToStart: RCTDirectEventBlock? 102 | public var onPlayerPIPControllerWillEnd: RCTDirectEventBlock? 103 | public var onPlayerPIPControllerDidEnd: RCTDirectEventBlock? 104 | public var onPlayerPIPRestoreUserInterfaceForStop: RCTDirectEventBlock? 105 | // MARK: - Life 106 | 107 | public override init(frame: CGRect) { 108 | super.init(frame: CGRect(x:0,y:0,width:100,height:100)) 109 | // self.backgroundColor = UIColor.red 110 | // self.initPlayerIfNeeded() 111 | 112 | } 113 | 114 | 115 | required public init?(coder aDecoder: NSCoder) { 116 | fatalError("init(coder:) has not been implemented") 117 | } 118 | 119 | override open func willMove(toWindow newWindow: UIWindow?) { 120 | // if newWindow == nil { 121 | // self.stop() 122 | // } 123 | } 124 | 125 | override open func willMove(toSuperview newSuperview: UIView?) { 126 | // if newSuperview == nil { 127 | // self.stop() 128 | // } 129 | } 130 | 131 | deinit { 132 | print("swift播放器释放") 133 | } 134 | 135 | // MARK: - player 136 | 137 | open func initPlayerIfNeeded(){ 138 | if(self.player == nil){ 139 | self.addObservers() 140 | self.player = self.useDefaultUI ? EZPlayer() : EZPlayer(controlView: UIView()) 141 | 142 | self.player!.autoPlay = self.autoPlay 143 | self.player!.videoGravity = self.getEZPlayerVideoGravity(videoGravity: self.videoGravity) 144 | self.player!.fullScreenMode = self.getEZPlayerFullScreenMode(fullScreenMode: self.fullScreenMode) 145 | self.player!.backButtonBlock = { fromDisplayMode in 146 | if fromDisplayMode == .embedded { 147 | self.stop() 148 | }else if fromDisplayMode == .fullscreen { 149 | 150 | }else if fromDisplayMode == .float { 151 | self.stop() 152 | } 153 | } 154 | self.player!.playWithURL(URL(string: source?["uri"] as? String ?? "")!, embeddedContentView: self) 155 | } 156 | } 157 | 158 | open func releasePlayerResource() { 159 | if self.player != nil { 160 | self.removeObservers() 161 | self.player = nil 162 | self.source = nil 163 | 164 | } 165 | } 166 | 167 | open func play(){ 168 | // if let source = self.source ,let uri = source["uri"] as? String { 169 | // self.initPlayerIfNeeded() 170 | // } 171 | self.player?.play() 172 | } 173 | 174 | open func pause(){ 175 | self.player?.pause() 176 | } 177 | 178 | open func stop(){ 179 | self.player?.stop() 180 | self.releasePlayerResource() 181 | } 182 | 183 | open func seek(to time: TimeInterval, completionHandler: ((Bool) -> Swift.Void )? = nil){ 184 | self.player?.seek(to: time, completionHandler: completionHandler) 185 | } 186 | 187 | open func replaceToPlay(source: [String: Any]){ 188 | self.source = source; 189 | } 190 | 191 | /// 视频播放速率 192 | // public var rate: Float{ 193 | // get { 194 | // if let player = self.player { 195 | // return player.rate 196 | // } 197 | // return .nan 198 | // } 199 | // set { 200 | // if let player = self.player { 201 | // player.rate = newValue 202 | // } 203 | // } 204 | // } 205 | 206 | 207 | 208 | private func getEZPlayerVideoGravity(videoGravity: String) -> EZPlayerVideoGravity{ 209 | var videoGravitString = "" 210 | switch(videoGravity){ 211 | case "aspect": videoGravitString = "AVLayerVideoGravityResizeAspect" 212 | case "aspectFill": videoGravitString = "AVLayerVideoGravityResizeAspectFill" 213 | case "scaleFill": videoGravitString = "AVLayerVideoGravityResize" 214 | default:videoGravitString = "AVLayerVideoGravityResizeAspect" 215 | } 216 | return EZPlayerVideoGravity(rawValue: videoGravitString)! 217 | } 218 | 219 | private func getEZPlayerFullScreenMode(fullScreenMode: String) -> EZPlayerFullScreenMode{ 220 | var ezPlayerFullScreenMode = EZPlayerFullScreenMode.landscape 221 | switch(fullScreenMode){ 222 | case "portrait": ezPlayerFullScreenMode = EZPlayerFullScreenMode.portrait 223 | case "landscape": ezPlayerFullScreenMode = EZPlayerFullScreenMode.landscape 224 | default:ezPlayerFullScreenMode = EZPlayerFullScreenMode.landscape 225 | } 226 | return ezPlayerFullScreenMode 227 | } 228 | 229 | private func getEZPlayerFloatMode(floatMode: String) -> EZPlayerFloatMode{ 230 | var ezPlayerFloatMode = EZPlayerFloatMode.auto 231 | switch(floatMode){ 232 | case "none": ezPlayerFloatMode = EZPlayerFloatMode.none 233 | case "auto": ezPlayerFloatMode = EZPlayerFloatMode.auto 234 | case "system": ezPlayerFloatMode = EZPlayerFloatMode.system 235 | case "window": ezPlayerFloatMode = EZPlayerFloatMode.window 236 | default:ezPlayerFloatMode = EZPlayerFloatMode.auto 237 | } 238 | return ezPlayerFloatMode 239 | } 240 | } 241 | 242 | 243 | // MARK: - Notification 244 | extension EZRNPlayerView { 245 | open func addObservers(){ 246 | self.removeObservers() 247 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerHeartbeat(_:)), name: NSNotification.Name.EZPlayerHeartbeat, object: nil) 248 | 249 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPlaybackTimeDidChange(_:)), name: NSNotification.Name.EZPlayerPlaybackTimeDidChange, object: nil) 250 | 251 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerStatusDidChange(_:)), name: NSNotification.Name.EZPlayerStatusDidChange, object: nil) 252 | 253 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPlaybackDidFinish(_:)), name: NSNotification.Name.EZPlayerPlaybackDidFinish, object: nil) 254 | 255 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerLoadingDidChange(_:)), name: NSNotification.Name.EZPlayerLoadingDidChange, object: nil) 256 | 257 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerControlsHiddenDidChange(_:)), name: NSNotification.Name.EZPlayerControlsHiddenDidChange, object: nil) 258 | 259 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerDisplayModeDidChange(_:)), name: NSNotification.Name.EZPlayerDisplayModeDidChange, object: nil) 260 | 261 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerDisplayModeChangedWillAppear(_:)), name: NSNotification.Name.EZPlayerDisplayModeChangedWillAppear, object: nil) 262 | 263 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerDisplayModeChangedDidAppear(_:)), name: NSNotification.Name.EZPlayerDisplayModeChangedDidAppear, object: nil) 264 | 265 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerTapGestureRecognizer(_:)), name: NSNotification.Name.EZPlayerTapGestureRecognizer, object: nil) 266 | 267 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerDidPersistContentKey(_:)), name: NSNotification.Name.EZPlayerDidPersistContentKey, object: nil) 268 | 269 | //pip 270 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPControllerWillStart(_:)), name: NSNotification.Name.EZPlayerPIPControllerWillStart, object: nil) 271 | 272 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPControllerDidStart(_:)), name: NSNotification.Name.EZPlayerPIPControllerDidStart, object: nil) 273 | 274 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPFailedToStart(_:)), name: NSNotification.Name.EZPlayerPIPFailedToStart, object: nil) 275 | 276 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPControllerWillEnd(_:)), name: NSNotification.Name.EZPlayerPIPControllerWillEnd, object: nil) 277 | 278 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPControllerDidEnd(_:)), name: NSNotification.Name.EZPlayerPIPControllerDidEnd, object: nil) 279 | 280 | NotificationCenter.default.addObserver(self, selector: #selector(self.playerPIPRestoreUserInterfaceForStop(_:)), name: NSNotification.Name.EZPlayerPIPRestoreUserInterfaceForStop, object: nil) 281 | 282 | 283 | 284 | } 285 | 286 | open func removeObservers(){ 287 | NotificationCenter.default.removeObserver(self) 288 | } 289 | 290 | @objc func playerHeartbeat(_ notifiaction: Notification) { 291 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 292 | return 293 | } 294 | var playerInfo = [String:Any]() 295 | if let player = self.player{ 296 | if let isLive = player.isLive { 297 | playerInfo["isLive"] = isLive 298 | } 299 | if let duration = player.duration { 300 | playerInfo["duration"] = duration.isNaN ? -1 : duration //maybe nan 301 | } 302 | if let currentTime = player.currentTime { 303 | playerInfo["currentTime"] = currentTime 304 | } 305 | 306 | playerInfo["isM3U8"] = player.isM3U8 307 | playerInfo["rate"] = player.rate.isNaN ? 0 : player.rate //maybe nan 308 | playerInfo["systemVolume"] = player.systemVolume 309 | playerInfo["state"] = self.stateName(state: player.state) 310 | 311 | } 312 | self.onPlayerHeartbeat?(playerInfo) 313 | } 314 | 315 | @objc func playerPlaybackTimeDidChange(_ notifiaction: Notification) { 316 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 317 | return 318 | } 319 | self.onPlayerPlaybackTimeDidChange?(notifiaction.userInfo) 320 | 321 | } 322 | 323 | @objc func playerStatusDidChange(_ notifiaction: Notification) { 324 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 325 | return 326 | } 327 | let newState = self.stateName(state: notifiaction.userInfo![Notification.Key.EZPlayerNewStateKey] as! EZPlayerState) 328 | let oldState = self.stateName(state: notifiaction.userInfo![Notification.Key.EZPlayerOldStateKey] as! EZPlayerState) 329 | self.onPlayerStatusDidChange?(["newState":newState,"oldState":oldState]) 330 | } 331 | 332 | @objc func playerPlaybackDidFinish(_ notifiaction: Notification) { 333 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 334 | return 335 | } 336 | let reason = self.finishReason(finishReason: notifiaction.userInfo![Notification.Key.EZPlayerPlaybackDidFinishReasonKey] as! EZPlayerPlaybackDidFinishReason) 337 | self.onPlayerPlaybackDidFinish?(["playerPlaybackDidFinish" : reason]) 338 | } 339 | 340 | @objc func playerLoadingDidChange(_ notifiaction: Notification) { 341 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 342 | return 343 | } 344 | self.onPlayerLoadingDidChange?(notifiaction.userInfo) 345 | } 346 | 347 | @objc func playerControlsHiddenDidChange(_ notifiaction: Notification) { 348 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 349 | return 350 | } 351 | self.onPlayerControlsHiddenDidChange?(notifiaction.userInfo) 352 | } 353 | 354 | @objc func playerDisplayModeDidChange(_ notifiaction: Notification) { 355 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 356 | return 357 | } 358 | let displayMode = self.displayModeName(displayMode:self.player?.displayMode ?? .none) 359 | self.onPlayerDisplayModeDidChange?(["displayMode":displayMode]) 360 | } 361 | 362 | @objc func playerDisplayModeChangedWillAppear(_ notifiaction: Notification) { 363 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 364 | return 365 | } 366 | self.onPlayerDisplayModeChangedWillAppear?(notifiaction.userInfo) 367 | } 368 | 369 | @objc func playerDisplayModeChangedDidAppear(_ notifiaction: Notification) { 370 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 371 | return 372 | } 373 | self.onPlayerDisplayModeChangedDidAppear?(notifiaction.userInfo) 374 | } 375 | 376 | @objc func playerTapGestureRecognizer(_ notifiaction: Notification) { 377 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 378 | return 379 | } 380 | self.onPlayerTapGestureRecognizer?(notifiaction.userInfo) 381 | } 382 | 383 | @objc func playerDidPersistContentKey(_ notifiaction: Notification) { 384 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 385 | return 386 | } 387 | self.onPlayerDidPersistContentKey?(notifiaction.userInfo) 388 | } 389 | 390 | @objc func playerPIPControllerWillStart(_ notifiaction: Notification) { 391 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 392 | return 393 | } 394 | self.onPlayerPIPControllerWillStart?(notifiaction.userInfo) 395 | } 396 | 397 | @objc func playerPIPControllerDidStart(_ notifiaction: Notification) { 398 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 399 | return 400 | } 401 | self.onPlayerPIPControllerDidStart?(notifiaction.userInfo) 402 | } 403 | 404 | @objc func playerPIPFailedToStart(_ notifiaction: Notification) { 405 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 406 | return 407 | } 408 | self.onPlayerPIPFailedToStart?(notifiaction.userInfo) 409 | } 410 | 411 | @objc func playerPIPControllerWillEnd(_ notifiaction: Notification) { 412 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 413 | return 414 | } 415 | self.onPlayerPIPControllerWillEnd?(notifiaction.userInfo) 416 | } 417 | 418 | @objc func playerPIPControllerDidEnd(_ notifiaction: Notification) { 419 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 420 | return 421 | } 422 | self.onPlayerPIPControllerDidEnd?(notifiaction.userInfo) 423 | } 424 | 425 | @objc func playerPIPRestoreUserInterfaceForStop(_ notifiaction: Notification) { 426 | guard let player = notifiaction.object as? EZPlayer ,let selfPlayer = self.player , player == selfPlayer else{ 427 | return 428 | } 429 | self.onPlayerPIPRestoreUserInterfaceForStop?(notifiaction.userInfo) 430 | } 431 | 432 | private func stateName(state: EZPlayerState) -> String{ 433 | var stateName = "" 434 | switch (state) { 435 | case .unknown: stateName = "unknown" 436 | case .readyToPlay: stateName = "readyToPlay" 437 | case .buffering: stateName = "buffering" 438 | case .bufferFinished: stateName = "bufferFinished" 439 | case .playing: stateName = "playing" 440 | case .seekingForward: stateName = "seekingForward" 441 | case .seekingBackward: stateName = "seekingBackward" 442 | case .pause: stateName = "pause" 443 | case .stopped: stateName = "stopped" 444 | case .error(let type): 445 | switch (type){ 446 | case .invalidContentURL: stateName = "error.invalidContentURL" 447 | case .playerFail: stateName = "error.playerFail" 448 | } 449 | } 450 | return stateName 451 | } 452 | 453 | private func displayModeName(displayMode: EZPlayerDisplayMode) -> String{ 454 | var displayModeName = "" 455 | switch (displayMode) { 456 | case .none: displayModeName = "none" 457 | case .embedded: displayModeName = "embedded" 458 | case .fullscreen: displayModeName = "fullscreen" 459 | case .float: displayModeName = "float" 460 | } 461 | return displayModeName 462 | } 463 | 464 | 465 | private func finishReason(finishReason: EZPlayerPlaybackDidFinishReason) -> String{ 466 | var reason = "" 467 | switch (finishReason) { 468 | case .playbackEndTime: reason = "playbackEndTime" 469 | case .playbackError: reason = "playbackError" 470 | case .stopByUser: reason = "stopByUser" 471 | } 472 | return reason 473 | } 474 | 475 | 476 | } 477 | 478 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer/EZRNPlayerViewBridge.h: -------------------------------------------------------------------------------- 1 | // 2 | // EZRNPlayerViewBridge.h 3 | // EZPlayerExample_RN 4 | // 5 | // Created by Zhu yangjun on 2017/9/30. 6 | // Copyright © 2017年 Facebook. All rights reserved. 7 | // 8 | 9 | #import 10 | NS_ASSUME_NONNULL_BEGIN 11 | @interface EZRNPlayerViewBridge : RCTView 12 | @property (nonatomic, strong, nullable) NSDictionary *source; 13 | @property (nonatomic, assign) BOOL *autoPlay; 14 | @property (nonatomic, strong) NSString *videoGravity; 15 | @property (nonatomic, strong) NSString *fullScreenMode; 16 | @property (nonatomic, strong) NSString *floatMode; 17 | @property (nonatomic, assign) BOOL *useDefaultUI; 18 | 19 | 20 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerHeartbeat; 21 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPlaybackTimeDidChange; 22 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerStatusDidChange; 23 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPlaybackDidFinish; 24 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerLoadingDidChange; 25 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerControlsHiddenDidChange; 26 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerDisplayModeDidChange; 27 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerDisplayModeChangedWillAppear; 28 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerDisplayModeChangedDidAppear; 29 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerTapGestureRecognizer; 30 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerDidPersistContentKey; 31 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPControllerWillStart; 32 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPControllerDidStart; 33 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPFailedToStart; 34 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPControllerWillEnd; 35 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPControllerDidEnd; 36 | @property (nonatomic, strong, nullable) RCTDirectEventBlock onPlayerPIPRestoreUserInterfaceForStop; 37 | 38 | 39 | @end 40 | NS_ASSUME_NONNULL_END 41 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer/EZRNPlayerViewBridge.m: -------------------------------------------------------------------------------- 1 | // 2 | // EZRNPlayerViewBridge.m 3 | // EZPlayerExample_RN 4 | // 5 | // Created by Zhu yangjun on 2017/9/30. 6 | // Copyright © 2017年 Facebook. All rights reserved. 7 | // 8 | 9 | #import "EZRNPlayerViewBridge.h" 10 | 11 | #import 12 | #import 13 | 14 | @interface RCT_EXTERN_MODULE(EZRNPlayerViewManager, RCTViewManager) 15 | RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary) 16 | RCT_EXPORT_VIEW_PROPERTY(autoPlay, BOOL) 17 | RCT_EXPORT_VIEW_PROPERTY(videoGravity, NSString) 18 | RCT_EXPORT_VIEW_PROPERTY(fullScreenMode, NSString) 19 | RCT_EXPORT_VIEW_PROPERTY(floatMode, NSString) 20 | RCT_EXPORT_VIEW_PROPERTY(useDefaultUI, BOOL) 21 | 22 | 23 | RCT_EXPORT_VIEW_PROPERTY(onPlayerHeartbeat, RCTBubblingEventBlock) 24 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPlaybackTimeDidChange, RCTBubblingEventBlock) 25 | RCT_EXPORT_VIEW_PROPERTY(onPlayerStatusDidChange, RCTBubblingEventBlock) 26 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPlaybackDidFinish, RCTBubblingEventBlock) 27 | RCT_EXPORT_VIEW_PROPERTY(onPlayerLoadingDidChange, RCTBubblingEventBlock) 28 | RCT_EXPORT_VIEW_PROPERTY(onPlayerControlsHiddenDidChange, RCTBubblingEventBlock) 29 | RCT_EXPORT_VIEW_PROPERTY(onPlayerDisplayModeDidChange, RCTBubblingEventBlock) 30 | RCT_EXPORT_VIEW_PROPERTY(onPlayerDisplayModeChangedWillAppear, RCTBubblingEventBlock) 31 | RCT_EXPORT_VIEW_PROPERTY(onPlayerDisplayModeChangedDidAppear, RCTBubblingEventBlock) 32 | RCT_EXPORT_VIEW_PROPERTY(onPlayerTapGestureRecognizer, RCTBubblingEventBlock) 33 | RCT_EXPORT_VIEW_PROPERTY(onPlayerDidPersistContentKey, RCTBubblingEventBlock) 34 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPControllerWillStart, RCTBubblingEventBlock) 35 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPControllerDidStart, RCTBubblingEventBlock) 36 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPFailedToStart, RCTBubblingEventBlock) 37 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPControllerWillEnd, RCTBubblingEventBlock) 38 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPControllerDidEnd, RCTBubblingEventBlock) 39 | RCT_EXPORT_VIEW_PROPERTY(onPlayerPIPRestoreUserInterfaceForStop, RCTBubblingEventBlock) 40 | 41 | RCT_EXTERN_METHOD( play: (nonnull NSNumber *)reactTag ) 42 | RCT_EXTERN_METHOD( pause: (nonnull NSNumber *)reactTag ) 43 | RCT_EXTERN_METHOD( stop: (nonnull NSNumber *)reactTag ) 44 | RCT_EXTERN_METHOD( seek: (nonnull NSNumber *)reactTag time:(double *)time callback:( RCTResponseSenderBlock)callback) 45 | RCT_EXTERN_METHOD( replaceToPlay: (nonnull NSNumber *)reactTag source:(NSDictionary*) source) 46 | 47 | RCT_EXTERN_METHOD( rate: (nonnull NSNumber *)reactTag rate:(float *)rate ) 48 | RCT_EXTERN_METHOD( autoPlay: (nonnull NSNumber *)reactTag autoPlay:(BOOL *)autoPlay ) 49 | 50 | RCT_EXTERN_METHOD( videoGravity: (nonnull NSNumber *)reactTag videoGravity:(NSString *)videoGravity ) 51 | 52 | RCT_EXTERN_METHOD( toEmbedded: (nonnull NSNumber *)reactTag animated:(BOOL *)animated callback:( RCTResponseSenderBlock)callback) 53 | RCT_EXTERN_METHOD( toFloat: (nonnull NSNumber *)reactTag animated:(BOOL *)animated callback:( RCTResponseSenderBlock)callback) 54 | RCT_EXTERN_METHOD( toFull: (nonnull NSNumber *)reactTag orientation:(NSString*)orientation animated:(BOOL *)animated callback:( RCTResponseSenderBlock)callback) 55 | RCT_EXTERN_METHOD( fullScreenMode: (nonnull NSNumber *)reactTag fullScreenMode:(NSString *)fullScreenMode ) 56 | RCT_EXTERN_METHOD( floatMode: (nonnull NSNumber *)reactTag floatMode:(NSString *)floatMode ) 57 | 58 | //RCT_EXPORT_VIEW_PROPERTY(imageNumber, NSInteger) 59 | // 60 | //RCT_EXPORT_VIEW_PROPERTY(repeatCount, NSInteger) 61 | // 62 | //RCT_EXPORT_VIEW_PROPERTY(imageLayout, NSString) 63 | // 64 | //RCT_EXPORT_VIEW_PROPERTY(animated, BOOL) 65 | // 66 | //RCT_EXPORT_VIEW_PROPERTY(duration, double) 67 | // 68 | //RCT_EXTERN_METHOD( createSequence: (nonnull NSNumber *)reactTag nameWithPath:(NSString *)nameWithPath count:(NSInteger *)count format:(NSString *)format duration:(double *)duration ) 69 | // 70 | //RCT_EXTERN_METHOD( animate: (nonnull NSNumber *)reactTag shouldPlay:(BOOL *)shouldPlay ) 71 | @end 72 | 73 | 74 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer/EZRNPlayerViewManager.swift: -------------------------------------------------------------------------------- 1 | // 2 | // EZRNPlayerViewManager.swift 3 | // EZPlayerExample_RN 4 | // 5 | // Created by Zhu yangjun on 2017/9/30. 6 | // Copyright © 2017年 Facebook. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | import EZPlayer 12 | 13 | @objc(EZRNPlayerViewManager) 14 | class EZRNPlayerViewManager : RCTViewManager { 15 | 16 | override class func requiresMainQueueSetup() -> Bool { 17 | return true 18 | } 19 | 20 | override func view() -> UIView! { 21 | return EZRNPlayerView(); 22 | } 23 | 24 | @objc func play(_ reactTag: NSNumber) { 25 | self.execute(reactTag: reactTag) { (playerView) in 26 | playerView.play(); 27 | } 28 | } 29 | 30 | @objc func pause(_ reactTag: NSNumber) { 31 | self.execute(reactTag: reactTag) { (playerView) in 32 | playerView.pause(); 33 | } 34 | } 35 | 36 | @objc func stop(_ reactTag: NSNumber) { 37 | self.execute(reactTag: reactTag) { (playerView) in 38 | playerView.stop(); 39 | } 40 | } 41 | 42 | @objc func seek(_ reactTag: NSNumber, time: Double, callback : (RCTResponseSenderBlock)? = nil) { 43 | self.execute(reactTag: reactTag) { (playerView) in 44 | playerView.seek(to: time, completionHandler: { (finished) in 45 | // callback([NSNull(),finished]) 46 | callback?([finished]) 47 | }); 48 | } 49 | } 50 | 51 | @objc func replaceToPlay(_ reactTag: NSNumber, source: [String: Any]) { 52 | self.execute(reactTag: reactTag) { (playerView) in 53 | playerView.replaceToPlay(source: source) 54 | } 55 | } 56 | 57 | @objc func rate(_ reactTag: NSNumber, rate: Float) { 58 | self.execute(reactTag: reactTag) { (playerView) in 59 | playerView.player?.rate = rate 60 | } 61 | } 62 | 63 | @objc func autoPlay(_ reactTag: NSNumber, autoPlay: Bool) { 64 | self.execute(reactTag: reactTag) { (playerView) in 65 | playerView.autoPlay = autoPlay 66 | } 67 | } 68 | 69 | @objc func videoGravity(_ reactTag: NSNumber, videoGravity: String) { 70 | self.execute(reactTag: reactTag) { (playerView) in 71 | playerView.videoGravity = videoGravity 72 | } 73 | } 74 | 75 | @objc func toEmbedded(_ reactTag: NSNumber, animated: Bool = true, callback : (RCTResponseSenderBlock)? = nil) { 76 | self.execute(reactTag: reactTag) { (playerView) in 77 | playerView.player?.toEmbedded(animated: animated, completion: { (finished) in 78 | callback?([finished]) 79 | }) 80 | } 81 | } 82 | 83 | @objc func toFloat(_ reactTag: NSNumber, animated: Bool = true, callback : (RCTResponseSenderBlock)? = nil) { 84 | self.execute(reactTag: reactTag) { (playerView) in 85 | playerView.player?.toFloat(animated: animated, completion: { (finished) in 86 | callback?([finished]) 87 | }) 88 | } 89 | } 90 | 91 | @objc func toFull(_ reactTag: NSNumber, orientation:String = "landscapeLeft", animated: Bool = true, callback : (RCTResponseSenderBlock)? = nil) { 92 | self.execute(reactTag: reactTag) { (playerView) in 93 | playerView.player?.toFull(orientation == "landscapeLeft" ? .landscapeLeft : .landscapeRight ,animated: animated, completion: { (finished) in 94 | callback?([finished]) 95 | }) 96 | } 97 | } 98 | 99 | @objc func fullScreenMode(_ reactTag: NSNumber, fullScreenMode:String = "portrait") { 100 | self.execute(reactTag: reactTag) { (playerView) in 101 | playerView.player?.fullScreenMode = fullScreenMode == "portrait" ? .portrait : .landscape 102 | } 103 | } 104 | 105 | @objc func floatMode(_ reactTag: NSNumber, floatMode:String = "auto") { 106 | self.execute(reactTag: reactTag) { (playerView) in 107 | var ezPlayerFloatMode:EZPlayerFloatMode = .auto 108 | switch(floatMode){ 109 | case "none": ezPlayerFloatMode = .none 110 | case "auto": ezPlayerFloatMode = .auto 111 | case "system": ezPlayerFloatMode = .system 112 | case "window": ezPlayerFloatMode = .window 113 | default:ezPlayerFloatMode = .auto 114 | } 115 | playerView.player?.floatMode = ezPlayerFloatMode 116 | } 117 | } 118 | 119 | 120 | 121 | private func execute(reactTag: NSNumber,action: @escaping ((EZRNPlayerView) -> Swift.Void )){ 122 | self.bridge!.uiManager.addUIBlock { (uiManager: RCTUIManager?, viewRegistry:[NSNumber : UIView]?) in 123 | if let playerView = viewRegistry![reactTag] as? EZRNPlayerView { 124 | action(playerView); 125 | } 126 | } 127 | } 128 | 129 | } 130 | -------------------------------------------------------------------------------- /ios/react-native-ezplayer/react-native-ezplayer-Bridging-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // Use this file to import your target's public headers that you would like to expose to Swift. 3 | // 4 | 5 | #import 6 | #import 7 | 8 | 9 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-native-ezplayer", 3 | "version": "1.1.0", 4 | "description": "EZPlayer component for react-native apps", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \\\"Error: no test specified\\\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/easyui/react-native-ezplayer.git" 12 | }, 13 | "keywords": [ 14 | "react", 15 | "react-native", 16 | "react-native-component", 17 | "react-native-ezplayer", 18 | "ezplayer", 19 | "ios", 20 | "avplayer", 21 | "media", 22 | "video" 23 | ], 24 | "author": "Zhu Yangjun(gzhuyangjun@gmail.com)", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/easyui/react-native-ezplayer/issues" 28 | }, 29 | "homepage": "https://github.com/easyui/react-native-ezplayer#readme" 30 | } -------------------------------------------------------------------------------- /src/EZPlayer.js: -------------------------------------------------------------------------------- 1 | import React, {Component} from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { 4 | requireNativeComponent, 5 | NativeModules, 6 | findNodeHandle, 7 | ViewPropTypes, 8 | } from 'react-native'; 9 | // refers to EZRNPlayerView.swift we have in XCode 10 | const EZRNPlayerViewNative = requireNativeComponent('EZRNPlayerView', EZPlayer); 11 | 12 | // refers to EZRNPlayerViewManager.swift 13 | const EZRNPlayerViewManager = NativeModules.EZRNPlayerViewManager; 14 | 15 | class EZPlayer extends Component { 16 | static propTypes = { 17 | ...ViewPropTypes, 18 | source: PropTypes.object, 19 | autoPlay: PropTypes.bool, 20 | useDefaultUI: PropTypes.bool, 21 | videoGravity: PropTypes.string, //aspect,aspectFill,scaleFill 22 | fullScreenMode: PropTypes.string, //portrait,landscape 23 | floatMode: PropTypes.string, //none,auto,system,window 24 | 25 | onPlayerHeartbeat: PropTypes.func, 26 | onPlayerPlaybackTimeDidChange: PropTypes.func, 27 | onPlayerStatusDidChange: PropTypes.func, 28 | onPlayerPlaybackDidFinish: PropTypes.func, 29 | onPlayerLoadingDidChange: PropTypes.func, 30 | onPlayerControlsHiddenDidChange: PropTypes.func, 31 | onPlayerDisplayModeDidChange: PropTypes.func, 32 | onPlayerDisplayModeChangedWillAppear: PropTypes.func, 33 | onPlayerDisplayModeChangedDidAppear: PropTypes.func, 34 | onPlayerTapGestureRecognizer: PropTypes.func, 35 | onPlayerDidPersistContentKey: PropTypes.func, 36 | onPlayerPIPControllerWillStart: PropTypes.func, 37 | onPlayerPIPControllerDidStart: PropTypes.func, 38 | onPlayerPIPFailedToStart: PropTypes.func, 39 | onPlayerPIPControllerWillEnd: PropTypes.func, 40 | onPlayerPIPControllerDidEnd: PropTypes.func, 41 | onPlayerPIPRestoreUserInterfaceForStop: PropTypes.func, 42 | }; 43 | 44 | static defaultProps = { 45 | ...Component.defaultProps, 46 | source: null, 47 | autoPlay: true, 48 | useDefaultUI: true, 49 | videoGravity: 'aspect', 50 | fullScreenMode: 'landscape', 51 | floatMode: 'auto', 52 | }; 53 | 54 | /** 55 | | ------------------------------------------------------- 56 | | EZPlayer 组件生命周期 57 | | ------------------------------------------------------- 58 | */ 59 | constructor(props) { 60 | super(props); 61 | 62 | /** 63 | * 播放器事件 64 | */ 65 | this.events = { 66 | onPlayerHeartbeat: this._onPlayerHeartbeat.bind(this), 67 | onPlayerPlaybackTimeDidChange: this._onPlayerPlaybackTimeDidChange.bind( 68 | this, 69 | ), 70 | onPlayerStatusDidChange: this._onPlayerStatusDidChange.bind(this), 71 | onPlayerPlaybackDidFinish: this._onPlayerPlaybackDidFinish.bind(this), 72 | onPlayerLoadingDidChange: this._onPlayerLoadingDidChange.bind(this), 73 | onPlayerControlsHiddenDidChange: this._onPlayerControlsHiddenDidChange.bind( 74 | this, 75 | ), 76 | onPlayerDisplayModeDidChange: this._onPlayerDisplayModeDidChange.bind( 77 | this, 78 | ), 79 | onPlayerDisplayModeChangedWillAppear: this._onPlayerDisplayModeChangedWillAppear.bind( 80 | this, 81 | ), 82 | onPlayerDisplayModeChangedDidAppear: this._onPlayerDisplayModeChangedDidAppear.bind( 83 | this, 84 | ), 85 | onPlayerTapGestureRecognizer: this._onPlayerTapGestureRecognizer.bind( 86 | this, 87 | ), 88 | onPlayerDidPersistContentKey: this._onPlayerDidPersistContentKey.bind( 89 | this, 90 | ), 91 | onPlayerPIPControllerWillStart: this._onPlayerPIPControllerWillStart.bind( 92 | this, 93 | ), 94 | onPlayerPIPControllerDidStart: this._onPlayerPIPControllerDidStart.bind( 95 | this, 96 | ), 97 | onPlayerPIPFailedToStart: this._onPlayerPIPFailedToStart.bind(this), 98 | onPlayerPIPControllerWillEnd: this._onPlayerPIPControllerWillEnd.bind( 99 | this, 100 | ), 101 | onPlayerPIPControllerDidEnd: this._onPlayerPIPControllerDidEnd.bind(this), 102 | onPlayerPIPRestoreUserInterfaceForStop: this._onPlayerPIPRestoreUserInterfaceForStop.bind( 103 | this, 104 | ), 105 | }; 106 | 107 | /** 108 | * 播放器 109 | */ 110 | this.player = { 111 | ref: EZRNPlayerViewNative, 112 | 113 | state: 'unknown', //unknown,readyToPlay,buffering,bufferFinished,playing,seekingForward,seekingBackward,pause,stopped,error.invalidContentURL,error.playerFail 114 | 115 | currentTime: undefined, 116 | duration: undefined, 117 | isLive: undefined, 118 | rate: 0, 119 | systemVolume: 0, 120 | isM3U8: false, 121 | displayMode: undefined, //none,embedded,fullscreen,float 122 | isLoading: true, 123 | 124 | firstReady: false, 125 | }; 126 | } 127 | 128 | componentWillUnmount() { 129 | console.log('[EZPlayer] componentWillUnmount'); 130 | this.player.firstReady = false; 131 | this.stop(); 132 | } 133 | 134 | /** 135 | | ------------------------------------------------------- 136 | | 播放器事件 137 | | ------------------------------------------------------- 138 | */ 139 | _onPlayerHeartbeat(event) { 140 | console.log( 141 | '[EZPlayer] onPlayerHeartbeat ' + JSON.stringify(event.nativeEvent), 142 | ); 143 | if (this.player.firstReady) { 144 | this.player.currentTime = event.nativeEvent.currentTime; 145 | this.player.duration = event.nativeEvent.duration; 146 | this.player.isLive = event.nativeEvent.isLive; 147 | this.player.rate = event.nativeEvent.rate; 148 | this.player.systemVolume = event.nativeEvent.systemVolume; 149 | this.player.isM3U8 = event.nativeEvent.isM3U8; 150 | this.player.state = event.nativeEvent.state; 151 | } 152 | 153 | if (typeof this.props.onPlayerHeartbeat === 'function') { 154 | this.props.onPlayerHeartbeat(...arguments); 155 | } 156 | } 157 | 158 | _onPlayerPlaybackTimeDidChange(event) { 159 | console.log( 160 | '[EZPlayer] onPlayerPlaybackTimeDidChange ' + 161 | JSON.stringify(event.nativeEvent), 162 | ); 163 | if (typeof this.props.onPlayerPlaybackTimeDidChange === 'function') { 164 | this.props.onPlayerPlaybackTimeDidChange(...arguments); 165 | } 166 | } 167 | 168 | _onPlayerStatusDidChange(event) { 169 | console.log( 170 | '[EZPlayer] onPlayerStatusDidChange ' + JSON.stringify(event.nativeEvent), 171 | ); 172 | if ( 173 | event.nativeEvent.oldState === 'unknown' && 174 | event.nativeEvent.newState === 'readyToPlay' 175 | ) { 176 | this.player.firstReady = true; 177 | } 178 | this.player.state = event.nativeEvent.newState; 179 | if (typeof this.props.onPlayerStatusDidChange === 'function') { 180 | this.props.onPlayerStatusDidChange(...arguments); 181 | } 182 | } 183 | 184 | _onPlayerPlaybackDidFinish(event) { 185 | console.log( 186 | '[EZPlayer] onPlayerPlaybackDidFinish ' + 187 | JSON.stringify(event.nativeEvent), 188 | ); 189 | if (typeof this.props.onPlayerPlaybackDidFinish === 'function') { 190 | this.props.onPlayerPlaybackDidFinish(...arguments); 191 | } 192 | } 193 | 194 | _onPlayerLoadingDidChange(event) { 195 | console.log( 196 | '[EZPlayer] onPlayerLoadingDidChange ' + 197 | JSON.stringify(event.nativeEvent), 198 | ); 199 | this.player.isLoading = event.nativeEvent.EZPlayerLoadingDidChangeKey; 200 | if (typeof this.props.onPlayerLoadingDidChange === 'function') { 201 | this.props.onPlayerLoadingDidChange(...arguments); 202 | } 203 | } 204 | 205 | _onPlayerControlsHiddenDidChange(event) { 206 | console.log( 207 | '[EZPlayer] onPlayerControlsHiddenDidChange ' + 208 | JSON.stringify(event.nativeEvent), 209 | ); 210 | if (typeof this.props.onPlayerControlsHiddenDidChange === 'function') { 211 | this.props.onPlayerControlsHiddenDidChange(...arguments); 212 | } 213 | } 214 | 215 | _onPlayerDisplayModeDidChange(event) { 216 | console.log( 217 | '[EZPlayer] onPlayerDisplayModeDidChange ' + 218 | JSON.stringify(event.nativeEvent), 219 | ); 220 | this.player.displayMode = event.nativeEvent.displayMode; 221 | if (typeof this.props.onPlayerDisplayModeDidChange === 'function') { 222 | this.props.onPlayerDisplayModeDidChange(...arguments); 223 | } 224 | } 225 | 226 | _onPlayerDisplayModeChangedWillAppear(event) { 227 | console.log( 228 | '[EZPlayer] onPlayerDisplayModeChangedWillAppear ' + 229 | JSON.stringify(event.nativeEvent), 230 | ); 231 | if (typeof this.props.onPlayerDisplayModeChangedWillAppear === 'function') { 232 | this.props.onPlayerDisplayModeChangedWillAppear(...arguments); 233 | } 234 | } 235 | 236 | _onPlayerDisplayModeChangedDidAppear(event) { 237 | console.log( 238 | '[EZPlayer] onPlayerDisplayModeChangedDidAppear ' + 239 | JSON.stringify(event.nativeEvent), 240 | ); 241 | if (typeof this.props.onPlayerDisplayModeChangedDidAppear === 'function') { 242 | this.props.onPlayerDisplayModeChangedDidAppear(...arguments); 243 | } 244 | } 245 | 246 | _onPlayerTapGestureRecognizer(event) { 247 | console.log( 248 | '[EZPlayer] onPlayerTapGestureRecognizer ' + 249 | JSON.stringify(event.nativeEvent), 250 | ); 251 | if (typeof this.props.onPlayerTapGestureRecognizer === 'function') { 252 | this.props.onPlayerTapGestureRecognizer(...arguments); 253 | } 254 | } 255 | 256 | _onPlayerDidPersistContentKey(event) { 257 | console.log( 258 | '[EZPlayer] onPlayerDidPersistContentKey ' + 259 | JSON.stringify(event.nativeEvent), 260 | ); 261 | if (typeof this.props.onPlayerDidPersistContentKey === 'function') { 262 | this.props.onPlayerDidPersistContentKey(...arguments); 263 | } 264 | } 265 | 266 | _onPlayerPIPControllerWillStart(event) { 267 | console.log( 268 | '[EZPlayer] onPlayerPIPControllerWillStart ' + 269 | JSON.stringify(event.nativeEvent), 270 | ); 271 | if (typeof this.props.onPlayerPIPControllerWillStart === 'function') { 272 | this.props.onPlayerPIPControllerWillStart(...arguments); 273 | } 274 | } 275 | 276 | _onPlayerPIPControllerDidStart(event) { 277 | console.log( 278 | '[EZPlayer] onPlayerPIPControllerDidStart ' + 279 | JSON.stringify(event.nativeEvent), 280 | ); 281 | if (typeof this.props.onPlayerPIPControllerDidStart === 'function') { 282 | this.props.onPlayerPIPControllerDidStart(...arguments); 283 | } 284 | } 285 | 286 | _onPlayerPIPFailedToStart(event) { 287 | console.log( 288 | '[EZPlayer] onPlayerPIPFailedToStart ' + 289 | JSON.stringify(event.nativeEvent), 290 | ); 291 | if (typeof this.props.onPlayerPIPFailedToStart === 'function') { 292 | this.props.onPlayerPIPFailedToStart(...arguments); 293 | } 294 | } 295 | 296 | _onPlayerPIPControllerWillEnd(event) { 297 | console.log( 298 | '[EZPlayer] onPlayerPIPControllerWillEnd ' + 299 | JSON.stringify(event.nativeEvent), 300 | ); 301 | if (typeof this.props.onPlayerPIPControllerWillEnd === 'function') { 302 | this.props.onPlayerPIPControllerWillEnd(...arguments); 303 | } 304 | } 305 | 306 | _onPlayerPIPControllerDidEnd(event) { 307 | console.log( 308 | '[EZPlayer] onPlayerPIPControllerDidEnd ' + 309 | JSON.stringify(event.nativeEvent), 310 | ); 311 | if (typeof this.props.onPlayerPIPControllerDidEnd === 'function') { 312 | this.props.onPlayerPIPControllerDidEnd(...arguments); 313 | } 314 | } 315 | 316 | _onPlayerPIPRestoreUserInterfaceForStop(event) { 317 | console.log( 318 | '[EZPlayer] onPlayerPIPRestoreUserInterfaceForStop ' + 319 | JSON.stringify(event.nativeEvent), 320 | ); 321 | if ( 322 | typeof this.props.onPlayerPIPRestoreUserInterfaceForStop === 'function' 323 | ) { 324 | this.props.onPlayerPIPRestoreUserInterfaceForStop(...arguments); 325 | } 326 | } 327 | 328 | /** 329 | | ------------------------------------------------------- 330 | | 播放器行为 331 | | ------------------------------------------------------- 332 | */ 333 | play() { 334 | EZRNPlayerViewManager.play( 335 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 336 | ); 337 | } 338 | 339 | pause() { 340 | EZRNPlayerViewManager.pause( 341 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 342 | ); 343 | } 344 | 345 | stop() { 346 | EZRNPlayerViewManager.stop( 347 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 348 | ); 349 | } 350 | 351 | seek(time, callback) { 352 | if (isNaN(time)) { 353 | return; 354 | } 355 | EZRNPlayerViewManager.seek( 356 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 357 | time, 358 | (finished) => callback && callback(finished), 359 | ); 360 | } 361 | 362 | replaceToPlay(source) { 363 | EZRNPlayerViewManager.replaceToPlay( 364 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 365 | source, 366 | ); 367 | } 368 | 369 | rate(rate) { 370 | EZRNPlayerViewManager.rate( 371 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 372 | rate, 373 | ); 374 | } 375 | 376 | autoPlay(autoPlay) { 377 | EZRNPlayerViewManager.autoPlay( 378 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 379 | autoPlay, 380 | ); 381 | } 382 | 383 | videoGravity(videoGravity) { 384 | EZRNPlayerViewManager.videoGravity( 385 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 386 | videoGravity, 387 | ); 388 | } 389 | 390 | toEmbedded(animated = true, callback) { 391 | EZRNPlayerViewManager.toEmbedded( 392 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 393 | animated, 394 | (finished) => callback && callback(finished), 395 | ); 396 | } 397 | 398 | toFloat(animated = true, callback) { 399 | EZRNPlayerViewManager.toFloat( 400 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 401 | animated, 402 | (finished) => callback && callback(finished), 403 | ); 404 | } 405 | 406 | //orientation : landscapeLeft , landscapeRight 407 | toFull(orientation = 'landscapeLeft', animated = true, callback) { 408 | EZRNPlayerViewManager.toFull( 409 | findNodeHandle(this._getEZRNPlayerViewNativeHandle()), 410 | orientation, 411 | animated, 412 | (finished) => callback && callback(finished), 413 | ); 414 | } 415 | 416 | //fullScreenMode:portrait , landscape 417 | fullScreenMode(fullScreenMode) { 418 | EZRNPlayerViewManager.fullScreenMode( 419 | this._getEZRNPlayerViewNativeHandle(), 420 | fullScreenMode, 421 | ); 422 | } 423 | 424 | //fullScreenMode:portrait , landscape 425 | floatMode(floatMode) { 426 | EZRNPlayerViewManager.floatMode( 427 | this._getEZRNPlayerViewNativeHandle(), 428 | floatMode, 429 | ); 430 | } 431 | 432 | /** 433 | | ------------------------------------------------------- 434 | | Priavate 435 | | ------------------------------------------------------- 436 | */ 437 | _getEZRNPlayerViewNativeHandle() { 438 | return findNodeHandle(this.player.ref); 439 | } 440 | 441 | render() { 442 | return ( 443 | (this.player.ref = nativePlayer)} 446 | style={this.props.style} 447 | onPlayerHeartbeat={this.events.onPlayerHeartbeat} 448 | onPlayerPlaybackTimeDidChange={ 449 | this.events.onPlayerPlaybackTimeDidChange 450 | } 451 | onPlayerStatusDidChange={this.events.onPlayerStatusDidChange} 452 | onPlayerPlaybackDidFinish={this.events.onPlayerPlaybackDidFinish} 453 | onPlayerLoadingDidChange={this.events.onPlayerLoadingDidChange} 454 | onPlayerControlsHiddenDidChange={ 455 | this.events.onPlayerControlsHiddenDidChange 456 | } 457 | onPlayerDisplayModeDidChange={this.events.onPlayerDisplayModeDidChange} 458 | onPlayerDisplayModeChangedWillAppear={ 459 | this.events.onPlayerDisplayModeChangedWillAppear 460 | } 461 | onPlayerDisplayModeChangedDidAppear={ 462 | this.events.onPlayerDisplayModeChangedDidAppear 463 | } 464 | onPlayerTapGestureRecognizer={this.events.onPlayerTapGestureRecognizer} 465 | onPlayerDidPersistContentKey={this.events.onPlayerDidPersistContentKey} 466 | onPlayerPIPControllerWillStart={ 467 | this.events.onPlayerPIPControllerWillStart 468 | } 469 | onPlayerPIPControllerDidStart={ 470 | this.events.onPlayerPIPControllerDidStart 471 | } 472 | onPlayerPIPFailedToStart={this.events.onPlayerPIPFailedToStart} 473 | onPlayerPIPControllerWillEnd={this.events.onPlayerPIPControllerWillEnd} 474 | onPlayerPIPControllerDidEnd={this.events.onPlayerPIPControllerDidEnd} 475 | onPlayerPIPRestoreUserInterfaceForStop={ 476 | this.events.onPlayerPIPRestoreUserInterfaceForStop 477 | } 478 | /> 479 | ); 480 | } 481 | } 482 | 483 | module.exports = EZPlayer; 484 | --------------------------------------------------------------------------------