|
|
|
|
@@ -12,6 +12,7 @@
|
|
|
|
|
// 配置保存的 key
|
|
|
|
|
static NSString * const kSCPlayerConfigProtocol = @"SCPlayerConfigProtocol";
|
|
|
|
|
static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
static NSString * const kSCPlayerConfigXorKey = @"SCPlayerConfigXorKey";
|
|
|
|
|
|
|
|
|
|
@implementation SCPlayerConfig
|
|
|
|
|
|
|
|
|
|
@@ -21,6 +22,11 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
if (self.streamId) {
|
|
|
|
|
[defaults setObject:self.streamId forKey:kSCPlayerConfigStreamId];
|
|
|
|
|
}
|
|
|
|
|
if (self.xorKey.length > 0) {
|
|
|
|
|
[defaults setObject:self.xorKey forKey:kSCPlayerConfigXorKey];
|
|
|
|
|
} else {
|
|
|
|
|
[defaults removeObjectForKey:kSCPlayerConfigXorKey];
|
|
|
|
|
}
|
|
|
|
|
[defaults synchronize];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -39,7 +45,10 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
// 加载 streamId
|
|
|
|
|
NSString *streamId = [defaults objectForKey:kSCPlayerConfigStreamId];
|
|
|
|
|
config.streamId = streamId ? streamId : @"test";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载 xorKey
|
|
|
|
|
config.xorKey = [defaults objectForKey:kSCPlayerConfigXorKey];
|
|
|
|
|
|
|
|
|
|
return config;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -50,6 +59,7 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
@property (nonatomic, strong) UIVisualEffectView *backgroundView;
|
|
|
|
|
@property (nonatomic, strong) UISegmentedControl *protocolSegment;
|
|
|
|
|
@property (nonatomic, strong) UITextField *streamIdField;
|
|
|
|
|
@property (nonatomic, strong) UITextField *xorKeyField;
|
|
|
|
|
@property (nonatomic, strong) UIButton *playButton;
|
|
|
|
|
@property (nonatomic, copy) void(^callback)(SCPlayerConfig *config);
|
|
|
|
|
@property (nonatomic, strong) MASConstraint *backgroundViewCenterYConstraint; // 保存约束引用
|
|
|
|
|
@@ -172,6 +182,35 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
make.height.offset(44);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// 加密密钥标签
|
|
|
|
|
UILabel *xorKeyLabel = [[UILabel alloc] init];
|
|
|
|
|
xorKeyLabel.text = @"加密密钥 (Hex),留空不解密";
|
|
|
|
|
xorKeyLabel.font = [UIFont systemFontOfSize:14];
|
|
|
|
|
xorKeyLabel.numberOfLines = 0;
|
|
|
|
|
[_contentView addSubview:xorKeyLabel];
|
|
|
|
|
[xorKeyLabel mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.equalTo(_streamIdField.mas_bottom).offset(24);
|
|
|
|
|
make.left.right.equalTo(_contentView);
|
|
|
|
|
make.height.offset(20);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// 加密密钥输入框
|
|
|
|
|
_xorKeyField = [[UITextField alloc] init];
|
|
|
|
|
_xorKeyField.placeholder = @"如 AABBCCDD";
|
|
|
|
|
_xorKeyField.borderStyle = UITextBorderStyleRoundedRect;
|
|
|
|
|
_xorKeyField.font = [UIFont systemFontOfSize:15];
|
|
|
|
|
_xorKeyField.clearButtonMode = UITextFieldViewModeWhileEditing;
|
|
|
|
|
_xorKeyField.returnKeyType = UIReturnKeyDone;
|
|
|
|
|
_xorKeyField.delegate = self;
|
|
|
|
|
_xorKeyField.autocapitalizationType = UITextAutocapitalizationTypeNone;
|
|
|
|
|
_xorKeyField.autocorrectionType = UITextAutocorrectionTypeNo;
|
|
|
|
|
[_contentView addSubview:_xorKeyField];
|
|
|
|
|
[_xorKeyField mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.equalTo(xorKeyLabel.mas_bottom).offset(8);
|
|
|
|
|
make.left.right.equalTo(_contentView);
|
|
|
|
|
make.height.offset(44);
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
|
|
// 播放按钮
|
|
|
|
|
_playButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
|
|
|
|
[_playButton setTitle:@"开始播放" forState:UIControlStateNormal];
|
|
|
|
|
@@ -183,7 +222,7 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
[_playButton addTarget:self action:@selector(playButtonTapped) forControlEvents:UIControlEventTouchUpInside];
|
|
|
|
|
[_contentView addSubview:_playButton];
|
|
|
|
|
[_playButton mas_makeConstraints:^(MASConstraintMaker *make) {
|
|
|
|
|
make.top.equalTo(_streamIdField.mas_bottom).offset(32);
|
|
|
|
|
make.top.equalTo(_xorKeyField.mas_bottom).offset(32);
|
|
|
|
|
make.left.right.equalTo(_contentView);
|
|
|
|
|
make.height.offset(50);
|
|
|
|
|
make.bottom.equalTo(_contentView);
|
|
|
|
|
@@ -201,10 +240,24 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NSString *xorKey = [_xorKeyField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
|
|
|
|
|
if (xorKey.length > 0) {
|
|
|
|
|
if (xorKey.length % 2 != 0) {
|
|
|
|
|
[self showAlertWithMessage:@"加密密钥必须为偶数长度"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
NSCharacterSet *hexChars = [NSCharacterSet characterSetWithCharactersInString:@"0123456789abcdefABCDEF"];
|
|
|
|
|
if ([xorKey rangeOfCharacterFromSet:hexChars.invertedSet].location != NSNotFound) {
|
|
|
|
|
[self showAlertWithMessage:@"加密密钥只能包含十六进制字符 (0-9, a-f, A-F)"];
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SCPlayerConfig *config = [[SCPlayerConfig alloc] init];
|
|
|
|
|
config.protocol = _protocolSegment.selectedSegmentIndex == 0 ? SellyLiveMode_RTMP : SellyLiveMode_RTC;
|
|
|
|
|
config.streamId = streamId;
|
|
|
|
|
|
|
|
|
|
config.xorKey = xorKey.length > 0 ? xorKey : nil;
|
|
|
|
|
|
|
|
|
|
// 保存配置
|
|
|
|
|
[config saveToUserDefaults];
|
|
|
|
|
|
|
|
|
|
@@ -306,6 +359,9 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
if (savedConfig.streamId && savedConfig.streamId.length > 0) {
|
|
|
|
|
_streamIdField.text = savedConfig.streamId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 设置 xorKey
|
|
|
|
|
_xorKeyField.text = savedConfig.xorKey ?: @"";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#pragma mark - UITextFieldDelegate
|
|
|
|
|
@@ -340,8 +396,9 @@ static NSString * const kSCPlayerConfigStreamId = @"SCPlayerConfigStreamId";
|
|
|
|
|
NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];
|
|
|
|
|
UIViewAnimationCurve curve = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue];
|
|
|
|
|
|
|
|
|
|
// 计算输入框在屏幕上的位置
|
|
|
|
|
CGRect textFieldFrame = [_streamIdField convertRect:_streamIdField.bounds toView:self];
|
|
|
|
|
// 计算当前激活输入框在屏幕上的位置
|
|
|
|
|
UITextField *activeField = _xorKeyField.isFirstResponder ? _xorKeyField : _streamIdField;
|
|
|
|
|
CGRect textFieldFrame = [activeField convertRect:activeField.bounds toView:self];
|
|
|
|
|
CGFloat textFieldBottom = CGRectGetMaxY(textFieldFrame);
|
|
|
|
|
|
|
|
|
|
// 计算需要的偏移量
|
|
|
|
|
|