问题背景
在 Flutter 应用开发中,我们最近遇到了一个棘手的兼容性问题:在部分 华为手机(HarmonyOS 4.2.0,如 Mate 30 Pro 5G) 上,应用运行时的最近任务列表(Overview Screen)中,只显示应用图标,却不显示应用名称(App Name)。
虽然我们在 AndroidManifest.xml 中正确配置了 android:label,但在 HarmonyOS 系统上依然无效。这不仅影响用户体验,也可能导致应用在审核时被拒(如华为应用市场审核指南第 2.19 项)。
问题分析
经过多次排查与尝试,我们发现该问题主要由以下几个因素共同导致:
- Flutter 引擎初始化干扰:FlutterActivity 初始化过程中可能会重置窗口属性,导致原生的标签设置被覆盖。
- API 兼容性:Android 不同版本对
TaskDescription(任务描述)的 API 支持不同。HarmonyOS 基于较新的 Android 版本,对旧版 API(如基于 Bitmap 的设置)可能兼容性不佳。 - 资源加载机制:直接硬编码字符串可能导致编码或加载失败,必须规范使用
strings.xml资源。 - 时序问题:仅在
onCreate中设置可能过早,应用启动后的某些系统回调可能会再次刷新任务状态,导致设置失效。
解决方案:三级加固策略
为了彻底解决这个问题,我们采用了一套“组合拳”方案,从资源配置到原生代码层层加固。
第一步:规范化资源配置
首先,确保 AndroidManifest.xml 中不使用硬编码,而是引用资源文件。
**1. 定义 strings.xml**在 android/app/src/main/res/values/strings.xml 和 values-zh/strings.xml 中明确定义应用名:
1<resources> 2 <string name="app_name">您的应用名称</string> 3</resources> 4
**2. 配置 AndroidManifest.xml**确保 application 和 activity 节点都引用了该资源,并配置 localeConfig:
1<application 2 android:label="@string/app_name" 3 android:localeConfig="@xml/locales_config" 4 ...> 5 <activity 6 android:name=".MainActivity" 7 android:label="@string/app_name" 8 ...> 9 </activity> 10</application> 11
第二步:原生代码强制干预 (Kotlin)
这是解决问题的核心。我们需要在 MainActivity.kt 中手动设置 TaskDescription。我们采用了 “三级加固” 策略:
- 多生命周期设置:在
onCreate(创建时)和onResume(可见时)都进行设置。 - 延迟设置:在
onResume后延迟 1 秒再次强制刷新,防止被 Flutter 引擎后续逻辑覆盖。 - API 自适应:针对 Android 9.0+ 使用资源 ID 方式(更稳定),旧版本使用 Bitmap 方式。
完整代码实现 (MainActivity.kt):
1package com.your.package.name 2 3import android.app.ActivityManager 4import android.graphics.BitmapFactory 5import android.os.Build 6import android.os.Bundle 7import android.os.Handler 8import android.os.Looper 9import android.util.Log 10import io.flutter.embedding.android.FlutterActivity 11 12class MainActivity : FlutterActivity() { 13 override fun onCreate(savedInstanceState: Bundle?) { 14 super.onCreate(savedInstanceState) 15 // 1. 初始化时尝试设置 16 updateTaskDescription() 17 } 18 19 override fun onResume() { 20 super.onResume() 21 // 2. 界面可见时再次设置 22 updateTaskDescription() 23 24 // 3. 关键修复:延迟 1 秒再次设置 25 // 防止 Flutter 引擎在启动完成后重置了窗口属性,导致之前的设置失效 26 Handler(Looper.getMainLooper()).postDelayed({ 27 updateTaskDescription() 28 }, 1000) 29 } 30 31 private fun updateTaskDescription() { 32 try { 33 val appName = getString(R.string.app_name) 34 35 // 尝试设置窗口标题,作为一种补充手段 36 try { 37 title = appName 38 } catch (e: Exception) { 39 // 忽略设置 title 失败 40 } 41 42 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { 43 // Android 9 (API 28) 及以上:直接使用资源 ID,更稳定 44 // 第三个参数 0 表示使用系统默认颜色 45 val taskDescription = ActivityManager.TaskDescription(appName, R.mipmap.launcher_icon, 0) 46 setTaskDescription(taskDescription) 47 } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 48 // Android 5.0 至 8.1:使用 Bitmap 解码 49 val icon = BitmapFactory.decodeResource(resources, R.mipmap.launcher_icon) 50 val taskDescription = ActivityManager.TaskDescription(appName, icon) 51 setTaskDescription(taskDescription) 52 } 53 } catch (e: Exception) { 54 Log.e("MainActivity", "Failed to update TaskDescription", e) 55 } 56 } 57} 58
小结
华为 HarmonyOS 系统对应用元数据的读取机制较为严格。通过在原生层主动调用 setTaskDescription,并配合 延迟执行 策略,我们成功绕过了系统或框架层面的干扰,确保了应用名称在最近任务列表中正确显示。
如果您的 Flutter 应用也遇到了类似问题,不妨尝试上述方案!
《Flutter 开发实战:解决华为 HarmonyOS 任务列表不显示 App 名称的终极指南》 是转载文章,点击查看原文。