西瓜视频 iOS Voice Over 无障碍适配实践

动手点关注 干货不迷路 👆

为了解决老年人、残疾人等群体在使用互联网等智能技术时遇到的困难,自 2021 年春季开始,西瓜视频开展了无障碍与适老化改造专项行动。陆续完成了无障碍影院、色弱模式、护眼模式、大字号模式、外挂字幕等多个改造需求,充分满足了视力障碍、听力障碍以及老年人等特殊群体的需求。

本文从研发的视角出发,讲述了如何使用 Voice Over、如何适配 Voice Over 以及适配过程中如果遇到问题应该如何解决。

一、Voice Over 简介

Voice Over 旁白是苹果手机自带的工具。它能让人们在不看屏幕的情况下了解页面内容和信息。盲人用户在使用 iOS 设备时依赖 Voice Over 提供听觉反馈。苹果在自研的各类系统中均实现了 Voice Over 功能,如 OS X,iOS,watchOS 等等。透过 Voice Over 视障用户可以在不同设备上获得相同的体验。

使用旁白来访问西瓜视频的用户有很多,“盲人小马哥”就是其中的一位,感兴趣的同学可以通过观看他的视频进一步了解旁白。

二、Voice Over 使用指南

本节介绍了 Voice Over 开发者通常需要配置的开发环境。并以西瓜视频为例,演示了 Voice Over 的基本操作。

Voice Over 开发环境配置

为了测试的方便,建议开发者可以将辅助功能快捷键设置成 VoiceOver 的切换,只需要连按三次右侧开关键就能开启/关闭 VoiceOver。

下方路径中的 “通用” 适用于低版本系统,高版本系统通过设置-> “辅助功能” 即可找到旁白

开启/关闭 Voice Over(旁白)

设置 -> “通用” -> “辅助功能” -> “VoiceOver”(旁白)

设置连按三次右侧开关键开启/关闭 Voice Over(旁白) (开启后可以便捷的打开/关闭旁白)

设置 -> “通用” -> “辅助功能” ->“辅助功能快捷键”,勾选 Voice Over 功能。

开启 Voice Over+字幕面板 (开启后可以便捷的查看旁白的全部朗读文案)

设置 -> “通用” -> “辅助功能” ->“VoiceOver”->“字幕面板”

Voice Over 基本使用 —— 以西瓜为例

Voice Over 常用手势详解

