如何用Swift在iOS UITextView中嵌入带iframe的HTML实现视频播放
UITextView渲染带iframe的HTML内容解决方案
根本原因说明
UITextView通过NSAttributedString加载HTML时,仅支持有限的HTML标签集,iframe标签不在原生支持范围内,所以无法直接渲染。
方案1:占位图+点击唤起播放(最稳妥,兼容性最高)
实现成本低、稳定性高,是无WKWebView可用时的首选方案:
- 第一步:预处理原始HTML,通过正则匹配提取所有iframe标签的
src属性值,同时将iframe标签替换为视频播放占位图对应的<img>标签,可自定义占位图宽高适配排版。 - 第二步:将处理后的HTML加载为NSAttributedString,同时给占位图对应的富文本范围添加自定义属性,存储对应提取到的视频URL。
- 第三步:给UITextView添加点击手势识别,点击时判断点击位置的富文本是否携带视频URL属性,存在则唤起AVPlayer/AVPlayerViewController播放对应资源。
核心代码示例
// 匹配iframe提取src的正则示例 NSString *htmlString = @"你的原始HTML内容"; NSString *regexPattern = @"<iframe[^>]+src\\s*=\\s*['\"]([^'\"]+)['\"][^>]*>"; NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexPattern options:NSRegularExpressionCaseInsensitive error:nil]; NSMutableString *processedHTML = [htmlString mutableCopy]; // 倒序遍历匹配结果,避免替换后range错位 NSArray *matches = [regex matchesInString:htmlString options:0 range:NSMakeRange(0, htmlString.length)]; for (NSTextCheckingResult *result in [matches reverseObjectEnumerator]) { NSRange srcRange = [result rangeAtIndex:1]; NSString *videoURL = [htmlString substringWithRange:srcRange]; // 替换iframe为占位img标签,可自定义宽高 NSString *placeholderImgTag = [NSString stringWithFormat:@"<img src='本地占位图资源名' width='300' height='200'/>", videoURL]; [processedHTML replaceCharactersInRange:result.range withString:placeholderImgTag]; } // 加载处理后的HTML为富文本 NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithData:[processedHTML dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: @(NSUTF8StringEncoding)} documentAttributes:nil error:nil]; // 给占位图范围添加自定义存储视频URL的属性,此处省略遍历富文本匹配img范围的逻辑 textView.attributedText = attributedString;
// 点击手势处理逻辑 - (void)handleTapOnTextView:(UITapGestureRecognizer *)gesture { CGPoint tapLocation = [gesture locationInView:textView]; UITextPosition *textPosition = [textView closestPositionToPoint:tapLocation]; NSDictionary *attributes = [textView textStylingAtPosition:textPosition inDirection:UITextStorageDirectionForward]; NSURL *videoURL = attributes[自定义视频URL属性名]; if (videoURL) { // 唤起播放器 AVPlayerViewController *playerVC = [[AVPlayerViewController alloc] init]; playerVC.player = [AVPlayer playerWithURL:videoURL]; [self presentViewController:playerVC animated:YES completion:^{ [playerVC.player play]; }]; } }
方案2:NSTextAttachment嵌入原生视频视图(适合需在文本流内直接播放的场景)
如果要求视频直接在文本流内播放无需跳转,可采用本方案:
- 第一步:同方案1,匹配提取所有iframe的视频地址,记录每个iframe在原始HTML中的位置和尺寸。
- 第二步:创建自定义NSTextAttachment,对应每个视频的占位位置,设置attachment的bounds为预期的视频渲染尺寸。
- 第三步:将原始HTML中iframe标签替换为对应attachment的占位标记,加载生成富文本后,将自定义的带AVPlayerLayer的视图添加到UITextView的对应坐标位置,监听滚动事件调整视图位置实现跟随富文本滚动。
注意事项
- 如果iframe的src是第三方平台的嵌入网页而非直链视频流,AVPlayer无法直接播放,可根据需求选择跳转系统浏览器打开对应URL,或单独解析嵌入页的实际视频资源地址。
- 加载HTML时需明确指定
NSDocumentTypeDocumentAttribute为NSHTMLTextDocumentType,编码指定为UTF-8,避免普通HTML内容渲染异常。 - 需将UITextView的
isEditable设为NO,避免误触编辑状态影响交互。
内容的提问来源于stack exchange,提问作者Chrishan
相关产品推荐
相关产品推荐

