You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

替代已弃用FLAG_SHOW_WHEN_LOCKED,Android锁屏启动Activity方案

解决锁屏下通过广播启动Activity的问题

嘿,这个问题我之前做项目时刚好踩过坑,给你梳理下完整的解决思路,保证能搞定!

首先你碰到的No virtual method setShowWhenLocked(Z)V错误,多半是两个原因:

  • 你的项目minSdkVersion低于27,毕竟setShowWhenLocked()setTurnScreenOn()是API 27才新增的方法
  • 调用对象不对——这俩是Window类的方法,得通过Activity的getWindow()来调用,不能瞎找个类就调用

下面分不同Android版本给你具体实现步骤:

1. 基础配置(全版本通用)

先在要启动的Activity的AndroidManifest.xml里声明必要属性:

<activity
    android:name=".YourTargetActivity"
    android:showOnLockScreen="true" <!-- 早期版本兼容属性,API27+可配合新方法使用 -->
    android:turnScreenOn="true">
</activity>

另外如果是静态注册广播接收器,别忘了在Manifest里注册好;动态注册的话就在代码里处理就行。

2. 分API版本处理Activity逻辑

API 27及以上(推荐写法)

在TargetActivity的onCreate()里,setContentView()之前调用Window的方法:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // 先处理锁屏亮屏逻辑
    Window window = getWindow();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
        window.setShowWhenLocked(true);
        window.setTurnScreenOn(true);
    }
    setContentView(R.layout.activity_target);
    // 其他初始化代码...
}

如果你的minSdk直接设为27+,可以不用版本判断直接调用。

API 23到26(过渡版本)

这部分版本旧的FLAG还没完全弃用,用旧写法兼容:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Window window = getWindow();
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {
        window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
        window.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
    }
    setContentView(R.layout.activity_target);
}

API 22及以下

直接用最原始的FLAG组合即可:

window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);

3. Android 10(API29)及以上的额外注意事项

从Android10开始,系统对后台启动Activity限制更严,如果你的广播是在APP后台触发的,得满足以下条件之一:

  • 广播是用户可见事件触发的(比如通知的PendingIntent)
  • 你的APP持有SYSTEM_ALERT_WINDOW权限(但这个权限需要用户手动授予,不推荐滥用)
  • 使用符合后台启动规则的方式,比如ActivityOptions.makeLaunchIntoPipMode()

如果还需要解锁屏幕,API28及以上可以这么做:

KeyguardManager keyguardManager = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    keyguardManager.requestDismissKeyguard(this, null);
}

4. 广播接收器里的启动逻辑

在广播接收器里启动Activity时,必须加FLAG_ACTIVITY_NEW_TASK标记,非Activity环境启动Activity都得加这个:

Intent intent = new Intent(context, YourTargetActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);

这套流程走下来,锁屏下通过广播启动Activity的需求就完全实现了,我自己项目里这么写一直没出问题!

内容的提问来源于stack exchange,提问作者Dave

火山引擎 最新活动