这里主要例举出 iOS 系统和西瓜视频中最常用的手势,完整操作可以参照苹果官方文档(https://support.apple.com/zh-cn/guide/iphone/iph3e2e2281/15.0/ios/15.0)。

入门手势
使用手势进行元素筛选
  • 轻点或触摸项目——选择并朗读项目

  • 向右轻扫——选择下一项

  • 向左轻扫——选择上一项

  • 三指向某个方向滑动——翻页操作,可以使 UIScrollView(包括 TableView、CollectionView)向某个方向翻动一页

使用手势响应元素事件
  • 轻点两下——响应当前元素的事件

  • 轻点三下——双击当前所选元素

  • 双指轻点两下——响应开发者定义的快捷事件 (如播放视频、暂停视频等)

  • 双指左右滑动(快速来回移动双指三次,形成“Z”字形)——关闭弹窗或返回到上一级页面

  • 双指轻点两下并按住——用户自定义元素名称

进阶手势
使用手势快速筛选元素
  • 四指轻点屏幕顶部附近——选择屏幕上的第一项

  • 四指轻点屏幕底部附近——选择屏幕上的最后一项

使用“旁白”转子

您可以使用转子来更改“旁白”设置(如语速、遍历方法等),在屏幕上从一个项目跳到下一个项目,以及选择特殊输入方法(如“盲文屏幕输入”或“手写”)等。有关详细信息,请参阅在 iPhone 上使用转子控制“旁白”(https://support.apple.com/zh-cn/guide/iphone/iph3e2e3a6d/15.0/ios/15.0)。

通过以下手势来使用转子。

  • 双指转动——选取转子设置

  • 向上轻扫——移到上一项或调高(取决于转子设置)

  • 向下轻扫——移到下一项或调低(取决于转子设置)

三、快速适配 Voice Over / 无障碍

想让 App 达到无障碍基本可用并非难事,通过设置无障碍焦点、设置无障碍文案、调整焦点顺序三步可以完成绝大多数的无障碍适配工作。本节对以上三步适配进行了快速入门的介绍,并将西瓜首页作为实战案例为大家讲解。

设置无障碍焦点

焦点是视力障碍用户访问应用的唯一途径,Voice Over 开启时,如果一个元素没有被设置为焦点,那么该元素在屏幕中将不可被访问。用户可以通过在屏幕上移动焦点来“浏览”内容。正确的焦点标注和焦点顺序能够让读屏软件用户获得更好的体验。

c9eb8ec1b3f9b6921496a8b6b64fbd56.png

打开旁白后,系统会使用黑色框体框选当前的焦点。通过轻触某个位置 或 单指左右轻扫即可切换焦点。

哪些场景需要焦点:

除装饰性组件以外的功能性组件都需要焦点,如标题、作者头像、点赞、收藏、评论、更多等。

哪些场景需要合并焦点:

  • 功能相同且距离近的焦点需要合并。如作者名称、作者头像(功能都是跳转个人主页,且距离近)。

  • 需要高效筛选信息的场景需要合并,保留合并焦点的主功能,其余功能添加到转子中,如 Feed。具体参照各业务方设计。

如何设置无障碍焦点:

针对绝大多数情况,我们可以利用以下的几个属性来调整焦点。

isAccessibilityElement:使用该属性可以调整单个元素的无障碍可见性。对于大多数 UI 基本元素,当父控件为无障碍元素时,子控件将无法获焦。

accessibilityElementsHidden:使用该属性可以调整单个元素及其 subviews的无障碍可见性,一般用于屏蔽整个组件。

accessibilityViewIsModal:使用该属性可以使该元素在同级 view中保持唯一可见性。常见场景见焦点被覆盖时仍然可以被访问。

设置无障碍文案

好的无障碍文案可以让用户清晰的了解到当前焦点的目的,一般来说我们可以将元素按照按钮、输入框、搜索框等来划分,从而进行标注。

当我们参照“开发环境配置”配置好字幕后,旁白朗读的文案将显示在屏幕的底部。

7e124be7d62f32d9e376a8fb7ab0a56b.png
无障碍文案应该包含什么:

无障碍文案需要能准确描述一个焦点的功能及当前的状态 (如 已选定、点赞、标签栏)。如果一个焦点包含多个不同的内容,应当按照信息优先级,将该焦点内全部肉眼可见信息全部朗读。

如何配置无障碍文案:

从代码层面来看,我们可以通过以下的几个属性来设置无障碍文案。

accessibilityLabel:一般来说,任意元素都需要设置 Label,Label 应当为短语 如:点赞、收藏;

accessibilityValue:(可选)用于经常变化的标签数据类文案,例如 视频的点赞按钮的具体数值 (共 xxx 人);

accessibilityTraits:当元素作为一个无障碍焦点时,我们需要描述该焦点的类别,如按钮、已选中等。此时需要使用 Traits 对元素进行标记;

accessibilityHint:(可选)当元素标签无法明确指出动作结果的时候,应该给出一个提示;

accessibilityFrame:当元素的焦点过小,需要手动调整焦点到较大值的时候,可以使用 Frame

VoiceOver 会把这几个属性连接起来,一般情况朗读顺序为accessibilityLabel→accessibilityValue→accessibilityTraits→accessibilityHint。

特例:accessibilitytraits中包含UIAccessibilityTraitSelected则会在最前方朗读“已选定”。

调整焦点顺序

焦点顺序应该遵循 从左往右 & 从上到下。正常情况下,焦点的顺序与 SubViews 的顺序一致,我们无需手动置顶焦点顺序。如果焦点顺序出现问题,我们可以利用 UIAccessibilityContainer 来调整屏幕中焦点的顺序。

accessibilityElements:通过该属性,我们可以指定一个元素包含的所有无障碍子元素。UITableViewCell 中重设需要格外谨慎,可能会出现焦点循环问题。以下图为例,如果 C、D、E 是无障碍可视元素,通过如下设置我们就能使无障碍元素按照 D、E、C 的顺序来排列。

A.accessibilityElements = @[B, C]
B.accessibilityElements = @[D, E]
bfbcb78face0f98ab50d562f40ccfdcc.png

西瓜首页适配实战

下面以西瓜首页为示例,为大家演示无障碍的基础适配。

d2ce864e22dd42843a19e3437aaddd3a.png

以西瓜首页为例,自上而下我们主要有五个区域需要设置焦点。分别是 搜索栏、频道栏 & 频道编辑器、作者动态栏 (Story)、视频卡片 (卡片为一个焦点,用户通过转子进行其他操作)、底部 Tab 选择器。下面针对每个部分进行无障碍适配的解释。

搜索栏

searchBox.isAccessibilityElement = YES;
searchBox.accessibilityLabel = @"搜索框";
searchBox.accessibilityValue = @"热搜词1,第一座4万亿GDP的城市。热搜词2,南昌至台湾专列开通";
searchBox.accessibilityTraits = UIAccessibilityTraitSearchField;

频道栏 & 频道编辑器

/// 频道栏的无障碍适配
categoryCell.isAccessibilityElement = YES;
categoryCell.accessibilityLabel = @"推荐频道";
categoryCell.accessibilityVaule = @"热搜词1,第一座4万亿GDP的城市。热搜词2,南昌至台湾专列开通";
categoryCell.accessibilityHint = @"轻点两下切换首页频道";
/// 未选中时
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar;
/// 已选中时
categoryCell.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;

/// 频道编辑器的无障碍适配
// 如果面板是以addSubview的形式添加到界面上时,需要屏蔽底层元素的访问
@implementation categoryEditViewController

- (void)viewDidAppear {
    categoryEditView.accessibilityViewIsModal = YES;
    /// 使用户焦点移动到频道编辑面板上。
    UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, categoryEditView);
}

- (void)viewDidDisAppear {
    categoryEditView.accessibilityViewIsModal = NO;
}

@end

作者动态栏

storyCell.isAccessibilityElement = YES;
storyCell.accessibilityLabel = isLive ?  @"入江闪闪,正在直播" : @"入江闪闪";
storyCell.accessibilityHint = isLive ? @"轻点两下进入作者直播观看视频" : @"轻点两下进入作者视频列表播放视频";

@implementation storyCell
// TableView与CollectionView嵌套时,cell可能会出现无法自然滚动的问题。
- (void)accessibilityElementDidBecomeFocused {
    [self.collectionView scrollToIndexPath:self.indexPath];
}

@end

视频列表

videoCell.isAccessibilityElement = YES
videoCell.accessibilityLabel = [视频标题、作者名称、点赞数、收藏数、评论数等]
videoCell.accessibilityHint = @"轻点两下进入详情页播放视频,上下轻扫使用转子访问更多功能"

UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"点赞" target:self selector:@selector(action1)];
UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"收藏" target:self selector:@selector(action2)];
UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"更多" target:self selector:@selector(action3)];

