hyzp_ybqx-Commit001:代码刚转换好,编译通过
@@ -0,0 +1,37 @@
|
||||
.idea/
|
||||
.vagrant/
|
||||
.sconsign.dblite
|
||||
.svn/
|
||||
|
||||
.DS_Store
|
||||
*.swp
|
||||
profile
|
||||
|
||||
DerivedData/
|
||||
build/
|
||||
GeneratedPluginRegistrant.h
|
||||
GeneratedPluginRegistrant.m
|
||||
|
||||
.generated/
|
||||
|
||||
*.pbxuser
|
||||
*.mode1v3
|
||||
*.mode2v3
|
||||
*.perspectivev3
|
||||
|
||||
!default.pbxuser
|
||||
!default.mode1v3
|
||||
!default.mode2v3
|
||||
!default.perspectivev3
|
||||
|
||||
xcuserdata
|
||||
|
||||
*.moved-aside
|
||||
|
||||
*.pyc
|
||||
*sync/
|
||||
Icon?
|
||||
.tags*
|
||||
|
||||
/Flutter/Generated.xcconfig
|
||||
/Flutter/flutter_export_environment.sh
|
||||
@@ -0,0 +1,33 @@
|
||||
//
|
||||
// SuperPlayerView.h
|
||||
//
|
||||
// Created by Lijy91 on 2020/9/4.
|
||||
//
|
||||
|
||||
#import <Flutter/Flutter.h>
|
||||
#import "SuperPlayer.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
// FLTSuperPlayerViewController
|
||||
@interface FLTSuperPlayerViewController : NSObject <FlutterPlatformView, FlutterStreamHandler, SuperPlayerDelegate>
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
|
||||
|
||||
- (UIView*)view;
|
||||
|
||||
@end
|
||||
|
||||
// FLTSuperPlayerViewFactory
|
||||
@interface FLTSuperPlayerViewFactory : NSObject
|
||||
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger;
|
||||
@end
|
||||
|
||||
// FLTSuperPlayerView
|
||||
@interface FLTSuperPlayerView : SuperPlayerView
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,322 @@
|
||||
//
|
||||
// FLTSuperPlayerView.m
|
||||
//
|
||||
// Created by Lijy91 on 2020/9/4.
|
||||
//
|
||||
|
||||
#import "FLTSuperPlayerView.h"
|
||||
|
||||
// FLTSuperPlayerViewController
|
||||
@implementation FLTSuperPlayerViewController {
|
||||
UIView* _containerView;
|
||||
FLTSuperPlayerView* _superPlayerView;
|
||||
int64_t _viewId;
|
||||
FlutterMethodChannel* _channel;
|
||||
FlutterEventChannel* _eventChannel;
|
||||
FlutterEventSink _eventSink;
|
||||
}
|
||||
|
||||
- (instancetype)initWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args
|
||||
binaryMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
if (self = [super init]) {
|
||||
_viewId = viewId;
|
||||
|
||||
NSString* channelName = [NSString stringWithFormat:@"leanflutter.org/superplayer_view/channel_%lld", viewId];
|
||||
_channel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:messenger];
|
||||
|
||||
NSString* eventChannelName = [NSString stringWithFormat:@"leanflutter.org/superplayer_view/event_channel_%lld", viewId];
|
||||
_eventChannel = [FlutterEventChannel eventChannelWithName:eventChannelName
|
||||
binaryMessenger:messenger];
|
||||
[_eventChannel setStreamHandler:self];
|
||||
|
||||
__weak __typeof__(self) weakSelf = self;
|
||||
[_channel setMethodCallHandler:^(FlutterMethodCall* call, FlutterResult result) {
|
||||
[weakSelf onMethodCall:call result:result];
|
||||
}];
|
||||
|
||||
_containerView = [[UIView alloc] initWithFrame:frame];
|
||||
|
||||
_superPlayerView = [[FLTSuperPlayerView alloc] init];
|
||||
_superPlayerView.fatherView = _containerView;
|
||||
_superPlayerView.delegate = self;
|
||||
|
||||
[self setControlViewType:args[@"controlViewType"]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIView*)view {
|
||||
return _containerView;
|
||||
}
|
||||
|
||||
- (FlutterError*)onListenWithArguments:(id)arguments eventSink:(FlutterEventSink)eventSink {
|
||||
_eventSink = eventSink;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (FlutterError*)onCancelWithArguments:(id)arguments {
|
||||
_eventSink = nil;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (void)setControlViewType:(NSString *)controlViewType
|
||||
{
|
||||
if ([controlViewType isEqualToString:@"without"]) {
|
||||
_superPlayerView.controlView = [[SPWithoutControlView alloc] initWithFrame:CGRectZero];
|
||||
} else {
|
||||
_superPlayerView.controlView = [[SPDefaultControlView alloc] initWithFrame:CGRectZero];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
if ([[call method] isEqualToString:@"getPlayMode"]) {
|
||||
[self getPlayMode:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"getPlayState"]) {
|
||||
[self getPlayState:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"getPlayRate"]) {
|
||||
[self getPlayRate:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"setPlayRate"]) {
|
||||
[self setPlayRate:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"resetPlayer"]) {
|
||||
[self resetPlayer:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"requestPlayMode"]) {
|
||||
[self requestPlayMode:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"playWithModel"]) {
|
||||
[self playWithModel:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"pause"]) {
|
||||
[self pause:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"resume"]) {
|
||||
[self resume:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"release"]) {
|
||||
[self release:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"seekTo"]) {
|
||||
[self seekTo:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"setLoop"]) {
|
||||
[self setLoop:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"uiHideDanmu"]) {
|
||||
[self uiHideDanmu:call result: result];
|
||||
} else if ([[call method] isEqualToString:@"uiHideReplay"]) {
|
||||
[self uiHideReplay:call result: result];
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)getPlayMode:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView setPlayerConfig:nil];
|
||||
}
|
||||
|
||||
- (void)getPlayState:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
result([NSNumber numberWithInt:_superPlayerView.state]);
|
||||
}
|
||||
|
||||
- (void)getPlayRate:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
CGFloat playRate = [[_superPlayerView playerConfig] playRate];
|
||||
result([NSNumber numberWithDouble:playRate]);
|
||||
}
|
||||
|
||||
- (void)setPlayRate:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
NSNumber *playRate = call.arguments[@"playRate"];
|
||||
[_superPlayerView setPlayRate:playRate.floatValue];
|
||||
}
|
||||
|
||||
- (void)resetPlayer:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView resetPlayer];
|
||||
}
|
||||
|
||||
- (void)requestPlayMode:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
|
||||
- (void)playWithModel:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
SuperPlayerModel *model = [[SuperPlayerModel alloc] init];
|
||||
|
||||
NSNumber *appId = call.arguments[@"appId"];
|
||||
NSString *url = call.arguments[@"url"];
|
||||
if (appId)
|
||||
[model setAppId: appId.longValue];
|
||||
if (url)
|
||||
[model setVideoURL:url];
|
||||
|
||||
NSDictionary *videoIdJson = call.arguments[@"videoId"];
|
||||
if (videoIdJson) {
|
||||
NSString *fileId = videoIdJson[@"fileId"];
|
||||
|
||||
SuperPlayerVideoId *videoId = [[SuperPlayerVideoId alloc] init];
|
||||
if (fileId)
|
||||
[videoId setFileId:fileId];
|
||||
|
||||
[model setVideoId:videoId];
|
||||
}
|
||||
|
||||
[_superPlayerView playWithModel:model];
|
||||
}
|
||||
|
||||
- (void)pause:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView pause];
|
||||
}
|
||||
|
||||
- (void)resume:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView resume];
|
||||
}
|
||||
|
||||
- (void)release:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
// skip
|
||||
}
|
||||
|
||||
- (void)seekTo:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
NSNumber *time = call.arguments[@"time"];
|
||||
[_superPlayerView seekToTime:time.intValue];
|
||||
}
|
||||
|
||||
- (void)setLoop:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
NSNumber *isLoop = call.arguments[@"isLoop"];
|
||||
[_superPlayerView setLoop:isLoop.boolValue];
|
||||
}
|
||||
|
||||
- (void) uiHideDanmu:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView uiHideDanmu];
|
||||
}
|
||||
|
||||
- (void) uiHideReplay:(FlutterMethodCall*)call
|
||||
result:(FlutterResult)result
|
||||
{
|
||||
[_superPlayerView uiHideReplay];
|
||||
}
|
||||
|
||||
/// 返回事件
|
||||
- (void)superPlayerBackAction:(SuperPlayerView *)player {
|
||||
NSDictionary<NSString *, id> *eventData = @{
|
||||
@"listener": @"SuperPlayerListener",
|
||||
@"method": @"onClickSmallReturnBtn",
|
||||
};
|
||||
self->_eventSink(eventData);
|
||||
}
|
||||
|
||||
/// 全屏改变通知
|
||||
- (void)superPlayerFullScreenChanged:(SuperPlayerView *)player {
|
||||
NSDictionary<NSString *, id> *eventData = @{
|
||||
@"listener": @"SuperPlayerListener",
|
||||
@"method": @"onFullScreenChange",
|
||||
@"data": @{
|
||||
@"isFullScreen": [NSNumber numberWithBool:[player isFullScreen]],
|
||||
},
|
||||
};
|
||||
self->_eventSink(eventData);
|
||||
}
|
||||
|
||||
/// 播放开始通知
|
||||
- (void)superPlayerDidStart:(SuperPlayerView *)player {
|
||||
|
||||
}
|
||||
/// 播放结束通知
|
||||
- (void)superPlayerDidEnd:(SuperPlayerView *)player {
|
||||
|
||||
}
|
||||
/// 播放错误通知
|
||||
- (void)superPlayerError:(SuperPlayerView *)player errCode:(int)code errMessage:(NSString *)why {
|
||||
|
||||
}
|
||||
|
||||
/// 播放状态发生变化
|
||||
- (void)onPlayStateChange:(int) playState {
|
||||
NSDictionary<NSString *, id> *eventData = @{
|
||||
@"listener": @"SuperPlayerListener",
|
||||
@"method": @"onPlayStateChange",
|
||||
@"data": @{
|
||||
@"playState": [NSNumber numberWithInt:playState],
|
||||
},
|
||||
};
|
||||
self->_eventSink(eventData);
|
||||
}
|
||||
|
||||
/// 播放进度发生变化
|
||||
- (void)onPlayProgressChange:(int) current duration:(int) duration {
|
||||
NSDictionary<NSString *, id> *eventData = @{
|
||||
@"listener": @"SuperPlayerListener",
|
||||
@"method": @"onPlayProgressChange",
|
||||
@"data": @{
|
||||
@"current": [NSNumber numberWithInt:current],
|
||||
@"duration": [NSNumber numberWithInt:duration],
|
||||
},
|
||||
};
|
||||
self->_eventSink(eventData);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
// FLTSuperPlayerViewFactory
|
||||
@implementation FLTSuperPlayerViewFactory{
|
||||
NSObject<FlutterBinaryMessenger>* _messenger;
|
||||
}
|
||||
|
||||
- (instancetype)initWithMessenger:(NSObject<FlutterBinaryMessenger>*)messenger {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_messenger = messenger;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSObject<FlutterMessageCodec>*)createArgsCodec {
|
||||
return [FlutterStandardMessageCodec sharedInstance];
|
||||
}
|
||||
|
||||
- (NSObject<FlutterPlatformView>*)createWithFrame:(CGRect)frame
|
||||
viewIdentifier:(int64_t)viewId
|
||||
arguments:(id _Nullable)args {
|
||||
FLTSuperPlayerViewController* superPlayerViewController = [[FLTSuperPlayerViewController alloc] initWithFrame:frame
|
||||
viewIdentifier:viewId
|
||||
arguments:args
|
||||
binaryMessenger:_messenger];
|
||||
return superPlayerViewController;
|
||||
}
|
||||
@end
|
||||
|
||||
// FLTSuperPlayerView
|
||||
@implementation FLTSuperPlayerView
|
||||
- (instancetype)initWithFrame:(CGRect)frame {
|
||||
self = [super initWithFrame:frame];
|
||||
|
||||
if (self) {
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)layoutSubviews {
|
||||
[super layoutSubviews];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,5 @@
|
||||
#import <Flutter/Flutter.h>
|
||||
#import "FLTSuperPlayerView.h"
|
||||
|
||||
@interface FlutterSuperplayerPlugin : NSObject<FlutterPlugin>
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
#import "FlutterSuperplayerPlugin.h"
|
||||
|
||||
@implementation FlutterSuperplayerPlugin
|
||||
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
|
||||
FlutterMethodChannel* channel = [FlutterMethodChannel
|
||||
methodChannelWithName:@"flutter_superplayer"
|
||||
binaryMessenger:[registrar messenger]];
|
||||
FlutterSuperplayerPlugin* instance = [[FlutterSuperplayerPlugin alloc] init];
|
||||
[registrar addMethodCallDelegate:instance channel:channel];
|
||||
|
||||
FLTSuperPlayerViewFactory* platformViewFactory = [[FLTSuperPlayerViewFactory alloc] initWithMessenger:registrar.messenger];
|
||||
[registrar registerViewFactory:platformViewFactory withId:@"leanflutter.org/superplayer_view"];
|
||||
}
|
||||
|
||||
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
|
||||
if ([@"getSDKVersion" isEqualToString:call.method]) {
|
||||
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
|
||||
} else {
|
||||
result(FlutterMethodNotImplemented);
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// NSString+URL.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by xcoderliu on 12/10/20.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface NSString (URL)
|
||||
/// 获取 URL GET 参数
|
||||
/// @param parameter key
|
||||
/// @param originUrl url
|
||||
+ (NSString *)getParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl;
|
||||
|
||||
/// 删除 URL GET 参数
|
||||
/// @param parameter key
|
||||
/// @param originUrl url
|
||||
+ (NSString *)deleteParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl;
|
||||
|
||||
|
||||
/// 追加 URL GET 参数
|
||||
/// @param queryString (@"key=value")
|
||||
/// @param originUrl url
|
||||
+ (NSString *)appendParameter:(NSString *)queryString WithOriginUrl:(NSString *)originUrl;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// NSString+URL.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by xcoderliu on 12/10/20.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "NSString+URL.h"
|
||||
|
||||
@implementation NSString (URL)
|
||||
+ (NSString *)getParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl {
|
||||
NSError *error;
|
||||
if (originUrl.length == 0) {
|
||||
return @"";
|
||||
}
|
||||
NSString *regTags = [[NSString alloc] initWithFormat:@"(^|&|\\?)+%@=+([^&]*)(&|$)",parameter];
|
||||
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regTags options:NSRegularExpressionCaseInsensitive error:&error];
|
||||
NSArray *matches = [regex matchesInString:originUrl options:0 range:NSMakeRange(0, [originUrl length])];
|
||||
for (NSTextCheckingResult *match in matches) {
|
||||
NSString *tagValue = [originUrl substringWithRange:[match rangeAtIndex:2]];
|
||||
return tagValue;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
+ (NSString *)deleteParameter:(NSString *)parameter WithOriginUrl:(NSString *)originUrl {
|
||||
NSString *finalStr = [NSString string];
|
||||
NSMutableString * mutStr = [NSMutableString stringWithString:originUrl];
|
||||
NSArray *strArray = [mutStr componentsSeparatedByString:parameter];
|
||||
NSMutableString *firstStr = [strArray objectAtIndex:0];
|
||||
NSMutableString *lastStr = [strArray lastObject];
|
||||
NSRange characterRange = [lastStr rangeOfString:@"&"];
|
||||
|
||||
if (characterRange.location !=NSNotFound) {
|
||||
NSArray *lastArray = [lastStr componentsSeparatedByString:@"&"];
|
||||
NSMutableArray *mutArray = [NSMutableArray arrayWithArray:lastArray];
|
||||
[mutArray removeObjectAtIndex:0];
|
||||
NSString *modifiedStr = [mutArray componentsJoinedByString:@"&"];
|
||||
finalStr = [[strArray objectAtIndex:0]stringByAppendingString:modifiedStr];
|
||||
} else {
|
||||
finalStr = [firstStr substringToIndex:[firstStr length] -1];
|
||||
}
|
||||
return finalStr;
|
||||
}
|
||||
|
||||
+ (NSString *)appendParameter:(NSString *)queryString WithOriginUrl:(NSString *)originUrl {
|
||||
if (![queryString length]) {
|
||||
return originUrl;
|
||||
}
|
||||
return [NSString stringWithFormat:@"%@%@%@", originUrl,
|
||||
[originUrl rangeOfString:@"?"].length > 0 ? @"&" : @"?", queryString];
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,6 @@
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UINavigationController (SuperPlayerRotation)<UIGestureRecognizerDelegate>
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,34 @@
|
||||
#import "UINavigationController+SuperPlayerRotation.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
@implementation UINavigationController (SuperPlayerRotation)
|
||||
|
||||
/**
|
||||
* 如果window的根视图是UINavigationController,则会先调用这个Category,然后调用UIViewController+SuperPlayerRotation
|
||||
* 只需要在支持除竖屏以外方向的页面重新下边三个方法
|
||||
*/
|
||||
|
||||
// 是否支持自动转屏
|
||||
- (BOOL)shouldAutorotate {
|
||||
return [self.topViewController shouldAutorotate];
|
||||
}
|
||||
|
||||
// 支持哪些屏幕方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return [self.topViewController supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
// 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return [self.topViewController preferredInterfaceOrientationForPresentation];
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarHidden {
|
||||
return self.topViewController;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,93 @@
|
||||
//
|
||||
// UIView+MM.h
|
||||
/*
|
||||
杜蒙 iOS开发
|
||||
annidy
|
||||
*/
|
||||
|
||||
#define m_weakify(object) autoreleasepool {} __weak typeof(object) weak##object = object
|
||||
#define m_strongify(object) autoreleasepool {} __strong typeof(weak##object) object = weak##object
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
@class MMLayout;
|
||||
@interface UIView (Layout)
|
||||
@property (strong , nonatomic , readonly) MMLayout *mm_selfLayout;
|
||||
- (void)setMm_x:(CGFloat)mm_x; ///<< set frame.x
|
||||
- (CGFloat)mm_x; ///<< get frame.x
|
||||
- (void)setMm_y:(CGFloat)mm_y; ///<< set frame.y
|
||||
- (CGFloat)mm_y; ///<< get frame.y
|
||||
- (void)setMm_w:(CGFloat)mm_w; ///<< set frame.bounds.size.width
|
||||
- (CGFloat)mm_w; ///<< get frame.bounds.size.width
|
||||
- (void)setMm_h:(CGFloat)mm_h; ///<< set frame.bounds.size.height
|
||||
- (CGFloat)mm_h; ///<< get frame.bounds.size.height
|
||||
- (void)setMm_center:(CGPoint )mm_center; ///<< set frame.origin
|
||||
- (CGPoint)mm_center; ///<< get frame origin
|
||||
- (CGFloat)mm_centerX; ///<< get self.center.x
|
||||
- (CGFloat)mm_centerY; ///<< get self.center.y
|
||||
- (CGFloat)mm_maxY; ///<< get CGRectGetMaxY
|
||||
- (CGFloat)mm_minY; ///<< get CGRectGetMinY
|
||||
- (CGFloat)mm_maxX; ///<< get CGRectGetMaxX
|
||||
- (CGFloat)mm_minX; ///<< get CGRectGetMinX
|
||||
- (CGFloat)mm_halfW; ///<< get self.width / 2
|
||||
- (CGFloat)mm_halfH; ///<< get self.height / 2
|
||||
- (CGFloat)mm_halfX; ///<< get self.x / 2
|
||||
- (CGFloat)mm_halfY; ///<< get self.y / 2
|
||||
- (CGFloat)mm_halfCenterX; ///<< get self.centerX / 2
|
||||
- (CGFloat)mm_halfCenterY; ///<< get self.centerY / 2
|
||||
- (void)setMm_size:(CGSize)mm_size;
|
||||
- (CGSize)mm_size; ///<< get self.bounds.size
|
||||
|
||||
// iPhoneX adapt
|
||||
|
||||
@property (readonly) CGFloat mm_safeAreaBottomGap;
|
||||
@property (readonly) CGFloat mm_safeAreaTopGap;
|
||||
@property (readonly) CGFloat mm_safeAreaLeftGap;
|
||||
@property (readonly) CGFloat mm_safeAreaRightGap;
|
||||
|
||||
/*
|
||||
示例链接编程
|
||||
self.m_width(100).m_height(100).m_left(10).m_top(10)
|
||||
*/
|
||||
- (UIView * (^)(CGFloat top))m_top; ///< set frame y
|
||||
- (UIView * (^)(CGFloat right))m_flexToTop; ///< set frame y by change height
|
||||
- (UIView * (^)(CGFloat bottom))m_bottom; ///< set frame y
|
||||
- (UIView * (^)(CGFloat right))m_flexToBottom; ///< set frame y by change height
|
||||
- (UIView * (^)(CGFloat left))m_left; ///< set frame x
|
||||
- (UIView * (^)(CGFloat right))m_flexToLeft; ///< set frame right by chang width
|
||||
- (UIView * (^)(CGFloat right))m_right; ///< set frame x
|
||||
- (UIView * (^)(CGFloat right))m_flexToRight; ///< set frame right by chang width
|
||||
- (UIView * (^)(CGFloat width))m_width; ///< set frame width
|
||||
- (UIView * (^)(CGFloat height))m_height; ///< set frame height
|
||||
- (UIView * (^)(CGSize size))m_size; ///< set frame size
|
||||
- (UIView * (^)(CGPoint center))m__center; ///< set frame center point
|
||||
- (UIView * (^)(void))m_center; ///< set frame center 前提是有w h 调用次方法居中父类
|
||||
- (UIView * (^)(void))m_centerY; ///< set frame Ycenter 前提是有h调用次方法居中父类
|
||||
- (UIView * (^)(void))m_centerX; ///< set frame Xcenter 前提是有w调用次方法居中父类
|
||||
|
||||
/*
|
||||
相对父View
|
||||
*/
|
||||
-(UIView *(^)(void))m_fill; ///< 填充
|
||||
|
||||
|
||||
- (UIView * (^)(UIView *obj))m_equalToFrame; /// equalTo frame
|
||||
- (UIView * (^)(UIView *obj))m_equalToTop; /// equalTo top
|
||||
- (UIView * (^)(UIView *obj))m_equalToBottom; /// equalTo Bottom
|
||||
- (UIView * (^)(UIView *obj))m_equalToLeft; /// equalTo left
|
||||
- (UIView * (^)(UIView *obj))m_equalToRight; /// equalTo right
|
||||
- (UIView * (^)(UIView *obj))m_equalToWidth; /// equalTo width
|
||||
- (UIView * (^)(UIView *obj))m_equalToHeight; /// equalTo height
|
||||
- (UIView * (^)(UIView *obj))m_equalToSize; /// equalTo size
|
||||
- (UIView * (^)(UIView *obj))m_equalToCenter; /// equalTo center
|
||||
|
||||
- (UIView * (^)(void))m_sizeToFit; /// call sizeToFit
|
||||
|
||||
- (NSData *)mm_createPDF;/// create self PDF
|
||||
|
||||
- (UIViewController *)viewController; //self Responder UIViewControler
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,525 @@
|
||||
|
||||
|
||||
#import "UIView+MMLayout.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#pragma mark - MMLayout
|
||||
@interface MMLayout : NSObject
|
||||
/*
|
||||
@LayoutView 传入进去 View
|
||||
*/
|
||||
-(instancetype)initWithLayoutView:(UIView *)LayoutView;
|
||||
@property (assign , nonatomic) CGFloat top; ///<< frame y
|
||||
@property (assign , nonatomic) CGFloat bottom; ///<< y = super.h - LayoutView.h - bottom
|
||||
@property (assign , nonatomic) CGFloat left; ///<< frame x
|
||||
@property (assign , nonatomic) CGFloat right; ///<< x = super.w - LayoutView.h - right
|
||||
@property (assign , nonatomic) CGFloat width; ///<< frame w
|
||||
@property (assign , nonatomic) CGFloat height; ///<< frame height
|
||||
@property (assign , nonatomic) CGSize size; ///<< frame bounds size width height
|
||||
@property (assign , nonatomic) CGPoint point; ///<< frame point
|
||||
- (void)center; ///<<调用此方法前必须先设置自己的宽高 (默认是居中父控件)
|
||||
- (void)centerX; ///<<调用此方法前必须先设置自己的宽 (默认是居中父控件)
|
||||
- (void)centerY; ///<<调用此方法前必须先设置自己的高 (默认是居中父控件)
|
||||
@property (weak , nonatomic) UIView *layoutView;
|
||||
@end
|
||||
@implementation MMLayout
|
||||
-(instancetype)initWithLayoutView:(UIView *)LayoutView{
|
||||
if (self=[super init]) {
|
||||
self.layoutView = LayoutView;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
-(void)setLeft:(CGFloat)left{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin.x = left;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
- (CGFloat)left {
|
||||
return self.layoutView.frame.origin.x;
|
||||
}
|
||||
-(void)setTop:(CGFloat)top{
|
||||
_top = top;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin.y = top;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setRight:(CGFloat)right{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_w - self.layoutView.mm_w - right;
|
||||
}
|
||||
- (CGFloat)right {
|
||||
UIView *superview = self.layoutView.superview;
|
||||
return superview.mm_w - self.layoutView.mm_x - self.layoutView.mm_w;
|
||||
}
|
||||
|
||||
-(void)setBottom:(CGFloat)bottom{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_y = superview.mm_h - self.layoutView.mm_h - bottom;
|
||||
}
|
||||
|
||||
- (CGFloat)bottom {
|
||||
UIView *superview = self.layoutView.superview;
|
||||
return superview.mm_h - self.layoutView.mm_maxY;
|
||||
}
|
||||
|
||||
-(void)setHeight:(CGFloat)height{
|
||||
_height = height;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size.height = height;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setWidth:(CGFloat)width{
|
||||
_width = width;
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size.width = width;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)setPoint:(CGPoint)point{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin = point;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(CGPoint)point{
|
||||
return CGPointMake(self.layoutView.mm_x, self.layoutView.mm_w);
|
||||
}
|
||||
-(void)setSize:(CGSize )size{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.size = size;
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(CGSize)size{
|
||||
return self.layoutView.mm_size;
|
||||
}
|
||||
|
||||
-(void)setCenter:(CGPoint)center{
|
||||
CGRect frame = self.layoutView.frame;
|
||||
frame.origin = CGPointMake(center.x-frame.size.width/2, center.y-frame.size.height/2);
|
||||
self.layoutView.frame = frame;
|
||||
}
|
||||
-(void)center{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_halfW - self.layoutView.mm_halfW;
|
||||
self.layoutView.mm_y = superview.mm_halfH - self.layoutView.mm_halfH;
|
||||
}
|
||||
-(void)centerY{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_y = superview.mm_halfH - self.layoutView.mm_halfH;
|
||||
}
|
||||
-(void)centerX{
|
||||
UIView *superview = self.layoutView.superview;
|
||||
self.layoutView.mm_x = superview.mm_halfW - self.layoutView.mm_halfW;
|
||||
}
|
||||
@end
|
||||
const void *_layoutKey;
|
||||
@implementation UIView (Layout)
|
||||
#pragma mark - frame
|
||||
- (void)setMm_x:(CGFloat)mm_x{
|
||||
[self mm_selfLayout].left = mm_x;
|
||||
}
|
||||
- (CGFloat)mm_x{
|
||||
return self.frame.origin.x;
|
||||
}
|
||||
- (void)setMm_y:(CGFloat)mm_y{
|
||||
[self mm_selfLayout].top = mm_y;
|
||||
}
|
||||
- (CGFloat)mm_y{
|
||||
return self.frame.origin.y;
|
||||
}
|
||||
- (void)setMm_w:(CGFloat)mm_w{
|
||||
[self mm_selfLayout].width = mm_w;
|
||||
}
|
||||
- (CGFloat)mm_w{
|
||||
return self.frame.size.width;
|
||||
}
|
||||
- (void)setMm_h:(CGFloat)mm_h{
|
||||
[self mm_selfLayout].height = mm_h;
|
||||
}
|
||||
- (CGFloat)mm_h{
|
||||
return self.frame.size.height;
|
||||
}
|
||||
-(void)setMm_center:(CGPoint)mm_center{
|
||||
[self mm_selfLayout].point = mm_center;
|
||||
|
||||
}
|
||||
-(CGPoint)mm_center{
|
||||
return self.frame.origin;
|
||||
}
|
||||
-(CGFloat)mm_centerX{
|
||||
return self.center.x;
|
||||
}
|
||||
-(CGFloat)mm_centerY{
|
||||
return self.center.y;
|
||||
}
|
||||
- (CGFloat)mm_maxY{
|
||||
return CGRectGetMaxY(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_minY{
|
||||
return CGRectGetMinY(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_maxX{
|
||||
return CGRectGetMaxX(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_minX{
|
||||
return CGRectGetMinX(self.frame);
|
||||
}
|
||||
- (CGFloat)mm_halfW{
|
||||
return self.mm_w / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfH{
|
||||
return self.mm_h / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfX{
|
||||
return self.mm_x / 2;
|
||||
}
|
||||
- (CGFloat)mm_halfY{
|
||||
return self.mm_y / 2;
|
||||
}
|
||||
-(CGFloat)mm_halfCenterX{
|
||||
return self.mm_centerX / 2;
|
||||
}
|
||||
-(CGFloat)mm_halfCenterY{
|
||||
return self.mm_centerY / 2;
|
||||
}
|
||||
-(void)setMm_size:(CGSize)mm_size{
|
||||
[self mm_selfLayout].size = mm_size;
|
||||
}
|
||||
-(CGSize)mm_size{
|
||||
return self.bounds.size;
|
||||
}
|
||||
#pragma mark - set_ frame
|
||||
- (MMLayout *)mm_selfLayout{
|
||||
MMLayout *layout = objc_getAssociatedObject(self, &_layoutKey);
|
||||
if (layout == nil) {
|
||||
layout = [[MMLayout alloc] initWithLayoutView:self];
|
||||
objc_setAssociatedObject(self, &_layoutKey, layout, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_top{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_top){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].top = m_top;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToTop{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToTop){
|
||||
@m_strongify(self);
|
||||
CGFloat top = [self mm_selfLayout].top;
|
||||
[self mm_selfLayout].top = m_flexToTop;
|
||||
[self mm_selfLayout].height += top-m_flexToTop;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_bottom{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_bottom){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].bottom = m_bottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToBottom{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToBottom){
|
||||
@m_strongify(self);
|
||||
CGFloat bottom = [self mm_selfLayout].bottom;
|
||||
[self mm_selfLayout].height += bottom-m_flexToBottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_left{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_left){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].left = m_left;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToLeft{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToLeft){
|
||||
@m_strongify(self);
|
||||
CGFloat left = [self mm_selfLayout].left;
|
||||
[self mm_selfLayout].left = m_flexToLeft;
|
||||
[self mm_selfLayout].width += left-m_flexToLeft;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_right{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_right){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].right = m_right;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_flexToRight{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_flexToRight){
|
||||
@m_strongify(self);
|
||||
CGFloat right = [self mm_selfLayout].right;
|
||||
[self mm_selfLayout].width += right-m_flexToRight;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_width{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_width){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].width = m_width;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGFloat))m_height{
|
||||
@m_weakify(self);
|
||||
return ^(CGFloat m_height){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].height = m_height;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(CGSize))m_size{
|
||||
@m_weakify(self);
|
||||
return ^(CGSize m_size){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].size = m_size;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
- (UIView *(^)(CGPoint))m__center{
|
||||
@m_weakify(self);
|
||||
return ^(CGPoint m__center){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].center = m__center;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(void))m_center{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] center];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_centerY{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] centerY];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_centerX{
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
[[self mm_selfLayout] centerX];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
-(UIView *(^)(void))m_fill {
|
||||
@m_weakify(self);
|
||||
return ^{
|
||||
@m_strongify(self);
|
||||
if (self.superview) {
|
||||
self.mm_x = self.mm_y = 0;
|
||||
self.mm_w = self.superview.mm_w;
|
||||
self.mm_h = self.superview.mm_h;
|
||||
}
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
#pragma mark - m_equalTo
|
||||
-(UIView *(^)(UIView *))m_equalToFrame{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.frame = obj.frame;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToTop{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.top = obj.mm_selfLayout.top;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToBottom{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.bottom = obj.mm_selfLayout.bottom;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToLeft{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.left = obj.mm_selfLayout.left;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToRight{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.right = obj.mm_selfLayout.right;
|
||||
return self;
|
||||
};
|
||||
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToWidth{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.width = obj.mm_selfLayout.width;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToHeight{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
self.mm_selfLayout.height = obj.mm_selfLayout.height;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
-(UIView *(^)(UIView *))m_equalToSize{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].size = obj.mm_selfLayout.size;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
- (UIView *(^)(UIView *))m_equalToCenter{
|
||||
@m_weakify(self);
|
||||
return ^(UIView *obj){
|
||||
@m_strongify(self);
|
||||
[self mm_selfLayout].point = obj.mm_selfLayout.point;
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
- (UIView *(^)(void))m_sizeToFit{
|
||||
@m_weakify(self);
|
||||
return ^(void){
|
||||
@m_strongify(self);
|
||||
[self sizeToFit];
|
||||
return self;
|
||||
};
|
||||
}
|
||||
|
||||
- (NSData *)mm_createPDF{
|
||||
CGRect bounds = self.bounds;
|
||||
NSMutableData *data = [NSMutableData data];
|
||||
CGDataConsumerRef consumer = CGDataConsumerCreateWithCFData((__bridge CFMutableDataRef)data);
|
||||
CGContextRef context = CGPDFContextCreate(consumer, &bounds, NULL);
|
||||
CGDataConsumerRelease(consumer);
|
||||
if (!context) return nil;
|
||||
CGPDFContextBeginPage(context, NULL);
|
||||
CGContextTranslateCTM(context, 0, bounds.size.height);
|
||||
CGContextScaleCTM(context, 1.0, -1.0);
|
||||
[self.layer renderInContext:context];
|
||||
CGPDFContextEndPage(context);
|
||||
CGPDFContextClose(context);
|
||||
CGContextRelease(context);
|
||||
return data;
|
||||
}
|
||||
|
||||
- (UIViewController *)viewController {
|
||||
UIView *view = self;
|
||||
while (view) {
|
||||
UIResponder *nextResponder = [view nextResponder];
|
||||
if ([nextResponder isKindOfClass:[UIViewController class]]) {
|
||||
return (UIViewController *)nextResponder;
|
||||
}
|
||||
view = view.superview;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
static void *kUIViewLayoutMethodPropertyBottomGap = &kUIViewLayoutMethodPropertyBottomGap;
|
||||
static void *kUIViewLayoutMethodPropertyTopGap = &kUIViewLayoutMethodPropertyTopGap;
|
||||
static void *kUIViewLayoutMethodPropertyLeftGap = &kUIViewLayoutMethodPropertyLeftGap;
|
||||
static void *kUIViewLayoutMethodPropertyRightGap = &kUIViewLayoutMethodPropertyRightGap;
|
||||
|
||||
- (CGFloat)mm_safeAreaBottomGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyBottomGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
if (self.superview.safeAreaLayoutGuide.layoutFrame.size.height > 0) {
|
||||
gap = @((self.superview.mm_h - self.superview.safeAreaLayoutGuide.layoutFrame.origin.y - self.superview.safeAreaLayoutGuide.layoutFrame.size.height));
|
||||
} else {
|
||||
gap = nil;
|
||||
}
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyBottomGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaTopGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyTopGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.y);
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyTopGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaLeftGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyLeftGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.x);
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyLeftGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
- (CGFloat)mm_safeAreaRightGap
|
||||
{
|
||||
NSNumber *gap = objc_getAssociatedObject(self, kUIViewLayoutMethodPropertyRightGap);
|
||||
if (gap == nil) {
|
||||
if (@available(iOS 11, *)) {
|
||||
gap = @((self.superview.mm_w - self.superview.safeAreaLayoutGuide.layoutFrame.origin.x - self.superview.safeAreaLayoutGuide.layoutFrame.size.width));
|
||||
} else {
|
||||
gap = @(0);
|
||||
}
|
||||
objc_setAssociatedObject(self, kUIViewLayoutMethodPropertyRightGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
return gap.floatValue;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIViewController (SuperPlayerRotation)
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
#import "UIViewController+SuperPlayerRotation.h"
|
||||
|
||||
@implementation UIViewController (SuperPlayerRotation)
|
||||
|
||||
/**
|
||||
* 默认所有都不支持转屏,如需个别页面支持除竖屏外的其他方向,请在viewController重新下边这三个方法
|
||||
*/
|
||||
|
||||
// 支持哪些屏幕方向
|
||||
- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
|
||||
return UIInterfaceOrientationMaskPortrait;
|
||||
}
|
||||
|
||||
// 默认的屏幕方向(当前ViewController必须是通过模态出来的UIViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)
|
||||
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
|
||||
return UIInterfaceOrientationPortrait;
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string></string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// AdaptiveStream.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AdaptiveStream : NSObject
|
||||
@property NSString *url;
|
||||
@property NSString *drmType;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// AdaptiveStream.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AdaptiveStream.h"
|
||||
|
||||
@implementation AdaptiveStream
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,69 @@
|
||||
//
|
||||
// SPPlayCGIParseResult.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
//#import "SPResolutionDefination.h"
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "AdaptiveStream.h"
|
||||
#import "SuperPlayerSprite.h"
|
||||
#import "SPVideoFrameDescription.h"
|
||||
#import "SuperPlayerUrl.h"
|
||||
|
||||
@class TXImageSprite;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef NS_ENUM(NSUInteger, SPDrmType) {
|
||||
SPDrmTypeNone,
|
||||
SPDrmTypeSimpleAES
|
||||
};
|
||||
|
||||
@interface SPPlayCGIParseResult : NSObject
|
||||
/// 视频播放url
|
||||
@property (strong, nonatomic) NSString *url;
|
||||
/// 视频名称
|
||||
@property (strong, nonatomic) NSString *name;
|
||||
/// 雪略图对象
|
||||
@property (strong, nonatomic) TXImageSprite *imageSprite;
|
||||
/// 雪略图打点帧信息
|
||||
@property (strong, nonatomic) NSArray<SPVideoFrameDescription *> *keyFrameDescList;
|
||||
/// 字流画质信息
|
||||
@property (strong, nonatomic) NSArray<SPSubStreamInfo *> *resolutionArray;
|
||||
/// 原视频时长
|
||||
@property (assign, nonatomic) NSTimeInterval originalDuration;
|
||||
|
||||
/// 预留字段,暂不使用
|
||||
@property (strong, nonatomic) NSArray<AdaptiveStream *> *adaptiveStreamArray;
|
||||
|
||||
/// V2协议的多码率URL列表
|
||||
@property (strong, nonatomic) NSArray<SuperPlayerUrl *> *multiVideoURLs;
|
||||
|
||||
/// 加密类型,用于 Drm
|
||||
@property (assign, nonatomic) SPDrmType drmType;
|
||||
|
||||
/// 加密令牌,用于 Drm
|
||||
@property (copy, nonatomic) NSString *drmToken;
|
||||
+ (SPDrmType)drmTypeFromString:(NSString *)typeString;
|
||||
/**
|
||||
* 获取画质信息
|
||||
*
|
||||
* @return 画质信息数组
|
||||
|
||||
List<TCVideoQuality> getVideoQualityList();
|
||||
|
||||
|
||||
* 获取默认画质信息
|
||||
*
|
||||
* @return 默认画质信息对象
|
||||
|
||||
TCVideoQuality getDefaultVideoQuality();
|
||||
*/
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// SPPlayCGIParseResult.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParseResult.h"
|
||||
#import "TXImageSprite.h"
|
||||
|
||||
@implementation SPPlayCGIParseResult
|
||||
+ (SPDrmType)drmTypeFromString:(NSString *)typeString {
|
||||
BOOL isSimpleAES = [typeString caseInsensitiveCompare:@"SimpleAES"] == NSOrderedSame;
|
||||
if (isSimpleAES) {
|
||||
return SPDrmTypeSimpleAES;
|
||||
}
|
||||
return SPDrmTypeNone;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPSubStreamInfo.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by Steven Choi on 2020/2/11.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/// 自适应码流子流信息
|
||||
@interface SPSubStreamInfo : NSObject
|
||||
@property (assign, nonatomic) CGSize size;
|
||||
@property (copy, nonatomic) NSString *resolutionName;
|
||||
@property (copy, nonatomic) NSString *type;
|
||||
+ (instancetype)infoWithDictionary:(NSDictionary *)dict;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SPSubStreamInfo.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by Steven Choi on 2020/2/11.
|
||||
// Copyright © 2020 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "J2Obj.h"
|
||||
@implementation SPSubStreamInfo
|
||||
+ (instancetype)infoWithDictionary:(NSDictionary *)dict {
|
||||
SPSubStreamInfo *info = [[SPSubStreamInfo alloc] init];
|
||||
double width = [J2Num(dict[@"width"]) doubleValue];
|
||||
double height = [J2Num(dict[@"height"]) doubleValue];
|
||||
info.size = CGSizeMake(width, height);
|
||||
info.resolutionName = J2Str(dict[@"name"]);
|
||||
info.type = J2Str(dict[@"type"]);
|
||||
return info;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,21 @@
|
||||
//
|
||||
// SPVideoFrameDescription.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPVideoFrameDescription : NSObject
|
||||
// updates in SuperPlayerView
|
||||
@property double where;
|
||||
@property NSString *text;
|
||||
@property double time;
|
||||
+ (instancetype)instanceFromDictionary:(NSDictionary *)dict;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPVideoFrameDescription.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPVideoFrameDescription.h"
|
||||
#import "J2Obj.h"
|
||||
|
||||
@implementation SPVideoFrameDescription
|
||||
+ (instancetype)instanceFromDictionary:(NSDictionary *)keyFrameDesc {
|
||||
if (![keyFrameDesc isKindOfClass:[NSDictionary class]]) {
|
||||
return nil;
|
||||
}
|
||||
SPVideoFrameDescription *ret = [[SPVideoFrameDescription alloc] init];
|
||||
ret.time = [J2Num([keyFrameDesc valueForKeyPath:@"timeOffset"]) intValue]/1000.0;
|
||||
ret.text = [J2Str([keyFrameDesc valueForKeyPath:@"content"]) stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SuperPlayerSprite.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SuperPlayerSprite : NSObject
|
||||
@property (strong, nonatomic) NSArray<NSString *> *imageURLs;
|
||||
@property (strong, nonatomic) NSString *webVttURL;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// SuperPlayerSprite.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SuperPlayerSprite.h"
|
||||
|
||||
@implementation SuperPlayerSprite
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// SuperPlayerUrl.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
/**
|
||||
* 多码率地址
|
||||
* 用于有多个播放地址的多清晰度视频的播放
|
||||
*/
|
||||
@interface SuperPlayerUrl : NSObject
|
||||
/// 播放器展示的对应标题,如“高清”、“低清”等
|
||||
@property NSString *title;
|
||||
/// 播放地址
|
||||
@property NSString *url;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,13 @@
|
||||
//
|
||||
// SuperPlayerUrl.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SuperPlayerUrl.h"
|
||||
|
||||
@implementation SuperPlayerUrl
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SPPlayCGIParser.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/26.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser : NSObject
|
||||
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// SPPlayCGIParser.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/26.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser.h"
|
||||
#import "SPPlayCGIParser_V2.h"
|
||||
#import "SPPlayCGIParser_V4.h"
|
||||
|
||||
@implementation SPPlayCGIParser
|
||||
+ (Class<SPPlayCGIParserProtocol>)parserOfVersion:(NSInteger)version {
|
||||
if (version == 2) {
|
||||
return [SPPlayCGIParser_V2 class];
|
||||
} else if (version == 4) {
|
||||
return [SPPlayCGIParser_V4 class];
|
||||
}
|
||||
return Nil;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// PlayCGIParserProtocol.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParseResult.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol SPPlayCGIParserProtocol <NSObject>
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// SPPlayCGIParser_V2.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser_V2 : NSObject <SPPlayCGIParserProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,105 @@
|
||||
//
|
||||
// SPPlayCGIParser_V2.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser_V2.h"
|
||||
#import "J2Obj.h"
|
||||
#import "SuperPlayerUrl.h"
|
||||
#import "TXBitrateItemHelper.h"
|
||||
#import "TXImageSprite.h"
|
||||
|
||||
@implementation SPPlayCGIParser_V2
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)responseObject {
|
||||
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
|
||||
NSString *masterUrl = J2Str([responseObject valueForKeyPath:@"videoInfo.masterPlayList.url"]);
|
||||
// masterUrl = nil;
|
||||
if (masterUrl.length > 0) {
|
||||
// 1. 如果有master url,优先用这个
|
||||
ret.url = masterUrl;
|
||||
} else {
|
||||
NSString *mainDefinition = J2Str([responseObject valueForKeyPath:@"playerInfo.defaultVideoClassification"]);
|
||||
|
||||
NSArray *videoClassification = J2Array([responseObject valueForKeyPath:@"playerInfo.videoClassification"]);
|
||||
NSArray *transcodeList = J2Array([responseObject valueForKeyPath:@"videoInfo.transcodeList"]);
|
||||
|
||||
NSMutableArray<SuperPlayerUrl *> *result = [NSMutableArray new];
|
||||
|
||||
// 2. 如果有转码的清晰度,用转码流
|
||||
for (NSDictionary *transcode in transcodeList) {
|
||||
SuperPlayerUrl *subModel = [SuperPlayerUrl new];
|
||||
subModel.url = J2Str(transcode[@"url"]);
|
||||
NSNumber *theDefinition = J2Num(transcode[@"definition"]);
|
||||
|
||||
for (NSDictionary *definition in videoClassification) {
|
||||
for (NSObject *definition2 in J2Array([definition valueForKeyPath:@"definitionList"])) {
|
||||
|
||||
if ([definition2 isEqual:theDefinition]) {
|
||||
subModel.title = J2Str([definition valueForKeyPath:@"name"]);
|
||||
NSString *definitionId = J2Str([definition valueForKeyPath:@"id"]);
|
||||
// 初始播放清晰度
|
||||
if ([definitionId isEqualToString:mainDefinition]) {
|
||||
if (![ret.url containsString:@".mp4"])
|
||||
ret.url = subModel.url;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// 同一个清晰度可能存在多个转码格式,这里只保留一种格式,且优先mp4类型
|
||||
for (SuperPlayerUrl *item in result) {
|
||||
if ([item.title isEqual:subModel.title]) {
|
||||
if (![item.url containsString:@".mp4"]) {
|
||||
item.url = subModel.url;
|
||||
}
|
||||
subModel = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (subModel) {
|
||||
[result addObject:subModel];
|
||||
}
|
||||
}
|
||||
ret.multiVideoURLs = result;
|
||||
}
|
||||
// 3. 以上都没有,用原始地址
|
||||
if (ret.url == nil) {
|
||||
NSString *source = J2Str([responseObject valueForKeyPath:@"videoInfo.sourceVideo.url"]);
|
||||
ret.url = source;
|
||||
}
|
||||
|
||||
NSArray *imageSprites = J2Array([responseObject valueForKeyPath:@"imageSpriteInfo.imageSpriteList"]);
|
||||
if (imageSprites.count > 0) {
|
||||
// id imageSpriteObj = imageSprites[0];
|
||||
id imageSpriteObj = imageSprites.lastObject;
|
||||
NSString *vtt = J2Str([imageSpriteObj valueForKeyPath:@"webVttUrl"]);
|
||||
NSArray *imgUrls = J2Array([imageSpriteObj valueForKeyPath:@"imageUrls"]);
|
||||
NSMutableArray *imgUrlArray = @[].mutableCopy;
|
||||
for (NSString *url in imgUrls) {
|
||||
NSURL *nsurl = [NSURL URLWithString:url];
|
||||
if (nsurl) {
|
||||
[imgUrlArray addObject:nsurl];
|
||||
}
|
||||
}
|
||||
|
||||
TXImageSprite *imageSprite = [[TXImageSprite alloc] init];
|
||||
[imageSprite setVTTUrl:[NSURL URLWithString:vtt] imageUrls:imgUrlArray];
|
||||
ret.imageSprite = imageSprite;
|
||||
}
|
||||
|
||||
NSArray *keyFrameDescList = J2Array([responseObject valueForKeyPath:@"keyFrameDescInfo.keyFrameDescList"]);
|
||||
if (keyFrameDescList.count > 0) {
|
||||
NSMutableArray<SPVideoFrameDescription *> *checkPoints = [[NSMutableArray alloc] initWithCapacity:keyFrameDescList.count];
|
||||
for (NSDictionary *info in keyFrameDescList) {
|
||||
SPVideoFrameDescription *checkPoint = [SPVideoFrameDescription instanceFromDictionary:info];
|
||||
[checkPoints addObject:checkPoint];
|
||||
}
|
||||
ret.keyFrameDescList = checkPoints;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// PlayCGIV4Parser.h
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "SPPlayCGIParserProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SPPlayCGIParser_V4 : NSObject <SPPlayCGIParserProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,122 @@
|
||||
//
|
||||
// PlayCGIV4Parser.m
|
||||
// SuperPlayer
|
||||
//
|
||||
// Created by cui on 2019/12/25.
|
||||
// Copyright © 2019 annidy. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SPPlayCGIParser_V4.h"
|
||||
//#import "SPResolutionDefination.h"
|
||||
#import "SPSubStreamInfo.h"
|
||||
#import "AdaptiveStream.h"
|
||||
#import "TXImageSprite.h"
|
||||
#import "J2Obj.h"
|
||||
|
||||
@implementation SPPlayCGIParser_V4
|
||||
|
||||
+ (SPPlayCGIParseResult *)parseResponse:(NSDictionary *)jsonResp {
|
||||
SPPlayCGIParseResult *ret = [[SPPlayCGIParseResult alloc] init];
|
||||
|
||||
// 获取媒体信息
|
||||
NSDictionary *media = jsonResp[@"media"];
|
||||
if ([media isKindOfClass:[NSDictionary class]]) {
|
||||
do {
|
||||
//解析视频名称
|
||||
ret.name = [media valueForKeyPath:@"basicInfo.name"];
|
||||
NSDictionary *streamInfo = [media valueForKeyPath:@"streamingInfo.plainOutput"];
|
||||
if (streamInfo == nil) {
|
||||
NSArray* drmOutputs = [media valueForKeyPath:@"streamingInfo.drmOutput"];
|
||||
for (NSDictionary *drmOutput in drmOutputs) {
|
||||
SPDrmType type = [SPPlayCGIParseResult drmTypeFromString:J2Str(drmOutput[@"type"])];
|
||||
if (type == SPDrmTypeSimpleAES) {
|
||||
streamInfo = drmOutput;
|
||||
ret.drmType = SPDrmTypeSimpleAES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
ret.drmToken = [media valueForKeyPath:@"streamingInfo.drmToken"];
|
||||
}
|
||||
if (streamInfo == nil) {
|
||||
return nil;
|
||||
}
|
||||
NSNumber *duration = [media valueForKeyPath:@"basicInfo.duration"];
|
||||
if ([duration isKindOfClass:[NSNumber class]]) {
|
||||
ret.originalDuration = duration.doubleValue;
|
||||
}
|
||||
// 解析分辨率名称
|
||||
NSArray *subStreamDictArray = J2Array(streamInfo[@"subStreams"]);
|
||||
NSMutableArray *subStreamInfoArray = [NSMutableArray arrayWithCapacity:subStreamDictArray.count];
|
||||
for (NSDictionary *resInfo in subStreamDictArray) {
|
||||
SuperPlayerUrl *url = [[SuperPlayerUrl alloc] init];
|
||||
url.title = J2Str(resInfo[@"resolutionName"]);
|
||||
// SPSubStreamInfo *info = [SPSubStreamInfo infoWithDictionary:resInfo];
|
||||
[subStreamInfoArray addObject:url];
|
||||
}
|
||||
ret.multiVideoURLs = subStreamInfoArray;
|
||||
|
||||
//解析视频播放url
|
||||
NSString *url = streamInfo[@"url"];
|
||||
if ([url isKindOfClass:[NSString class]] && url.length > 0) {
|
||||
//未加密直接解析出视频url
|
||||
ret.url = url;
|
||||
} else {
|
||||
//有加密,url为空,则解析drm加密的url信息
|
||||
NSArray *urlArray = streamInfo[@"drmUrls"];
|
||||
if ([urlArray isKindOfClass:[NSArray class]] &&
|
||||
urlArray.count > 0) {
|
||||
NSMutableArray *drmURLArray = [NSMutableArray arrayWithCapacity:urlArray.count];
|
||||
for (NSDictionary *dict in urlArray) {
|
||||
if ([dict isKindOfClass:[NSDictionary class]]) {
|
||||
continue;
|
||||
}
|
||||
AdaptiveStream *stream = [[AdaptiveStream alloc] init];
|
||||
stream.url = dict[@"url"];
|
||||
stream.drmType = dict[@"type"];
|
||||
[drmURLArray addObject:stream];
|
||||
}
|
||||
ret.adaptiveStreamArray = drmURLArray;
|
||||
}
|
||||
}
|
||||
|
||||
//解析略缩图信息
|
||||
NSDictionary *imageSpriteInfo = media[@"imageSpriteInfo"];
|
||||
|
||||
if ([imageSpriteInfo isKindOfClass:[NSDictionary class]]) {
|
||||
NSString *vttURLString = J2Str(imageSpriteInfo[@"webVttUrl"]);
|
||||
NSURL *vttURL = [NSURL URLWithString:vttURLString];
|
||||
NSArray *imageURLStrings = J2Array(imageSpriteInfo[@"imageUrls"]);
|
||||
NSMutableArray<NSURL *> *imageURLs = [NSMutableArray arrayWithCapacity:imageURLStrings.count];
|
||||
for (NSString *urlString in imageURLStrings) {
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
if (url) {
|
||||
[imageURLs addObject:url];
|
||||
}
|
||||
}
|
||||
TXImageSprite *sprite = [[TXImageSprite alloc] init];
|
||||
[sprite setVTTUrl:vttURL imageUrls:imageURLs];
|
||||
ret.imageSprite = sprite;
|
||||
}
|
||||
|
||||
//解析关键帧信息
|
||||
NSDictionary *keyFrameDescInfo = media[@"keyFrameDescInfo"];
|
||||
if ([keyFrameDescInfo isKindOfClass:[NSDictionary class]]) {
|
||||
NSArray *keyFrameDescList = keyFrameDescInfo[@"keyFrameDescList"];
|
||||
if ([keyFrameDescList isKindOfClass:[NSArray class]] &&
|
||||
keyFrameDescList.count > 0) {
|
||||
NSMutableArray<SPVideoFrameDescription *> *videoPoints = [NSMutableArray array];
|
||||
for (NSDictionary *jsonObject in keyFrameDescList) {
|
||||
SPVideoFrameDescription *point = [SPVideoFrameDescription instanceFromDictionary:jsonObject];
|
||||
if (point) {
|
||||
[videoPoints addObject:point];
|
||||
}
|
||||
}
|
||||
ret.keyFrameDescList = videoPoints;
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@end
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 361 B |
|
After Width: | Height: | Size: 539 B |
|
After Width: | Height: | Size: 9.6 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 327 B |
|
After Width: | Height: | Size: 426 B |
|
After Width: | Height: | Size: 615 B |
|
After Width: | Height: | Size: 834 B |
|
After Width: | Height: | Size: 565 B |
|
After Width: | Height: | Size: 772 B |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 173 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 6.7 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 587 B |
|
After Width: | Height: | Size: 833 B |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 270 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 577 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 124 B |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 907 B |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 753 B |
|
After Width: | Height: | Size: 1.1 KiB |