Android 支付 SDK 结束后如何恢复 status bar color
结论
colorPrimaryDark 资源无法在运行时被“覆盖”。应用构建完成后,资源值不会因为支付 SDK 启动而被永久修改。
状态栏一直显示红色,通常是因为支付 SDK 修改了当前 Window 的 statusBarColor 或系统栏标志,而应用页面恢复时没有重新设置。可以在支付结束或页面重新获得焦点后,主动恢复状态栏颜色。通常把这段逻辑放在宿主 Activity 的 onResume() 中,也可以在支付结果回调中执行。
推荐做法
从支付页面返回后,重新设置当前 Activity 的状态栏颜色:
class PaymentActivity : AppCompatActivity() {
override fun onResume() {
super.onResume()
restoreStatusBar()
}
private fun restoreStatusBar() {
window.statusBarColor = ContextCompat.getColor(
this,
R.color.status_bar_blue
)
WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = false
}
}
对应的颜色资源:
<!-- res/values/colors.xml -->
<color name="status_bar_blue">#1565C0</color>
isAppearanceLightStatusBars = false 表示使用浅色状态栏图标,适合较深的蓝色背景。状态栏背景较浅时,应将其设置为 true,改用深色图标。
在支付结果回调中恢复
如果 SDK 通过 Activity Result 返回结果,可以在回调中恢复状态栏:
private val paymentLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
restoreStatusBar()
if (result.resultCode == Activity.RESULT_OK) {
// 处理支付成功结果
} else {
// 处理取消或失败结果
}
}
private fun startPayment(intent: Intent) {
paymentLauncher.launch(intent)
}
private fun restoreStatusBar() {
window.statusBarColor = ContextCompat.getColor(
this,
R.color.status_bar_blue
)
WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = false
}
即使回调中已经恢复了状态栏,也建议保留 onResume() 中的设置。部分 SDK 可能通过内部 Activity、回调或窗口标志改变系统栏外观,实际执行顺序不一定相同。
Java 写法
@Override
protected void onResume() {
super.onResume();
getWindow().setStatusBarColor(
ContextCompat.getColor(this, R.color.status_bar_blue)
);
WindowInsetsControllerCompat controller =
WindowCompat.getInsetsController(getWindow(), getWindow().getDecorView());
controller.setAppearanceLightStatusBars(false);
}
为什么修改主题没有生效
主题配置主要在创建 Activity 时用于初始化窗口,例如:
<style name="Theme.MyApp" parent="Theme.MaterialComponents.DayNight.NoActionBar">
<item name="colorPrimaryDark">@color/status_bar_blue</item>
<item name="android:statusBarColor">@color/status_bar_blue</item>
<item name="android:windowLightStatusBar">false</item>
</style>
如果 SDK 在运行期间调用了类似代码:
window.statusBarColor = Color.RED
这个运行时设置会覆盖主题初始化的颜色。返回原来的 Activity 时,该 Activity 通常不会重新创建,主题自然也不会再次应用。因此,需要在生命周期回调中主动恢复状态栏。
另外,colorPrimaryDark 只是主题属性,并不是可以在运行时修改的全局状态。SDK 更可能修改自己的窗口或宿主窗口,而不是资源文件中的值。
如果仍然无法恢复
检查 SDK 是否直接在宿主 Activity 中展示支付界面,例如使用 Dialog、Fragment 或透明页面。如果 SDK 修改了窗口标志,可以先清除相关设置,再恢复颜色:
private fun restoreStatusBar() {
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
window.statusBarColor = ContextCompat.getColor(
this,
R.color.status_bar_blue
)
WindowCompat.getInsetsController(window, window.decorView)
.isAppearanceLightStatusBars = false
}
还要确认应用是否启用了 edge-to-edge。启用后,状态栏可能是透明的,用户看到的颜色实际上来自状态栏下方的页面背景,而不是 statusBarColor。此时需要同时设置顶部容器的背景和 Window Insets,仅修改 colorPrimaryDark 并不能解决问题。
注意事项
- 不要尝试在运行时修改
R.color或colorPrimaryDark,编译后的资源不是可变配置。 - 新代码不推荐使用
onActivityResult(),应优先使用 Activity Result API。 - 如果 SDK 提供“关闭”“支付完成”或“页面销毁”回调,可以在回调中恢复状态栏,但
onResume()通常更稳妥。 - 如果应用支持浅色和深色主题,应分别提供颜色资源,例如放在
values/colors.xml和values-night/colors.xml中。 - Android 15 及后续版本对 edge-to-edge 的处理可能影响系统栏的最终效果,具体表现取决于应用的 target SDK、主题和布局方式。
备注:内容仅供参考。