videoCell.accessibilityCustomActions = @[action1,action2,action3];

四、Voice Over 相关协议介绍

UIAccessibility 无障碍标签标注

@interface NSObject (UIAccessibility)
/// 标记一个元素是否是无障碍元素
@property (nonatomic) BOOL isAccessibilityElement;
/// 标记一个元素的无障碍元素的简短描述 如 (点赞、收藏)
@property (nullable, nonatomic, copy) NSString *accessibilityLabel;
/// (可选)标记一个元素的无障碍元素的详细描述 如 (轻点两下与xxx人一起点赞,轻点两下将视频添加到收藏列表)
@property (nullable, nonatomic, copy) NSString *accessibilityHint;
/// (可选)标记一个元素的无障碍元素的具体值,如50%等
@property (nullable, nonatomic, copy) NSString *accessibilityValue;
/// (可选)标记一个元素的无障碍特征 如(按钮、标签夹等)
@property (nonatomic) UIAccessibilityTraits accessibilityTraits;
/// (可选)自定义一个元素的无障碍模式下的焦点大小
@property (nonatomic) CGRect accessibilityFrame;

@end

UIAccessibilityAction 无障碍手势响应

@interface NSObject (UIAccessibilityAction)

/// 自定义无障碍事件,可以使点击事件与普通用户隔离。
- (BOOL)accessibilityActivate API_AVAILABLE(ios(7.0));

/// 当元素被定义为可变元素时,可以实现下面的方法。如音量、亮度调节器。
- (void)accessibilityIncrement API_AVAILABLE(ios(4.0));
- (void)accessibilityDecrement API_AVAILABLE(ios(4.0));


- (BOOL)accessibilityScroll:(UIAccessibilityScrollDirection)direction API_AVAILABLE(ios(4.2));
/// 通常浮窗或页面需要实现该方法,实现该方法后用户可以使用“Z”字形手势退出页面
- (BOOL)accessibilityPerformEscape API_AVAILABLE(ios(5.0));
/// 该方法可以接收到用户的双指双击事件。可以用于弹出更多面板 or 定义一些重要操作如 暂停。
- (BOOL)accessibilityPerformMagicTap API_AVAILABLE(ios(6.0));

/// 转子的核心方法,给accessibilityCustomActions赋值后可以上下轻扫访问转子
@property (nullable, nonatomic, strong) NSArray <UIAccessibilityCustomAction *> *accessibilityCustomActions API_AVAILABLE(ios(8.0));
@end

UIAccessibilityFocus 无障碍焦点响应

@interface NSObject (UIAccessibilityFocus)

/// 焦点响应事件,可以捕获元素是否成为了焦点。通常重写这两个方法。
- (void)accessibilityElementDidBecomeFocused API_AVAILABLE(ios(4.0));
- (void)accessibilityElementDidLoseFocus API_AVAILABLE(ios(4.0));

/// 可以判断该元素是否被聚焦,通常不要处理该方法。
- (BOOL)accessibilityElementIsFocused API_AVAILABLE(ios(4.0));

@end

UIAccessibilityContainer 无障碍自定义焦点

@interface NSObject (UIAccessibilityContainer)

/// 返回当前容器无障碍元素的总数
- (NSInteger)accessibilityElementCount NS_SWIFT_UI_ACTOR;

/// 返回对应index的元素
/// 需要保证返回的是真实存在的实例(不能为alloc出来的)
- (nullable id)accessibilityElementAtIndex:(NSInteger)index NS_SWIFT_UI_ACTOR;

/// 返回对应元素的index
- (NSInteger)indexOfAccessibilityElement:(id)element NS_SWIFT_UI_ACTOR;
⚠️如果使用上面的三个方法,一般需要同时全部实现。
⚠️如果实现了上面的三个方法,那么就不要再手动设置accessibilityElements

/// 容器的无障碍元素List,设置后页面无障碍元素范围将会被限制在List内,顺序与List内元素顺序相同。
@property (nullable, nonatomic, strong) NSArray *accessibilityElements API_AVAILABLE(ios(8.0)) NS_SWIFT_UI_ACTOR;

/// default == UIAccessibilityContainerTypeNone,绝大多数情况保持None即可。如果手动设置Type则需要实现对于Type的指定协议。
@property (nonatomic) UIAccessibilityContainerType accessibilityContainerType API_AVAILABLE(ios(11.0)) NS_SWIFT_UI_ACTOR;

@end

五、常见问题与解决方案

该部分根据西瓜真实的业务实践,列举了数个常见无障碍问题的修复方案。例如:焦点目的不明确、焦点乱跳问题、嵌套容器 ScrollView 无法跟随滚动等。

焦点缺失/焦点冗余

焦点缺失是无障碍 Bug 中最基础但最严重的问题。极端情况情况下会产生致命的阻塞性的 Bug(如返回按钮缺失焦点)。通常而言产品上一些按钮、链接、勾选框、图片、编辑框等需要焦点方便用户交互。

