demo代码如下:
import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import com.demo.lockscreenmsgdemo.MyService; import com.demo.lockscreenmsgdemo.R; /** * 仿qq,微信,支付宝锁屏消息 * 使用步骤,点击这个按钮以后,按返回键退出APP,关闭手机屏幕,5s以后会受到锁屏消息,可以点击进入消息详情页面 */ public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findViewById(R.id.start_service_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Intent intent = new Intent(MainActivity.this, MyService.class); startService(intent); //启动后台服务 } }); } }
import android.app.KeyguardManager; import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.Window; import android.view.WindowManager; import com.demo.lockscreenmsgdemo.R; /** * 锁屏消息内容的activity */ public class MessageActivity extends AppCompatActivity { private Context mContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i("tag", "onCreate:启动了消息内容的activity "); //四个标志位顾名思义,分别是锁屏状态下显示,解锁,保持屏幕长亮,打开屏幕。这样当Activity启动的时候,它会解锁并亮屏显示。 Window win = getWindow(); win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED //锁屏状态下显示 | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD //解锁 | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON //保持屏幕长亮 | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON); //打开屏幕 //使用手机的背景 Drawable wallPaper = WallpaperManager.getInstance(this).getDrawable(); win.setBackgroundDrawable(wallPaper); setContentView(R.layout.activity_message); mContext = this; initView(); } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); //获取电源管理器对象 // PowerManager pm = (PowerManager) this.getSystemService(Context.POWER_SERVICE); // if (!pm.isScreenOn()) { // PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | // PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "bright"); // wl.acquire(); //点亮屏幕 // wl.release(); //任务结束后释放 // } } private void initView() { findViewById(R.id.message_layout).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { //先解锁系统自带锁屏服务,放在锁屏界面里面 KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); keyguardManager.newKeyguardLock("").disableKeyguard(); //解锁 //点击进入消息对应的页面 mContext.startActivity(new Intent(mContext, DetailsActivity.class)); finish(); } }); findViewById(R.id.close_iv).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); } }
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import com.demo.lockscreenmsgdemo.R; public class DetailsActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_details); } }
import android.app.KeyguardManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.os.Build; import android.util.Log; import com.demo.lockscreenmsgdemo.activity.MessageActivity; /** * 监听锁屏消息的广播接收器 */ public class LockScreenMsgReceiver extends BroadcastReceiver { private static final String TAG = "LockScreenMsgReceiver"; @Override public void onReceive(Context context, Intent intent) { Log.i(TAG, "onReceive:收到了锁屏消息 "); String action = intent.getAction(); if (action.equals("com.zx.lockscreenmsgdemo.LockScreenMsgReceiver")) { //管理锁屏的一个服务 KeyguardManager km = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE); String text = km.inKeyguardRestrictedInputMode() ? "锁屏了" : "屏幕亮着的"; Log.i(TAG, "text: " + text); if (km.inKeyguardRestrictedInputMode()) { Log.i(TAG, "onReceive:锁屏了 "); //判断是否锁屏 Intent alarmIntent = new Intent(context, MessageActivity.class); //在广播中启动Activity的context可能不是Activity对象,所以需要添加NEW_TASK的标志,否则启动时可能会报错。 alarmIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if(Build.VERSION.SDK_INT >= 26){ alarmIntent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP); } context.startActivity(alarmIntent); //启动显示锁屏消息的activity } } } }
import android.app.Service; import android.content.ComponentName; import android.content.Intent; import android.os.IBinder; import android.util.Log; /** * 模拟推送,在退出APP后的一段时间发送消息 */ public class MyService extends Service { private static final String TAG = "MyService"; public MyService() { } @Override public IBinder onBind(Intent intent) { Log.i(TAG, "onBind: "); throw new UnsupportedOperationException("Not yet implemented"); } @Override public void onCreate() { Log.i(TAG, "onCreate: "); super.onCreate(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.i(TAG, "onStartCommand: "); sendMessage(); return START_STICKY; } @Override public void onDestroy() { Log.i(TAG, "onDestroy: "); super.onDestroy(); } /** * 模仿推送,发消息 */ private void sendMessage() { System.out.println("sendMessage"); new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } Intent intent = new Intent(); intent.setAction("com.demo.lockscreenmsgdemo.LockScreenMsgReceiver"); //Android O版本对后台进程做了限制广播的发送,对隐式广播也做了限制;必须要指定接受广播类的包名和类名 //解决Background execution not allowed-----8.0以上发送的隐式广播无法被收到问题 intent.setComponent(new ComponentName("com.demo.lockscreenmsgdemo","com.demo.lockscreenmsgdemo.LockScreenMsgReceiver")); sendBroadcast(intent); //发送广播 } }).start(); } }
页面布局:
activity_details.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" tools:context="com.demo.lockscreenmsgdemo.activity.DetailsActivity"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="18sp" android:text="这是消息的详情"/> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.demo.lockscreenmsgdemo.activity.MainActivity"> <Button android:id="@+id/start_service_btn" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="开启消息服务" /> </RelativeLayout>
activity_message.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:layout_marginStart="15dp" android:layout_marginEnd="15dp" android:orientation="vertical"> <RelativeLayout android:layout_width="match_parent" android:layout_height="50dp" android:background="#381515" android:orientation="horizontal"> <ImageView android:id="@+id/icon_iv" android:layout_width="25dp" android:layout_height="25dp" android:layout_centerVertical="true" android:layout_marginStart="15dp" android:scaleType="centerCrop" android:src="@mipmap/qq" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_marginStart="15dp" android:layout_toEndOf="@id/icon_iv" android:text="QQ" android:textColor="#fff" /> <ImageView android:id="@+id/close_iv" android:layout_width="15dp" android:layout_height="15dp" android:layout_alignParentEnd="true" android:layout_centerVertical="true" android:layout_marginEnd="15dp" android:scaleType="centerCrop" android:src="@mipmap/close" /> </RelativeLayout> <LinearLayout android:id="@+id/message_layout" android:layout_width="match_parent" android:layout_height="100dp" android:background="#1c3636" android:orientation="vertical" android:paddingLeft="15dp" android:paddingTop="25dp"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=".在吗?" android:textColor="#fff" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text=".今天有空吗!" android:textColor="#fff" /> </LinearLayout> </LinearLayout>
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.demo.lockscreenmsgdemo"> <!-- 解锁屏幕需要的权限 --> <uses-permission android:name="android.permission.DISABLE_KEYGUARD" /> <!-- 申请电源锁需要的权限 --> <uses-permission android:name="android.permission.WAKE_LOCK" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".activity.MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".activity.MessageActivity" android:excludeFromRecents="true" android:launchMode="singleInstance" android:taskAffinity="" /> <receiver android:name=".LockScreenMsgReceiver" android:enabled="true" android:exported="true"> <intent-filter> <!-- 监听锁屏消息 --> <action android:name="com.demo.lockscreenmsgdemo.LockScreenMsgReceiver" /> </intent-filter> </receiver> <service android:name=".MyService" android:enabled="true" android:exported="true" /> <activity android:name=".activity.DetailsActivity"></activity> </application> </manifest>
适用应用场景
- 适用应用场景:应用没有完全退出的情况下在后台运行时,如果用户已经关闭了手机屏幕,如果我们的APP收到推送消息,则打开手机屏幕,弹框显示消息的方式来提醒用户。
实现思路
- 在收到自己服务器的推送消息时,发送一条广播,在接收到指定广播之后在广播的onReceive()中判断当前屏幕是否处于关闭状态,如果处于关闭状态,则显示这个弹窗消息,反之,则不需要显示
说明:
-
KeyguardManager类,管理锁屏
-
在广播中启动Activity的context可能不是Activity对象,有可能是Service或者其他BroadcastReceiver,所以需要添加NEW_TASK的标志,否则启动时会报错。
- 能够在锁屏状态下显示消息就是因为窗体对象的这个添加标志位的这个方法起了作用。四个标志位的作用,分别是锁屏状态下显示,解锁,保持屏幕长亮,打开屏幕。这样当Activity启动的时候,它会解锁并亮屏显示。保持屏幕长亮这个标志位是可选的。
设置了背景为壁纸的背景,所以显示的是桌面的背景。如果背景设为默认的白色,则导致弹窗后面是一片白色,看起来很丑。如果背景设置为透明,则弹窗后面会显示出解锁后的界面(即使有锁屏密码,也是会显示解锁后的界面的),一样很影响视觉效果。
当显示完消息,点击消息内容的时候,需要先先解锁系统自带锁屏服务,才能进入我们对应的消息界面。
运行效果: