Компонент навигации обеспечивает поддержку приложений Jetpack Compose. Вы можете перемещаться между составными объектами, используя преимущества инфраструктуры и функций компонента навигации.
Настраивать
Для поддержки Compose используйте следующую зависимость в файле build.gradle
вашего модуля приложения:
dependencies { def nav_version = "2.8.8" implementation "androidx.navigation:navigation-compose:$nav_version" }
dependencies { val nav_version = "2.8.8" implementation("androidx.navigation:navigation-compose:$nav_version") }
Начать
При реализации навигации в приложении реализуйте хост навигации, график и контроллер. Дополнительную информацию см. в разделе Обзор навигации .
Создайте NavController
Информацию о том, как создать NavController
в Compose, см. в разделе «Создание» статьи «Создание контроллера навигации» .
Создать NavHost
Информацию о том, как создать NavHost
в Compose, см. в разделе «Создание» статьи «Создание навигационного графа» .
Перейдите к составному элементу
Информацию о переходе к составному объекту см. в разделе «Навигация к месту назначения» документации по архитектуре.
Навигация с аргументами
Информацию о передаче аргументов между составными пунктами назначения см. в разделе «Создание» статьи «Создание навигационного графа» .
Получение сложных данных при навигации
Настоятельно рекомендуется не передавать сложные объекты данных при навигации, а вместо этого передавать минимально необходимую информацию, например уникальный идентификатор или другую форму идентификатора, в качестве аргументов при выполнении действий навигации:
// Pass only the user ID when navigating to a new destination as argument
navController.navigate(Profile(id = "user1234"))
Сложные объекты должны храниться как данные в одном источнике достоверности, например на уровне данных. Как только вы приземлитесь в пункте назначения после навигации, вы сможете загрузить необходимую информацию из единого источника истины, используя переданный идентификатор. Чтобы получить аргументы в вашей ViewModel
, отвечающие за доступ к уровню данных, используйте SavedStateHandle
ViewModel
:
class UserViewModel(
savedStateHandle: SavedStateHandle,
private val userInfoRepository: UserInfoRepository
) : ViewModel() {
private val profile = savedStateHandle.toRoute<Profile>()
// Fetch the relevant user information from the data layer,
// ie. userInfoRepository, based on the passed userId argument
private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
// …
}
Этот подход помогает предотвратить потерю данных во время изменений конфигурации и любые несоответствия при обновлении или мутации рассматриваемого объекта.
Более подробное объяснение того, почему следует избегать передачи сложных данных в качестве аргументов, а также список поддерживаемых типов аргументов см. в разделе Передача данных между пунктами назначения .
Глубокие ссылки
Navigation Compose поддерживает глубокие ссылки, которые также можно определить как часть функции composable()
. Его параметр deepLinks
принимает список объектов NavDeepLink
, которые можно быстро создать с помощью метода navDeepLink()
:
@Serializable data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
deepLinks = listOf(
navDeepLink<Profile>(basePath = "$uri/profile")
)
) { backStackEntry ->
ProfileScreen(id = backStackEntry.toRoute<Profile>().id)
}
Эти глубокие ссылки позволяют связать определенный URL-адрес, действие или тип MIME с составным объектом. По умолчанию эти глубокие ссылки не доступны внешним приложениям. Чтобы сделать эти глубокие ссылки доступными извне, необходимо добавить соответствующие элементы <intent-filter>
в файл manifest.xml
. Чтобы включить глубокую ссылку в предыдущем примере, вам следует добавить следующее внутрь элемента <activity>
манифеста:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
Автоматическая навигация по глубоким ссылкам на этот компонуемый объект, когда глубокая ссылка активируется другим приложением.
Эти же глубокие ссылки также можно использовать для создания PendingIntent
с соответствующей глубокой ссылкой из составного объекта:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/profile/$id".toUri(),
context,
MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
Затем вы можете использовать этот deepLinkPendingIntent
, как и любой другой PendingIntent
, чтобы открыть свое приложение в месте назначения глубокой ссылки.
Вложенная навигация
Информацию о том, как создавать вложенные графики навигации, см. в разделе Вложенные графики .
Интеграция с нижней панелью навигации
Определив NavController
на более высоком уровне в составной иерархии, вы можете соединить навигацию с другими компонентами, такими как нижний компонент навигации. Это позволит вам перемещаться, выбирая значки на нижней панели.
Чтобы использовать компоненты BottomNavigation
и BottomNavigationItem
, добавьте зависимость androidx.compose.material
в свое приложение Android.
dependencies { implementation "androidx.compose.material:material:1.7.5" } android { buildFeatures { compose true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
dependencies { implementation("androidx.compose.material:material:1.7.5") } android { buildFeatures { compose = true } composeOptions { kotlinCompilerExtensionVersion = "1.5.15" } kotlinOptions { jvmTarget = "1.8" } }
Чтобы связать элементы нижней панели навигации с маршрутами в графе навигации, рекомендуется определить класс, например TopLevelRoute
показанный здесь, который имеет класс маршрута и значок.
data class TopLevelRoute<T : Any>(val name: String, val route: T, val icon: ImageVector)
Затем поместите эти маршруты в список, который может использоваться BottomNavigationItem
:
val topLevelRoutes = listOf(
TopLevelRoute("Profile", Profile, Icons.Profile),
TopLevelRoute("Friends", Friends, Icons.Friends)
)
В компонуемом элементе BottomNavigation
получите текущий NavBackStackEntry
с помощью функции currentBackStackEntryAsState()
. Эта запись дает вам доступ к текущему NavDestination
. Затем выбранное состояние каждого BottomNavigationItem
можно определить путем сравнения маршрута элемента с маршрутом текущего пункта назначения и его родительских пунктов назначения для обработки случаев, когда вы используете вложенную навигацию с использованием иерархии NavDestination
.
Маршрут элемента также используется для подключения лямбды onClick
к вызову navigate
, чтобы нажатие на элемент переходило к этому элементу. При использовании флагов saveState
и restoreState
состояние и задний стек этого элемента правильно сохраняются и восстанавливаются при переключении между элементами нижней навигации.
val navController = rememberNavController()
Scaffold(
bottomBar = {
BottomNavigation {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentDestination = navBackStackEntry?.destination
topLevelRoutes.forEach { topLevelRoute ->
BottomNavigationItem(
icon = { Icon(topLevelRoute.icon, contentDescription = topLevelRoute.name) },
label = { Text(topLevelRoute.name) },
selected = currentDestination?.hierarchy?.any { it.hasRoute(topLevelRoute.route::class) } == true,
onClick = {
navController.navigate(topLevelRoute.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
popUpTo(navController.graph.findStartDestination().id) {
saveState = true
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
}
)
}
}
}
) { innerPadding ->
NavHost(navController, startDestination = Profile, Modifier.padding(innerPadding)) {
composable<Profile> { ProfileScreen(...) }
composable<Friends> { FriendsScreen(...) }
}
}
Здесь вы воспользуетесь методом NavController.currentBackStackEntryAsState()
чтобы поднять состояние navController
из функции NavHost
и поделиться им с компонентом BottomNavigation
. Это означает, что BottomNavigation
автоматически получает самое актуальное состояние.
Совместимость
Если вы хотите использовать компонент навигации с Compose, у вас есть два варианта:
- Определите граф навигации с помощью компонента «Навигация» для фрагментов.
- Определите граф навигации с помощью
NavHost
в Compose, используя пункты назначения Compose. Это возможно только в том случае, если все экраны навигационного графа являются составными.
Поэтому для смешанных приложений Compose и Views рекомендуется использовать компонент навигации на основе фрагментов. Затем фрагменты будут содержать экраны на основе просмотра, экраны создания и экраны, использующие как представления, так и создание. Как только содержимое каждого фрагмента окажется в Compose, следующим шагом будет объединение всех этих экранов вместе с помощью Navigation Compose и удаление всех фрагментов.
Переход от создания с помощью навигации по фрагментам
Чтобы изменить пункты назначения внутри кода Compose, вы предоставляете события, которые могут быть переданы и запущены любым компонуемым объектом в иерархии:
@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
В своем фрагменте вы создаете мост между Compose и компонентом навигации на основе фрагментов, находя NavController
и переходя к месту назначения:
override fun onCreateView( /* ... */ ) {
setContent {
MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
}
}
Альтернативно вы можете передать NavController
вниз по иерархии Compose. Однако предоставление простых функций гораздо более пригодно для повторного использования и тестирования.
Тестирование
Отделите код навигации от составных пунктов назначения, чтобы можно было тестировать каждый составной объект изолированно, отдельно от составного объекта NavHost
.
Это означает, что вам не следует передавать navController
непосредственно в любой компонуемый объект , а вместо этого передавать обратные вызовы навигации в качестве параметров. Это позволяет индивидуально тестировать все ваши составные элементы, поскольку для них не требуется экземпляр navController
в тестах.
Уровень косвенности, обеспечиваемый composable
лямбдой, позволяет вам отделить код навигации от самого составного объекта. Это работает в двух направлениях:
- Передавайте в компонуемый объект только проанализированные аргументы.
- Передавайте лямбды, которые должны запускаться компонуемым объектом для навигации, а не самим
NavController
.
Например, компонуемый ProfileScreen
, который принимает userId
в качестве входных данных и позволяет пользователям переходить на страницу профиля друга, может иметь подпись:
@Composable
fun ProfileScreen(
userId: String,
navigateToFriendProfile: (friendUserId: String) -> Unit
) {
…
}
Таким образом, компонуемый ProfileScreen
работает независимо от навигации, что позволяет тестировать его независимо. composable
лямбда-выражение будет инкапсулировать минимальную логику, необходимую для устранения разрыва между API навигации и вашим компонуемым объектом:
@Serializable data class Profile(id: String)
composable<Profile> { backStackEntry ->
val profile = backStackEntry.toRoute<Profile>()
ProfileScreen(userId = profile.id) { friendUserId ->
navController.navigate(route = Profile(id = friendUserId))
}
}
Рекомендуется писать тесты, которые охватывают требования к навигации вашего приложения, проверяя NavHost
, действия навигации, передаваемые в ваши составные элементы, а также ваши отдельные составные элементы экрана.
Тестирование NavHost
Чтобы начать тестирование вашего NavHost
, добавьте следующую зависимость тестирования навигации:
dependencies {
// ...
androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
// ...
}
Оберните NavHost
вашего приложения в составной элемент, который принимает NavHostController
в качестве параметра.
@Composable
fun AppNavHost(navController: NavHostController){
NavHost(navController = navController){ ... }
}
Теперь вы можете протестировать AppNavHost
и всю логику навигации, определенную внутри NavHost
, передав экземпляр артефакта тестирования навигации TestNavHostController
. Тест пользовательского интерфейса, проверяющий начальный пункт назначения вашего приложения и NavHost
будет выглядеть следующим образом:
class NavigationTest {
@get:Rule
val composeTestRule = createComposeRule()
lateinit var navController: TestNavHostController
@Before
fun setupAppNavHost() {
composeTestRule.setContent {
navController = TestNavHostController(LocalContext.current)
navController.navigatorProvider.addNavigator(ComposeNavigator())
AppNavHost(navController = navController)
}
}
// Unit test
@Test
fun appNavHost_verifyStartDestination() {
composeTestRule
.onNodeWithContentDescription("Start Screen")
.assertIsDisplayed()
}
}
Тестирование действий навигации
Вы можете протестировать реализацию навигации несколькими способами: щелкнув элементы пользовательского интерфейса, а затем либо проверив отображаемый пункт назначения, либо сравнив ожидаемый маршрут с текущим маршрутом.
Поскольку вы хотите протестировать реализацию конкретного приложения, предпочтительным является нажатие на пользовательский интерфейс. Чтобы узнать, как протестировать это вместе с отдельными составными функциями изолированно, обязательно ознакомьтесь с кодовой лабораторией «Тестирование в Jetpack Compose» .
Вы также можете использовать navController
для проверки своих утверждений, сравнивая текущий маршрут с ожидаемым, используя currentBackStackEntry
navController
:
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
composeTestRule.onNodeWithContentDescription("All Profiles")
.performScrollTo()
.performClick()
assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}
Дополнительные рекомендации по основам тестирования Compose см. в разделах Тестирование макета Compose и лаборатории тестирования Compose в Jetpack . Чтобы узнать больше о расширенном тестировании кода навигации, посетите руководство по тестированию навигации .
Узнать больше
Дополнительные сведения о навигации Jetpack см. в разделе Начало работы с компонентом навигации или воспользуйтесь лабораторной работой по написанию кода Jetpack Compose Navigation .
Чтобы узнать, как спроектировать навигацию вашего приложения так, чтобы она адаптировалась к различным размерам, ориентациям и форм-факторам экрана, см. раздел «Навигация для адаптивных пользовательских интерфейсов» .
Чтобы узнать о более продвинутой реализации навигации Compose в модульном приложении, включая такие концепции, как вложенные графики и интеграция нижней панели навигации, ознакомьтесь с приложением Now in Android на GitHub.
Образцы
Mir 2: Return of the King 是 Actoz Soft 授权的优质《传奇》IP 移动游戏,由 HK ZHILI YAOAN LIMITED 使用 Unity 游戏引擎开发。 这款游戏不仅完美再现了韩国奇幻类 MMORPG 的代表作 Mir 2 的游戏氛围,还提供了许多最受欢迎的游戏内容,例如装备收集、大规模沙漠攻击和其他核心玩法。 该游戏使用了 Android Frame Pacing 库 (Swappy) 来提高帧速率的稳定性、实现流畅的渲染,并显著提升了 Android 鸣潮 是一款由 Kuro Games 开发的高保真动作角色扮演游戏。为了持续为长时间的游戏会话提供卓越的用户体验,优化功耗非常重要。 Android Studio 从 Hedgehog (2023.1.1) 开始引入了 功耗性能分析器 ,可帮助开发者根据设备端电源轨监视器 (ODPM) 了解功耗数据。 借助 Android Studio 中的功耗性能分析功能,您还可以 有效地对 Android 应用功能的功耗进行 A/B 测试 (如下所示)。 Kuro Games 首先使用 Android Godot Engine 是一个广受欢迎的多平台开源游戏引擎,对 Android 提供强大的支持。Godot 可用于制作几乎任何类型的游戏,并且支持 2D 和 3D 图形。Godot 4 版引入了新的渲染系统,该系统具有用于高保真图形的高级功能。Godot 4 渲染程序专为 Vulkan 等现代图形 API 而设计。 Godot Foundation 聘请了 The Forge Interactive 的图形优化专家,并与 Google 合作分析和进一步改进了 Godot 4 Vulkan Android 动态性能框架 (ADPF) 是 Google 推出的一款强大工具,适用于希望优化应用性能的开发者。ADPF 通过其热管理 API 提供有关设备热状态的实时信息,这些信息随后用于调整应用中的图形设置。 出于研究目的,Arm 使用 Unreal Engine 和 ADPF 开发了一个演示版,以研究如何使用 ADPF 优化游戏性能。 ADPF 会监控热状态,并相应地在游戏引擎中调整图形质量。 NCSoft《天堂 W》是由 NCSoft 开发的大型多人在线角色扮演游戏 (MMORPG)。这款游戏继承了原始 Lineage W 游戏的传统,为世界各地的玩家提供了一个环境,让他们可以通过全球服务器进行合作和竞争。《Lineage W》以独特的中世纪奇幻世界为背景,通过各种职业、技能和战斗系统为玩家提供深层次的游戏体验。 NCSoft 使用 Android 动态性能框架最大限度地提高了图形质量,同时避免了由温控调频导致的性能问题。 Android 动态性能框架 (ADPF) 改进性能和散热管理对于开发成功的 Android 游戏至关重要。传统上,开发者必须通过降低游戏保真度或进一步优化渲染程序来管理这些问题。这些更改往往针对特定游戏,并且往往不够灵活。 Android 生态系统中的多个参与者为开发者提供了自适应性能 API。为了简化自适应性能功能的集成并减少生态系统中的碎片化,Google 和 MediaTek 携手合作集成了我们的产品:Android 动态性能框架 (ADPF) 和 MediaTek 自适应游戏技术 (MAGT)。 借助 ADPF 使命召唤:战争地带移动版 是广受欢迎的《使命召唤》系列中的第一人称动作游戏。 超受欢迎的主机和 PC 游戏的移动实现利用低层级移动 API 来提供出色的玩家体验。 从技术角度来看,移动实现的目标是支持各种 Android 移动设备,同时尽可能使实现与主机版本保持一致,并确保图形管道和工具链与当前的主机和 PC 游戏及内容保持兼容。 Call of Duty 引擎使用名为 任务图渲染程序 的系统实现渲染提交管理的同步、内存分配和调度,该系统确定在 GPU 《魔灵召唤:克罗尼柯战记》 是韩国游戏开发商 Com2uS 于 2023 年 3 月面向全球发布的一款移动端大型多人在线角色扮演游戏。迄今为止,《魔灵召唤》在全球的下载量超过 1.8 亿,收入超过 27 亿美元。《魔灵召唤》是目前全球最受欢迎的手游之一,这款游戏展现了一个奇幻世界,玩家必须收集并训练各种怪物,才能与其他玩家对战。 近十年过去了,这款游戏庞大的玩家社区依然很是活跃,而且仍在扩展,部分原因在于 Com2uS 不断发布新的内容和更新,使这款游戏历久弥新、十分刺激。Com2uS 《魔灵召唤:克罗尼柯战记》 US(WW) 和 KR by Com2uS 专门利用 Vulkan 在 Android 上进行渲染,可将性能提升高达 30%。 Vulkan 是一种现代化的跨平台 3D 图形 API,旨在最大限度减少设备图形硬件与您的游戏之间的抽象。与 OpenGL ES 相比,Vulkan 的 CPU 开销更低,并且 Vulkan 提供更广泛的功能。 Com2uS 为 《魔灵召唤:克罗尼柯战记》 开发了高级渲染功能,包括: 《魔灵召唤:克罗尼柯战记》 对 Android 《Ares: Rise of Guardians 》是一款移动设备转 PC 的科幻 MMORPG 游戏,由 Second Dive 开发,后者是一家位于韩国的游戏工作室,以其动作角色扮演系列开发方面的专业知识而闻名。该游戏由 Kakao Games 发布。 《阿瑞斯》以广袤的宇宙为背景,采用细节满满的未来主义背景。《阿瑞斯》充满了刺激的玩法和画面精美的角色,涉及身着战斗服的战斗人员。然而,由于这些细节丰富的图形,一些用户的设备在处理游戏内容时有些吃力。 Cat Daddy Games 是一家全资 2K 工作室,位于华盛顿州柯克兰,是 NBA 2K Mobile 的开发者。该团队希望提高游戏的整体质量和稳定性,具体方法是减少“应用无响应”错误 (ANR)。如果 Android 应用的界面线程处于阻塞状态的时间过长,就会发生 ANR。发生这种情况时,负责更新界面的应用主线程将无法绘制或处理用户输入事件,这会引起用户的不满。如果应用在前台运行,系统会显示一个对话框,允许用户强制退出应用。 减少 ANR 一直是 Cat Daddy 的首要任务。QA Devsisters 是一家全球性的移动游戏开发商和发布商,专门制作基于《跑跑姜饼人》IP 的休闲游戏。他们最受欢迎的游戏包括 《跑跑姜饼人:烤箱大逃亡》 (跑步街机)和 《跑跑王国》 (社交 RPG),这两款游戏都深受全球用户的喜爱,尤其是在韩国、台湾和美国。虽然《跑跑姜饼人:烤箱大逃亡》是一款休闲游戏,但五年积累的资源使 CDN 容量提高到了 2.5GB,这使得 CDN 费用的增加。Devsisters 需要找到一种可持续的模式来宣传他们的大文件游戏。 Devsisters 发现,大量的 NEW STATE Mobile 是 Krafton 的一款大逃杀游戏于 2021 年 11 月面向全球发布,在发布后的第一个月便获得了超过 4500 万次下载。KRAFTON, Inc. 是一个由多个独立的游戏开发工作室组成的联合公司,旨在为全球游戏玩家打造富有吸引力的创新娱乐体验。该公司包括 PUBG Studio、Bluehole Studio、Striking Distance Studio、RisingWings、Dreamotion 和 Unknown Spokko 住在波兰,是一群雄心勃勃的创作者,他们致力于打造要求极为严苛的 IP。Spokko 是 CD PROJEKT 家族的成员,但是一家独立公司,已将 《巫师:怪物杀手》 的精彩世界转移到智能手机上。 《巫师:怪物杀手》是一款使用增强现实技术的基于位置的角色扮演游戏。这是一款计算密集型游戏,会给许多设备带来挑战。发布之初,Spokko 希望确保其游戏可以覆盖尽可能多的用户,同时为所有人提供高品质的体验。 Cat Daddy Games 是一家全资 2K 工作室,总部位于华盛顿州柯克兰。NBA 2K Mobile、NBA SuperCard 和 WWE SuperCard 系列背后的团队正在寻找一个解决方案来为用户提高游戏的整体质量,具体方法是在支持这些游戏的设备上提供更优质的素材资源。 他们实现了 Play Asset Delivery,以简单而更灵活的方式针对每位用户的设备配置生成并提供经过优化的 APK,并使用纹理压缩格式定位功能针对特定设备提供更好的美术资源并减少资源下载。 首先,Cat Unreal Engine 是由 Epic Games 开发的游戏引擎,可为各行各业的创作者提供自由和控制权,让他们提供先进的娱乐、富有吸引力的可视化内容和沉浸式虚拟世界。一些主要的 Android 游戏都是使用 Unreal Engine 构建的。 图 1. 在 Pixel 4 上运行的 Unreal Engine Suntemple 示例的屏幕截图 Epic 和其他游戏开发者使用 Android Studio 调试 C++、Kotlin 或 Java 编程语言,但许多游戏开发者都有以 Electronic Arts (EA) 是一家总部位于美国加利福尼亚州的游戏公司。它制作了各种不同类型的游戏,例如体育、动作、赛车和模拟游戏。EA 的开发工作室 Firemonkeys 因开发 真实赛车 3 、 模拟人生自由玩 和 Need For Speed: No Limits 而闻名于世。Firemonkeys 使用自定义游戏引擎来开发游戏,现在他们的所有 Android 游戏都在其开发工作流中使用 Android Game Development Extension (AGDE) 游戏开发商 CD Projekt RED (CDPR) 位于波兰华沙,他们重新构思了自己的迷你游戏《巫师 3》、 《巫师之昆特牌》 ,并于 2020 年 3 月在 Google Play 上以独立的免费畅玩形式发布。由于初始文件较大,且定期更新需要额外的设备存储空间,用户通常必须重新安装完整版游戏,才能获得更新的版本。这是游戏社区中最突出的挫败点。为了帮助进行差分修补,CDPR 通过实现 Play Asset Delivery 取得了巨大的成功。 CDPR 是实现 Play Asset 20 多年来, Gameloft 为数字平台打造了富有创意的游戏体验,从移动游戏到跨平台 PC 和主机游戏,不一而足。除了自有的知名游戏系列外,Gameloft 还为乐高、环球和长宝等热门品牌开发游戏。他们的游戏团队在全球拥有 3,600 名员工,每月可在 100 多个国家/地区覆盖 5500 万唯一身份玩家。 竞速街机游戏 Asphalt 9: Legends 于 2018 年首次发布,他们需要找到一种平衡性能、保真度和电池的方式。为此,Gameloft 怀着对游戏的热情以及将游戏带给世界各地玩家的渴望, Gameloft 于 2000 年成立。他们是开发移动游戏的先驱,现在旗下有超过 190 款游戏。Gameloft 的许多移动游戏是图形密集型游戏,下载大小较大。这使得他们成为 Google Play Asset Delivery (PAD) 早期开发阶段一个极具吸引力的合作伙伴。PAD 是一套基于我们的 app bundle 基础架构构建的游戏服务分发功能。PAD 会在适当的时间免费向适当的设备提供免费、动态的适当游戏素材资源。这引起了 RV AppStudios 是一家总部位于美国的游戏开发商,该公司旗下的休闲游戏、教育儿童应用和实用类应用到目前为止已有超过 2 亿的下载量。该团队在其应用 Puzzle Kids - Animals Shapes and Jigsaw Puzzles 中引入了 Google Play Asset Delivery,属于早期测试用户。他们希望优化应用的大小,节省资金,并在需要下载新的资源包时消除任何干扰,从而提升用户体验。 当用户安装 Puzzle Kids Pixonic 是一个总部位于莫斯科的视频游戏开发团队,其以抓住每一个机会升级自己的移动应用并覆盖更广泛的玩家群体为荣。该公司最著名的游戏之一是 《War Robots》 ,这是一款 12 人的玩家对战 (PVP) 游戏,玩家可以在即时战场上操作定制的机器人进行决斗。 《War Robots》于 2014 年发布,最初是专为 Android 的早期设备设计的,通过触控板操控游戏角色,用不到鼠标。Pixonic Gameloft 一直致力于成为首批在最新便携式硬件上发布游戏的开发商之一,以便随时随地为玩家提供激动人心的体验。因此,Gameloft 知道 ChromeOS 是适合其移动赛车系列最新游戏《狂野飙车 8:极速凌云》的平台。 Gameloft 非常了解如何针对不同的设备开发游戏,但将 Asphalt 体验转换为 Chromebook 特有的触摸屏/键盘混合控制(可随时切换)似乎具有挑战性。然而,结果证明这个过程没有想象的那么困难,值得一试。 利用 ChromebookMir 2 通过使用 Frame Pacing 库来提升渲染性能
Kuro Games 使用 Android Studio 功耗性能分析器和 ODPM 为 Wuthering Waves 降低了 9.68% 的功耗
适用于 Android 的 Godot Engine Vulkan 优化
在 Unreal Engine 中使用 Android 动态性能框架 (ADPF) 入门
NCSoft Lineage W 使用 ADPF 提高了持续性能并防止温控降频
MediaTek 提升了 Android SoC 的动态性能
《使命召唤:战争地带手游》使用 Vulkan 提升图形效果
Com2uS - Google Play 游戏电脑版
Com2uS 使用 Vulkan 提升图形效果
Kakao Games 通过 Android 自适应功能将 FPS 稳定性提升至 96%
2K 利用 Android Game Development Kit 将 ANR 发生率降低了 35%
《跑跑姜饼人:烤箱大逃亡》通过 Play Asset Delivery 节省了超过 20 万美元的 CDN 费用
新 STATE Mobile 利用 Android GPU 检查器将 GPU 使用量降低了 22%
《The Witcher: Monster Slayer》借助 Android Performance Tuner 扩大覆盖面
2K 借助 Play Asset Delivery 提供高清画质
“AGDE 简直太棒了!”;使用 Unreal Engine 进行 Android 开发
Firemonkeys 借助 AGDE 缩短了开发和调试时间
CD Projekt RED 借助 Play Asset Delivery 将游戏更新大小缩减了 90% 并将更新率提高了 10%
借助 Game Mode API,Gameloft 将设备功耗降低了 70%,从而使游戏时长延长了 35%
Gameloft 借助 Google Play Asset Delivery 将新用户数增加了 10%
RV AppStudios 借助 Google Play Asset Delivery 提高了用户留存率
Pixonic 针对大屏设备进行优化后,在 ChromeOS 上的互动度提高了 25%
Gameloft 针对 ChromeOS 进行优化后,收入迅速提升了 9 倍
Пока рекомендаций нет.
Попытайтесь войти в свой аккаунт Google.