此外焦点冗余也会严重影响用户的使用体验,一些装饰性元素焦点冗余后,用户的信息筛选效率会严重降低。通常而言,用户点击后无明确响应事件的组件不应该成为焦点。

「解决方法」:一般情况下,系统会自动给标准控件 UIButton 等交互控件添加焦点,其他自定义控件需要手动添加/更改。一般情况下手动指定属性isAccessibilityElement为 YES 或者 NO 可解决该问题。

self.isAccessibilityElement = YES;
self.accessibilityLabel = @"点赞";  // 通常焦点描述也会缺失,需要一并补充。

/// 对于一些自定义的UI控件,也可以重写上述两个对象的Get方法。
- (NSString *)accessibilityLabel {
    return @"点赞";
}

- (BOOL) isAccessibilityElement {
    return YES;
}

焦点过细/焦点合并

焦点合并指的是有相同目的、相同操作的,或具有组合意义的组合视图,焦点没有合并的情况,问题描述为“合并焦点”。例如,好友列表中的好友头像和昵称应合并为一个焦点,二者功能都一样,都是跳转到个人资料界面。

「解决方法」:在需要合并焦点的 superView 处将 isAccessibilityElement 设置为 YES。

self.isAccessibilityElement = YES;

焦点信息错误 (目的不明确,信息冗余等)

焦点目的不明确是指页面中的焦点仅朗读出基本文案,但是未朗读该控件的类型(按钮、标签栏、链接等),或者未朗读该焦点响应后会发生的事件(轻点两下进入详情页播放视频等)。

「解决方法」:参照产品的无障碍标注规范。调整问题焦点的 accessibilityLabel、accessibilityTraits、accessibilityHint 等字段,从而使焦点信息朗读准确。

/// Button
// 点赞按钮未被选中时
self.accessibilityTraits = UIAccessibilityTraitButton;
self.accessibilityHint = @"轻点两下与xxx人一同点赞";

// 点赞按钮被选中时
self.accessibilityTraits = UIAccessibilityTraitButton|UIAccessibilityTraitSelected;
self.accessibilityHint = @"轻点两下取消点赞";

///TabBar(包括顶Tab和底Tab)
// 当对象为TabBar
self.accessibilityTraits = UIAccessibilityTraitTabBar
// 被选中的TabBar
self.accessibilityTraits = UIAccessibilityTraitTabBar|UIAccessibilityTraitSelected;

焦点停留不当

页面刷新后跑焦点、对视图或控件进行操作后跑焦点,打开新界面焦点停留的位置不适当,问题描述为“焦点停留不当”。例如进入一些页面后,焦点默认停留在原位置,或者停留在新页面的返回按钮。

「解决方法」:在进入界面时将 VoiceOver 焦点定位到特定控件。可以使用UIAccessibilityPostNotification发送通知给特定控件,改变 voiceOver 焦点。

@implementation MyViewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];

UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification,
self.myFirstElement);
}
@end

焦点顺序错误问题

焦点顺序不符合逻辑顺序时,通常描述为:“焦点顺序不符合逻辑顺序”;焦点顺序不符合视觉顺序时,描述为“焦点顺序不符合视觉顺序”。

「解决方法」:手动设置 accessibilityElements。极端场景下可以主动实现 UIAccessibilityContainer 协议。

/// 普通场景. 切勿在TableView的Cell中使用

self.accessibilityElements = @[View1,View2,View3];

/// 复杂场景,务必将三个方法都实现,否则容易出现意料之外的问题

- (NSInteger)accessibilityElementCount {
    return 3;
}

- (nullable id)accessibilityElementAtIndex:(NSInteger)index {
    return Views[index];
}

- (NSInteger)indexOfAccessibilityElement:(id)element {
    return [Views indexOfObject:element];
}

焦点选中时乱跳问题

该问题主要发生在 CollectionView 上,一般现象为调整一个 Cell 的选中态并 reloadData,焦点会先转移到一个随机的位置(一般是选中 Cell 的后一个),而后再跳回正确的位置。

「解决方法」:慎用 UICollectionView、UITableView 的 reloadData。当需要刷新 Cell 的选中状态时,尽量自己实现一个 updateVisibleCell。reloadData 时会导致 Cell 随机复用,最终产生焦点乱跳的异常。

❌
[self reloadData];

✅
[self updateVisibleCells];

- (void)updateVisibleCells {
  NSArray<UICollectionViewCell *> *visibleCells = self.collectionView.visibleCells;
  [visibleCells enumerateObjectsUsingBlock:^(UICollectionViewCell * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
    // Todo something
  }];
}

浮窗问题 / 焦点被覆盖时仍可访问

在西瓜视频中,浮窗有多种不同的存在形式,如 XIGAlert(隐私弹窗等)、XIGToast(网络异常等)、半屏浮窗(键盘、清晰度面板、倍速面板等)。在弹窗出现时,用户可以通过左右滑动切换焦点至不可视的视图。这些视图产生的相关事件可能会使程序崩溃,发生一些意料之外的事情。

「解决方法」:一般做法为让底层控件元素失去焦点来达到屏蔽底层元素的效果,将灰色变暗区域设为单个大焦点,标签设为 “关闭” 或 “收起” 等提示,双击可关闭浮层。弹窗或弹层时,自动使上层容器的第一控件(如标题或通知内容)获取焦点,视障用户无须二次切换焦点,更符合视障用户使用体验,更加体现人性化。

self.accessibilityViewIsModal = YES

对蒙层设置属性,会使蒙层的同级 view不响应 VoiceOver,而蒙层的子 view 可响应。如下图所示,如果希望 E 可以被访问,CD 不可被访问,此时需要设置 B 的accessibilityViewIsModal为 YES。

07e1180241466361ecd7b13a9b29c836.png

嵌套容器 ScrollView 无法跟随滚动问题

在 UICollectionView 中,嵌套一个 UIScrollView 或者 UITableView,焦点在 TableView、ScrollView 中滑动时,不会发生自动滚动,从而导致页面发生白屏等现象。

「解决方法」:使用 accessibilityActivate,在焦点聚焦到一个 Cell 上的时候,手动调用scrollToRowAtIndexPath: atScrollPosition: animated:如果一个 Cell 中包含多个功能,Cell 还需要进行转子适配。

- (BOOL)accessibilityElementDidBecomeFocused {
   [self.tableview scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:NO];

   return YES;
}

横滑拖拽问题(手势替代问题)

在应用中有许多场景有横滑手势,如横滑删除,横滑编辑等。此类事件在 Voice Over 开启时无法被响应。故需要通过一些其他手段使用户能够访问到横滑的功能。

「解决方法」:使用转子对功能进行改造。

UIAccessibilityCustomAction * action1 = [[UIAccessibilityCustomAction alloc] initWithName:@"进入详情页" target:self selector:@selector(action1)];
UIAccessibilityCustomAction * action2 = [[UIAccessibilityCustomAction alloc] initWithName:@"删除该视频" target:self selector:@selector(action2)];
UIAccessibilityCustomAction * action3 = [[UIAccessibilityCustomAction alloc] initWithName:@"隐藏该视频" target:self selector:@selector(action3)];

self.accessibilityCustomActions = @[action1,action2,action3];
‍

‍加入我们

西瓜视频是一个开眼界、涨知识的视频 App,作为国内领先的中视频平台,它源源不断地为不同人群提供优质内容,让人们看到更丰富和有深度的世界,点亮对生活的好奇心。在这里你将会负责西瓜视频的产品研发与相关架构工作,服务千万用户,打造极致的视听体验。同时客户端团队技术实力强,有多款业内知名的开源项目,在这里你也能收获颇多,共同成长。欢迎大家加入我们!

点击文末阅读原文,进入字节跳动招聘官网查询【西瓜客户端研发工程师】相关职位,也可以直接邮件联系 chenjunlin.innovate@bytedance.com 咨询相关信息~‍

‍

6655516a63c38216f9bb4fdaa285c779.png 点击“阅读原文”了解岗位详情!

相关推荐

2024 抖音欢笑中国年(五):Wasm、WebGL 在互动技术中的创新应用

前言随着 Web 前端技术的不断发展,越来越多的新兴技术方案被引入到 Web 开发中,其中 Wasm 和 WebGL 作为前端领域的两大利器,为开发者带来了更多的可能性。本文将结合2024 年抖音欢笑中国年的部分项目,重点介绍如何利用 Wasm 和 WebGL 对目前流行的一些前端互动技术(比如 Lottie、渲染引擎、动画图片等)进行创新和实践,利用 Wasm 和 WebGL 等新技术方案的特性...

字节跳动技术团队官方博客 2万+

2024 抖音欢笑中国年(四):渲染技术实践与探索

作者:陈瑞、欧阳浩铸、王武俊、倪梵云前言抖音在2024年春节期间推出了欢笑中国年系列活动,为用户带来了全新的体验和乐趣。而SAR Creator则为该项目研发工作提供了重要的技术支持。SAR Creator是一款基于 Typescript 的高性能、轻量化的互动解决方案,目前支持了浏览器和跨端框架平台,服务于字节内部的各种互动业务。这些绚烂多彩的互动场景当然也离不开实时渲染技术的支持,因此本文将专...

字节跳动技术团队官方博客 2万+

2024 抖音欢笑中国年(三):编辑器技巧与实践

前言本次春节活动中,我们大部分场景使用内部的 SAR Creator互动方案来实现。SAR Creator 是一款基于 TypeScript 的高性能、轻量化的互动解决方案,目前支持了Web和字节内部跨端框架平台,服务于字节内部的各种互动业务,包括但不限于抖音春节、抖音直播礼物、抖音UG活动等。SAR Creator 编辑器支持了图形化界面,提供了各类完善的系统(光照、动画、脚本等)供用户快速便捷...

字节跳动技术团队官方博客 1万+

2024 抖音欢笑中国年(二):AnnieX互动容器创新玩法解析

本文基于24年抖音春节活动业务背景,介绍了字节跨端容器AnnieX在游戏互动套件上的探索,致力于提升容器在游戏互动场景的优化能力。业务背景AnnieX作为字节一方游戏统一容器,服务字节内部电商、直播、UG等跨端场景业务。在字节一方游戏互动场景,有大量的一方游戏业务对容器有特定的流量、端能力和游戏优化的诉求。因此我们不断深入互动游戏业务特点,为字节游戏提供完善游戏端能力和流量运营能力,同时提供游戏互...

字节跳动技术团队官方博客 1万+

2024 抖音欢笑中国年(一):招财神龙互动技术揭秘

字节跳动旗下的抖音等 App 在 2024 年春节期间推出了欢笑中国年系列活动,在实现增长业务目标的同时,为用户带来了全新的体验和乐趣。「招财神龙」是其中的一个重要玩法。前言本次春节活动,使用到了字节内的主要前端、跨端、互动技术产品。主要涉及:跨端框架提供了首屏直出的方案使其具有较短的首屏时间,能够大大提升业务加载成功率。跨端框架也提供了 Canvas 作为 SAR Creator 等渲染引擎的...

字节跳动技术团队官方博客 1万+

Monorepo 解决方案 — 基于 Bazel 的 Xcode 性能优化实践

背景介绍书接上回《Monorepo 解决方案 — Bazel 在头条 iOS 的实践》,在头条工程切换至 Bazel 构建系统后,为了支持用户使用 Xcode 开发的习惯,我们使用了开源项目 Tulsi 作为生成工具,用于将 Bazel 工程转换为 Xcode 工程。但是在使用的过程中,我们发现了一些问题,其中影响较大的是,Xcode 工程卡顿:对于头条这种大型项目来说,Xcode 卡顿一直是本地...

字节跳动技术团队官方博客 1万+

抖音 ANR 自动归因平台建设实践

背景介绍本文在 2024 年初最新一期『抖音客户端基础技术大揭秘』技术沙龙活动中已做过专题分享,本次将内容重新整理文章进行分享。公众号后台回复技术沙龙可查看沙龙回放及 PPT~抖音作为一个超大型的应用,我们在 ANR 问题治理上面临着很大的挑战。首先对于存量问题的优化,由于缺少有效的归因手段,一些长期的疑难问题一直难以突破解决,例如长期位于 Top 1 的 nativePollOnce 问题。同时...

字节跳动技术团队官方博客 2万+

CVPR 2024 | CAMixerSR 动态注意力分配的超分辨率加速框架

背景随着相关技术和应用的发展,比如超高清屏幕、虚拟现实(VR)等沉浸式体验的增加,用户对超高分辨率图像和视频的需求变得越来越强烈。在这些场景中,图像的质量和清晰度对于提供最佳的用户体验至关重要。超高分辨率不仅能提供更清晰、更真实的视觉效果,还能在一定程度上增强人们的互动和沉浸感,在一些VR场景中我们需要8K甚至16K的才可以满足需求。然而要生成或者处理这些超高分辨率的内容,对算力的要求也是与日增长...

字节跳动技术团队官方博客 1万+

CVPR 2024 | Modular Blind Video Quality Assessment:模块化无参视频质量评估

无参视频质量评估 (Blind Video Quality Assessment,BVQA) 在评估和改善各种视频平台并服务用户的观看体验方面发挥着关键作用。当前基于深度学习的模型主要以下采样/局部块采样的形式分析视频内容,而忽视了实际空域分辨率和时域帧率对视频质量的影响,随着高分辨率和高帧率视频投稿逐渐普及,特别是跨分辨率/帧率视频转码档位画质评估场景中,这种影响变得更加不可忽视。在本文中,我们...

字节跳动技术团队官方博客 1万+

2024 AI & 前端:回首展望,光芒未至,破晓之前!

前言回望 2023 年,ChatGPT 的突然爆火,让 AI 无疑成为最为值得注目的新兴领域之一,我们也一起见证了生成式 AI 的寒武纪大爆发。这一年来,国内外的生成式 AI 、大模型和相关产品以令人眼花缭乱的速度更新迭代,新的创业浪潮风起云涌。在这 AI 浪潮下,也让我们有了新的开发思考,探索着在各个环节中“前端 & AI”的应用场景。勇于探索的前端开发者们已经开始挥舞着 AI 的“魔法...

字节跳动技术团队官方博客 1万+

Kotlin 云端差分缓存技术

本文由字节跳动 Buildinfra 团队出品。在我们的工程上线 Monorepo 全源码后,Kotlin 编译成了整个编译中最耗时的步骤,全源码过程中大量的 BuildCache Miss 导致我们的编译数据落后原来多仓二进制时代很多,且业界没有相关的解决方案。本篇文章我们来具体阐述下 BuildInfra 团队自研的解决方案 - Kotlin 云端差分方案的原理和技术实现。一、Monorepo...

字节跳动技术团队官方博客 1万+

字节跳动基础架构SRE-Copilot获得2023 CCF国际AIOps挑战赛冠军

近日,2023 CCF国际AIOps挑战赛决赛暨“大模型时代的AIOps”研讨会在北京成功举办,活动吸引了来自互联网、运营商、科研院所、高校、软硬件厂商等领域多名专家学者参与,为智能运维的前沿学术研究、落地生产实践打开了新思路。决赛中,从初赛两百多支队伍中脱颖而出的十支入围队伍分别展示了各自的方案,并进行了现场答辩,评审专家从选题方向、创新性、实用性、完整度和实验复现结果等多角度进行了综合评定,最...

字节跳动技术团队官方博客 2万+

字节跳动百万级Metrics Agent性能优化的探索与实践

背景metricserver2 (以下简称Agent)是与字节内场时序数据库 ByteTSD 配套使用的用户指标打点 Agent,用于在物理机粒度收集用户的指标打点数据,在字节内几乎所有的服务节点上均有部署集成,装机量达到百万以上。此外Agent需要负责打点数据的解析、聚合、压缩、协议转换和发送,属于CPU和Mem密集的服务。两者结合,使得Agent在监控全链路服务成本中占比达到70%以上,对Ag...

