You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

锁屏状态下FCM特定通知无法启动Activity且内容为空问题求助

Fixing FCM Notification & Activity Launch Issues on Lock Screen

Let's break down the problems you're facing and fix them step by step. Your code works fine when the app is foreground/background/killed, but fails on lock screen due to missing window permissions, thread-safe data handling, and incomplete intent flags.


Problem Analysis

The main issues causing failure on lock screen:

  • Insufficient window flags: Your OverlayActivity lacks flags to turn on the screen, dismiss the keyguard, and stay visible over lock screen
  • Thread-unsafe data passing: Using GlobalVariable to share data between background FCM service and UI thread can lead to race conditions (empty Toast content)
  • Incomplete intent flags: The flags used to launch OverlayActivity don't prioritize bringing it to the foreground on lock screen
  • Null pointer risks: No null checks for FCM message body or parsed data, leading to unexpected failures
  • Unnecessary Service initialization logic: The onCreate() method in MyFirebaseMessagingService incorrectly launches OverlayActivity when the service starts

Step-by-Step Fixes

1. Enhance OverlayActivity Window Permissions

Update OverlayActivity.onCreate() to add all critical flags for lock screen visibility:

public class OverlayActivity extends Activity {
    private static final String TAG = OverlayActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.d(TAG, "[onCreate]");
        super.onCreate(savedInstanceState);
        Window window = getWindow();
        // Add all required lock-screen flags
        window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
                | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
                | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        
        // Existing fragment transaction code...
        Fragment fragment = getFragmentManager().findFragmentByTag(FragmentType.OVERLAY.getTag());
        if (fragment == null) {
            fragment = OverlayFragment.newInstance();
        }
        FragmentTransaction ft = getFragmentManager().beginTransaction();
        ft.replace(android.R.id.content, fragment, FragmentType.OVERLAY.getTag());
        ft.commit();
    }

    // Existing FragmentType enum...
}

2. Fix FCM Message Handling & Data Passing

Rewrite MyFirebaseMessagingService.onMessageReceived() to add null checks, use intent extras instead of global variables, and update intent flags:

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMessaging";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.d(TAG, "From: " + remoteMessage.getFrom());
        Log.d(TAG, "FCM Data: " + remoteMessage.getData());

        // Guard against empty message body
        String body = remoteMessage.getData().get("body");
        if (body == null || body.isEmpty()) {
            Log.e(TAG, "FCM message body is empty!");
            return;
        }

        // Extract ticket number from body
        StringBuilder myNumbers = new StringBuilder();
        for (int i = 0; i < body.length(); i++) {
            if (Character.isDigit(body.charAt(i))) {
                myNumbers.append(body.charAt(i));
            }
        }
        String ticketNo = myNumbers.toString();

        // Split message and validate format
        String[] splited = body.split("\\s+");
        if (splited.length < 2) {
            Log.e(TAG, "Invalid message format!");
            return;
        }
        String firstWord1 = splited[0];
        String firstWord = splited[1];

        Log.d(TAG, "FW Word : " + firstWord);
        Log.d(TAG, "0 Word : " + firstWord1);

        // Launch OverlayActivity directly with intent extras (no global variables)
        if ("Please".equals(firstWord1)) {
            Intent intent = new Intent(this, OverlayActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
                    | Intent.FLAG_ACTIVITY_CLEAR_TOP
                    | Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
            // Pass data via intent extras
            intent.putExtra("showPopupStr", body);
            intent.putExtra("showPopupFirstword", firstWord1);
            intent.putExtra("ticketNo", ticketNo);
            intent.putExtra("msg", firstWord);
            startActivity(intent);
        } else {
            // Existing notification logic (update PendingIntent flag for Android 12+)
            String clickAction = remoteMessage.getNotification().getClickAction();
            Intent intent = new Intent(clickAction);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            
            int pendingFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
                    ? PendingIntent.FLAG_IMMUTABLE
                    : PendingIntent.FLAG_ONE_SHOT;
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, pendingFlag);

            Uri sound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            String channelId = "Default";
            NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setSound(sound)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent);

            NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                NotificationChannel channel = new NotificationChannel(channelId, "Default channel", NotificationManager.IMPORTANCE_DEFAULT);
                manager.createNotificationChannel(channel);
            }
            manager.notify(0, builder.build());
        }
    }

    // DELETE the onCreate() method that launches OverlayActivity - it's unnecessary and incorrect
}

3. Update OverlayFragment to Use Intent Extras

Modify OverlayFragment to get data directly from the intent (avoids global variable race conditions) and fix MediaPlayer resource handling:

public class OverlayFragment extends Fragment {
    private static final String TAG = OverlayFragment.class.getSimpleName();

    public static OverlayFragment newInstance() {
        return new OverlayFragment();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_overlay, container, false);
        Activity activity = getActivity();
        if (activity == null) return view;

        // Get data from intent extras
        String showPopupFirstword = activity.getIntent().getStringExtra("showPopupFirstword");
        String showPopupStr = activity.getIntent().getStringExtra("showPopupStr");
        String msg = activity.getIntent().getStringExtra("msg");

        // Show Toasts with non-null checks
        if (showPopupFirstword != null) {
            Toast.makeText(activity, showPopupFirstword, Toast.LENGTH_LONG).show();
        }
        if (msg != null) {
            Toast.makeText(activity, "msg: " + msg, Toast.LENGTH_LONG).show();
        }

        // Handle visitor request dialog
        MediaPlayer mp = null;
        if ("Please".equals(showPopupFirstword)) {
            // Initialize MediaPlayer safely
            try {
                mp = MediaPlayer.create(activity, R.raw.ring);
                mp.start();
            } catch (Exception e) {
                Log.e(TAG, "Failed to play notification sound", e);
            }

            android.app.AlertDialog.Builder builder = new android.app.AlertDialog.Builder(activity);
            builder.setTitle("Visitor Request");
            builder.setMessage(showPopupStr != null ? showPopupStr : "No message content");
            builder.setCancelable(false);

            builder.setPositiveButton("Accept", (dialog, which) -> {
                stopAndReleaseMediaPlayer(mp);
                GlobalVeriable.notiMsg = "In";
                // sendOwnerResponce();
            });

            builder.setNegativeButton("Reject", (dialog, which) -> {
                stopAndReleaseMediaPlayer(mp);
                GlobalVeriable.notiMsg = "Out";
                // sendOwnerResponce();
            });

            final android.app.AlertDialog dialog = builder.create();
            dialog.show();
            dialog.getButton(DialogInterface.BUTTON_POSITIVE).setTextColor(Color.parseColor("#48A21D"));
            dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextColor(Color.RED);

            new CountDownTimer(15000, 1000) {
                @Override
                public void onTick(long millisUntilFinished) {}

                @Override
                public void onFinish() {
                    dialog.dismiss();
                    stopAndReleaseMediaPlayer(mp);
                    activity.finish();
                }
            }.start();
        } else {
            activity.finish();
        }

        // Close button logic
        Button close = view.findViewById(R.id.close);
        close.setOnClickListener(v -> activity.finish());

        return view;
    }

    // Helper method to safely stop and release MediaPlayer
    private void stopAndReleaseMediaPlayer(MediaPlayer mp) {
        if (mp != null) {
            if (mp.isPlaying()) mp.stop();
            mp.release();
        }
    }
}

4. Add Required Permissions

Ensure these permissions are in your AndroidManifest.xml:

<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- For Android 13+, add notification permission -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 05:38:28