字节跳动技术团队官方博客 1万+

西瓜视频RenderThread引起的闪退问题攻坚历程

背景影响西瓜之前存在过一类RenderThread闪退,从堆栈上看,全部都是系统so调用,给人的第一印象像是一个系统bug,无从下手。闪退集中在Android 5~6上,表现为打开直播间立即闪退。该问题在2022年占据Native Crash Top5,2023年更是上升到到Top1。因此有必要投入时间和精力再重新审视一下这个问题。在历经多周的源码分析和排查后,逐步明确了问题根因并修复,最终取得了...

字节跳动技术团队官方博客 2万+

字节电商双11 大促容量保障是如何做的?

前言Rhino 简介Rhino是字节自研全链路容量评估产品,致力于构建完整的全链路容量评估解决方案(覆盖:容量预估->资源准备->数据准备->容量验证->监控->分析->决策->处理反馈);围绕容量在稳定性、成本、效率 三方面提供业务全方位基础支撑。Rhino 目前已经成为字节各业务容量评估主流解决方案,并且历年来在业务大型活动稳定性保障中(抖音春节项目、...

字节跳动技术团队官方博客 10万+

使用火山引擎 APMPlus 解决抖音Top 1 Java 崩溃的通用优化方案

背景近3个月,抖音 Android 版面临一个多次触发线上报警的崩溃问题,全量版本和灰度版本的异常数据激增,该问题不仅容易触发报警,更成为了 Java Top 1 崩溃问题,带来巨大困扰,急需攻坚解决。本文展现了具体的分析过程、优化思路和解决方案,同时提供了已集成该方案的实用工具。初步分析多维特征我们以某发版期间数据为例进行分析:机型方面:比较分散,有聚集部分samsung sm-s9180 占比...

字节跳动技术团队官方博客 2万+

用 Addon 增强 Node.js 和 Electron 应用的原生能力

前言Node.js Addon 是 Node.js 中为 JavaScript 环境提供 C/C++ 交互能力的机制。其形态十分类似 Java 的 JNI,都是通过提供一套 C/C++ SDK,用于在 C/C++ 中创建函数方法、进行数据转换,以便 JavaScript / Java 等语言进行调用。这样编写的代码通常叫做 Bindings。此外还有基于 C ABI Calling Convent...

字节跳动技术团队官方博客 2万+

火山引擎 ByteHouse 的增强型数据导入技术实践

作为企业数字化建设的必备要素,易用的数据引擎能帮助企业提升数据使用效率,更好提升数据应用价值,夯实数字化建设基础。数据导入是衡量OLAP引擎性能及易用性的重要标准之一,高效的数据导入能力能够加速数据实时处理和分析的效率。作为一款OLAP引擎,火山引擎云原生数据仓库ByteHouse源于开源ClickHouse,在字节跳动多年打磨下,提供更丰富的能力和更强性能,能为用户带来极速分析体验,支撑实时数据...

字节跳动技术团队官方博客 1万+

打造企业级智能问答系统的秘密:如何使用云数据库 PostgreSQL 版实现向量检索

本文就如何利用火山引擎云数据库 PostgreSQL 版和大语言模型技术(Large Language Model,简称 LLM),实现企业级智能交互式问答系统进行介绍。通过本文,你将会了解交互式问答系统的原理,学习 PostgreSQL 的向量化存储和检索技术,以及大语言模型交互技术等。背景在大数据的浪潮下,众多企业建立了自己的知识库,以便于信息检索和知识查询。然而,随着知识库内容的膨胀,传统的...

字节跳动技术团队官方博客 2万+

抖音大型直播的画质优化实践

面临挑战随着抖音内容生态的不断丰富,越来越多的大型赛事在抖音平台进行直播,世界杯/春晚/亚运会等各项赛事节目引来大量用户观看。卡塔尔世界杯期间,抖音提供的稳定高质直播画面为观众带来了完美的观赛体验,决赛的 PCU 高达 3700W+。不同赛事节目涉及链路众多,且不同赛事之间存在差异,如何保障各链路的画质稳定并进一步提升画质,是一个巨大的挑战。如何应对挑战?画质优化链路大型赛事直播涉及链路较长,不同...

字节跳动技术团队官方博客 2万+

抖音直播新一代BVC编码器正式亮相

面临挑战在直播行业发展如火如荼的今天,用户对视频体验的要求也水涨船高。视频基础体验的关键要素包括清晰度、流畅度、低延迟等,而这些要素的“第一性原理”,就是视频本身的编码效率,也就是压缩率。视频编码是整个技术体系的基座,编码效率的显著提升,能够在同等码率下极大提高画质,从而改善用户体验。视频编码效率的重要性不言而喻,但进一步地提升也并非易事,尤其在直播场景中,对编码速度、延迟、码率控制等方面都有很高...

字节跳动技术团队官方博客 7356

Go Metrics SDK Tag 校验性能优化实践

背景Metrics SDK 是与字节内场时序数据库 ByteTSD 配套的用户指标打点 SDK,在字节内数十万服务中集成,应用广泛,因此 SDK 的性能优化是个重要和持续性的话题。本文主要以 Go Metrics SDK 为例,讲述对打点 API 的 hot-path 优化的实践。用户在使用 SDK API 进行打点时,需要传入指标对应的 Tag:tags:=[]m.T{{Name:"foo...

字节跳动技术团队官方博客 1万+

云上智能驾驶三维重建最佳实践

智能驾驶技术的不断发展,正在改变着我们的出行方式和交通系统。作为其中的一个关键技术,三维重建在智能驾驶系统中起着重要的作用。除去车端本身的感知、重建算法,自动驾驶技术的落地与发展需要庞大的云端重建能力支撑,火山引擎多媒体实验室通过行业领先的自研三维重建技术,结合强大的云平台资源与能力,助力相关技术在云端大规模重建、自动标注、真实感仿真等场景的落地与应用。本文重点介绍火山引擎多媒体实验室三维重建技术...

字节跳动技术团队官方博客 6305

火山引擎实时、低延时拥塞控制算法的优化实践

摘要火山引擎智能拥塞控制算法 VICC(Volcano Intelligent Congestion Control)是一种自适应的拥塞控制算法,旨在解决全球不同网络环境下,不同音视频应用对带宽利用率和延时的差异化要求。它结合了传统拥塞控制算法(如 GCC 和 BBR)的优点,并且能够根据不同的网络条件、业务偏好和码率特征进行自适应调整,包括自适应拥塞响应速度、自适应带宽探测幅度、自适应丢包检测策...

字节跳动技术团队官方博客 6735

veImageX 演进之路:Web 图片加载提速50%

背景说明火山引擎veImageX演进之路主要介绍了veImageX在字节内部从2012年随着字节成长过程中逐步演进的过程,演进中包括V1、V2、V3版本并最终面向行业输出;整个演进过程中包括服务端、客户端、网络库、业务场景与优化等多个角度介绍在图像处理压缩、省成本与体验优化的经验与方案;本篇文章重点介绍在web端演进和提供的能力,图片是 Web 站点中的重要元素,图片体积、格式、分辨率以及渲染方式...

字节跳动技术团队官方博客 6589

自研多模态追踪算法 PICO 为「手柄小型化」找到新思路

作者:张韬、林泽一 、闻超 、赵洋研发背景作为头戴的追踪配件,VR手柄可以通过HMD(头戴显示设备)的inside-out光学追踪定位原理,计算出手柄的空间运动轨迹,同时结合6轴传感器实现6DoF空间定位。与此同时,结合手柄控制器的物理按键、马达反馈、摇杆等,用户还能获得逼真、细腻的触觉反馈,进一步增强虚拟现实人机交互的能力以及沉浸感,这也是目前无手柄方案所难以实现的。目前主流VR手柄的追踪技术方...

字节跳动技术团队官方博客 7818

如何利用播放器节省20%点播成本

点播成本节省的点其实涉及诸多部分,例如:CDN、转码、存储等,而利用播放器降本却是很多客户比较陌生的部分。火山引擎基于内部支撑抖音集团相关业务的实践,播放器恰恰是成本优化中最重要和最为依赖的部分。火山引擎的视频团队做了份数据统计,在一个很经典的视频业务中,我们在2022年至2023年大约1年半的时间里,针对这个业务进行了33次成本优化点,其中13次是播放器主导的优化,其余的有12次也是需要播放器强...

字节跳动技术团队官方博客 6176

火山引擎 ByteHouse:ClickHouse 如何保证海量数据一致性

背景ClickHouse是一个开源的OLAP引擎,不仅被全球开发者广泛使用,在字节各个应用场景中也可以看到它的身影。基于高性能、分布式特点,ClickHouse可以满足大规模数据的分析和查询需求,因此字节研发团队以开源ClickHouse为基础,推出火山引擎云原生数据仓库ByteHouse。在日常工作中,研发人员经常会遇到业务链路过长,导致流程稳定性和数据一致性难保障的问题,这在分布式、跨服务的场...

字节跳动技术团队官方博客 6900

抖音集团都在用的画质评估工具,确定不试试吗?

导读本文从抖音集团内部画质评估体系的建设历程着笔,主要分享了画质评测对于业务的重要性、主要应用场景和内部产品的一些典型实践案例。通过分享业务视角遇到的一些问题和我们的解决思路,希望能抛砖引玉,为遇到类似困扰的伙伴们提供有价值的参考。画质评估体系建设历程为何评测画质如此重要?我们通过线上业务大量实验发现,图片画质优劣对点击率、 停留时长等消费类指标有正相关影响,间接影响用户收益指标。因此,建设一套行...

字节跳动技术团队官方博客 7940

VLDB 2023 | CDSBen: 字节跳动 veDB 数据库存储系统性能测试模型

背景随着业务爆炸式增长与云原生技术的日渐成熟,大量云原生分布式数据库产品如雨后春笋般涌现,其中一部分主打 OLTP 场景的分布式数据库强调的是从计算-存储分离架构获得弹性收益;对于业界各种计算-存储分离架构的数据库而言,怎么用真实的端到端数据库 workload 去 benchmark 其底层存储系统一直存在以下难题:对于数据库专用存储系统,不存在如 fio 一样的“事实标准” benchmark...

字节跳动技术团队官方博客 5896
上一篇: 一文了解字节跳动如何解决 SLA 治理难题
下一篇: 字节跳动自研高性能微服务框架 Kitex 的演进之旅
 字节跳动技术团队
字节跳动技术团队 企业官方账号 企业官方账号
博客等级 码龄7年 8153粉丝 316原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值