Android FCM在应用程序被杀死时部分工作。

huangapple go评论93阅读模式
英文:

Android FCM working partly while app is killed

问题

以下是您要翻译的内容:

我在我的 MyFirebaseMessagingService.java 中有两种通知构建器,一种传递名为 'lecture_date' 的字符串,并在单击时打开 Lectures_graph.class,而另一种传递名为 'web_url' 的字符串,并在单击时打开 webview_base.class。

我想要实现的目标是:即使应用程序被关闭,也要完全工作的 FCM 通知,通知在单击后必须打开活动(带有额外信息)。

我目前的进展:我可以接收通知以打开 Lectures_graph.class,并带有意图附加项,一切都加载并正常工作。即使我接收到打开 webview_base.class 活动的通知,单击通知时什么都不会发生。

可能有一件事情指向问题 - Logcat 经常告诉我:

E/FirebaseMessaging: 通知挂起意图已取消

我使用 PHP 发送通知(该代码是 100% 正确和工作的),下面的代码代表了发送给 webview_base.class 活动的 JSON 的想法。要发送通知以打开 Lectures_graph.class 活动,我只需将 click_action 从 "OPEN_ACTIVITY_WEBVIEW" 更改为 "OPEN_ACTIVITY_LECTURES" 并更改数据有效载荷。用于 webview_base.class 活动的 PHP 发送这样的数据:

$msg = array
    (
        'body'  => 'test body',
        'title'     => "test title",
        'click_action' => 'OPEN_ACTIVITY_WEBVIEW',
        'channelId' => "newsfeed",
        'vibrate'   => 1,
        'sound'     => 1
        
    );


//通过主题发送通知
$fields = array
    (
        "data" => [
            'web_url' => $_POST['notification_url']
        ],
        'notification'          => $msg,
        'to'  => '/topics/test'
    );

这是我的整个 Android Studio 清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="secret">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT"/>
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />

    <supports-screens
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:anyDensity="true" />

    <application
        android:allowBackup="false"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@style/AppTheme.CustomTheme"
        android:usesCleartextTraffic="true"
        tools:targetApi="m">

        <activity
            android:name=".systems.webview_activity.webview_base"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <category android:name="android.intent.category.BROWSABLE" />
                <action android:name="android.intent.action.VIEW" />
                <data android:scheme="file" />
                <data android:mimeType="*/*" />
                <data android:pathPattern=".*\.kdb" />
                <data android:host="*" />

                <!-- 即使此方法适用于 Lectures_graph 活动,但对于此方法无效 -->
                <action android:name="OPEN_ACTIVITY_WEBVIEW" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".systems.lectures.Lectures_graph"
            android:configChanges="keyboardHidden|screenSize"
            android:label="@string/title_lectures_graph"
            >
            <intent-filter>

                <!-- 此意图过滤器对于提供在我的 PHP 文件中的 click_action 的正确响应 -->
                <action android:name="OPEN_ACTIVITY_LECTURES" />
                <action android:name="android.intent.action.CREATE_SHORTCUT" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
        <activity
            android:name=".SplashScreen"
            android:configChanges="keyboardHidden|orientation|screenSize" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".NoInternetConnection"
            android:configChanges="keyboardHidden|orientation|screenSize" />
        <activity
            android:name="secret.systems.about.about_app"
            android:configChanges="orientation|keyboardHidden|screenSize"
            android:theme="@style/FullscreenTheme" />
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask"
            android:configChanges="orientation|keyboardHidden|screenSize">
        </activity>

        <service
            android:name="secret.services.MyFirebaseMessagingService"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>

</manifest>

MyFirebaseMessagingService.java:

public class MyFirebaseMessagingService extends FirebaseMessagingService {

    private static final String TAG = "MyFirebaseMsgService";

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        // 检查消息是否包含通知负载。
        if (remoteMessage.getNotification() != null) {
            Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());

            // 从通知中获取键/值
            String lectureDate = remoteMessage.getData().get("lecture_date");
            String web_url = remoteMessage.getData().get("web_url");

            if(lectureDate != null)sendLecturesNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), lectureDate);
            else if(web_url != null) sendNotificationWithURL(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), web_url);
            else Log.e(TAG, "Message.notification is empty!");
        }
    }

    @Override
    public void onNewToken(@NonNull String token) {
        Log.d

<details>
<summary>英文:</summary>

I have 2 kinds of notification builders in my MyFirebaseMessagingService.java, one passes string called &#39;lecture_date&#39; and opens Lectures_graph.class while the other one passes string called &#39;web_url&#39; and opens webview_base.class when clicked.

What i want to achieve : fully working FCM notifications even when app is killed, notifications must open activity (with extras) once they are clicked.

How far i am : I can receive notifications to open Lectures_graph.class with intent extras, everything loads and works just fine. Even if i receive notifications for webview_base.class activity, nothing happens when i click on notification. 

There might be one thing that points to problem - Logcat often tells me this :

    E/FirebaseMessaging: Notification pending intent canceled

Im using PHP to send out notifications (that code is 100% correct and working), code below shows represents the idea of JSON sent out for webview_base.class activity. To send out notifications for Lectures_graph.class activity, i just have to swap click_action from &quot;OPEN_ACTIVITY_WEBVIEW&quot; to &quot;OPEN_ACTIVITY_LECTURES&quot; and change the data payload. PHP for webview_base.class activity sends away such data :

    $msg = array
    	(
    		&#39;body&#39;  =&gt; &#39;test body&#39;,
    	    &#39;title&#39;     =&gt; &quot;test title&quot;,
    	    &#39;click_action&#39; =&gt; &#39;OPEN_ACTIVITY_WEBVIEW&#39;,
    	    &#39;channelId&#39; =&gt; &quot;newsfeed&quot;,
    	    &#39;vibrate&#39;   =&gt; 1,
    	    &#39;sound&#39;		=&gt; 1
    	    
    	);
    
    
    //sends notifications via topics
    $fields = array
    	(
    	    &quot;data&quot; =&gt; [
    	        &#39;web_url&#39; =&gt; $_POST[&#39;notification_url&#39;]
    	    ],
    	    &#39;notification&#39;          =&gt; $msg,
    	    &#39;to&#39;  =&gt; &#39;/topics/test&#39;
    	);

This is my whole manifest file from Android studio :


    &lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
        xmlns:tools=&quot;http://schemas.android.com/tools&quot;
        package=&quot;secret&quot;&gt;
        
        
        &lt;uses-permission android:name=&quot;android.permission.INTERNET&quot; /&gt;
        &lt;uses-permission android:name=&quot;android.permission.WRITE_EXTERNAL_STORAGE&quot; /&gt;
        &lt;uses-permission android:name=&quot;android.permission.READ_EXTERNAL_STORAGE&quot; /&gt;
        &lt;uses-permission android:name=&quot;android.permission.ACCESS_NETWORK_STATE&quot; /&gt;
        &lt;uses-permission android:name=&quot;com.android.launcher.permission.INSTALL_SHORTCUT&quot;/&gt;
        &lt;uses-permission android:name=&quot;com.google.android.c2dm.permission.RECEIVE&quot; /&gt;
        &lt;uses-permission android:name=&quot;android.permission.WAKE_LOCK&quot; /&gt;
        
        &lt;supports-screens
            android:smallScreens=&quot;true&quot;
            android:normalScreens=&quot;true&quot;
            android:largeScreens=&quot;true&quot;
            android:anyDensity=&quot;true&quot; /&gt;
        
        &lt;application
            android:allowBackup=&quot;false&quot;
            android:icon=&quot;@mipmap/ic_launcher&quot;
            android:label=&quot;@string/app_name&quot;
            android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
            android:theme=&quot;@style/AppTheme.CustomTheme&quot;
            android:usesCleartextTraffic=&quot;true&quot;
            tools:targetApi=&quot;m&quot;&gt;
            &lt;activity
                android:name=&quot;.systems.webview_activity.webview_base&quot;
                android:configChanges=&quot;orientation|screenSize&quot;&gt;
                &lt;intent-filter&gt;
                    &lt;category android:name=&quot;android.intent.category.BROWSABLE&quot; /&gt;
                    &lt;action android:name=&quot;android.intent.action.VIEW&quot; /&gt;
                    &lt;data android:scheme=&quot;file&quot; /&gt;
                    &lt;data android:mimeType=&quot;\*/\*&quot; /&gt;
                    &lt;data android:pathPattern=&quot;.*\\.kdb&quot; /&gt;
                    &lt;data android:host=&quot;*&quot; /&gt;
        
    
    //even if this method worked with Lectures_graph activity
    //it doesnt work with this one
    
                    &lt;action android:name=&quot;OPEN_ACTIVITY_WEBVIEW&quot; /&gt;
                    &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
                &lt;/intent-filter&gt;
            &lt;/activity&gt;
            &lt;activity
                android:name=&quot;.systems.lectures.Lectures_graph&quot;
                android:configChanges=&quot;keyboardHidden|screenSize&quot;
                android:label=&quot;@string/title_lectures_graph&quot;
                &gt;
                &lt;intent-filter&gt;
    
    //this intent filter provides correct response
    //to click_action which is provided in my PHP file
    
    
                    &lt;action android:name=&quot;OPEN_ACTIVITY_LECTURES&quot; /&gt;
                    &lt;action android:name = &quot;android.intent.action.CREATE_SHORTCUT&quot; /&gt;
                    &lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
                &lt;/intent-filter&gt;
            &lt;/activity&gt;
            &lt;activity
                android:name=&quot;.SplashScreen&quot;
                android:configChanges=&quot;keyboardHidden|orientation|screenSize&quot; &gt;
            &lt;intent-filter&gt;
                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;
                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
            &lt;/intent-filter&gt;
            &lt;/activity&gt;
            &lt;activity
                android:name=&quot;.NoInternetConnection&quot;
                android:configChanges=&quot;keyboardHidden|orientation|screenSize&quot; /&gt;
            &lt;activity
                android:name=&quot;secret.systems.about.about_app&quot;
                android:configChanges=&quot;orientation|keyboardHidden|screenSize&quot;
                android:theme=&quot;@style/FullscreenTheme&quot; /&gt;
            &lt;activity
                android:name=&quot;.MainActivity&quot;
                android:launchMode=&quot;singleTask&quot;
                android:configChanges=&quot;orientation|keyboardHidden|screenSize&quot;&gt;
        
            &lt;/activity&gt;
        
            &lt;service
                android:name=&quot;secret.services.MyFirebaseMessagingService&quot;
                android:enabled=&quot;true&quot;
                android:exported=&quot;false&quot;&gt;
                &lt;intent-filter&gt;
                    &lt;action android:name=&quot;com.google.firebase.MESSAGING_EVENT&quot; /&gt;
                &lt;/intent-filter&gt;
            &lt;/service&gt;
        &lt;/application&gt;
        
        &lt;/manifest&gt;

MyFirebaseMessagingService.java:

    public class MyFirebaseMessagingService extends FirebaseMessagingService {
    
        private static final String TAG = &quot;MyFirebaseMsgService&quot;;
    
        @Override
        public void onMessageReceived(RemoteMessage remoteMessage) {
    
            // Check if message contains a notification payload.
            if (remoteMessage.getNotification() != null) {
                Log.d(TAG, &quot;Message Notification Body: &quot; + remoteMessage.getNotification().getBody());
    
                //get key/value from notification
                String lectureDate = remoteMessage.getData().get(&quot;lecture_date&quot;);
                String web_url = remoteMessage.getData().get(&quot;web_url&quot;);
    
                if(lectureDate != null)sendLecturesNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), lectureDate);
                else if(web_url != null) sendNotificationWithURL(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody(), web_url);
                else Log.e(TAG, &quot;Message.notification is empty!&quot;);
            }
        }
    
        @Override
        public void onNewToken(@NonNull String token) {
            Log.d(TAG, &quot;Refreshed token: &quot; + token);
        }
    
        private void sendLecturesNotification(String title,String messageBody, String date) {
    
            Intent intent;
            intent = new Intent(this, Lectures_graph.class).putExtra(&quot;lecture_date&quot;, date).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    
            PendingIntent pendingIntent = PendingIntent.getActivity(this, ((int) System.currentTimeMillis()) /* Request code */, intent,
                    0);
    
            String channelId = getString(R.string.lectures_channel_id);
            Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            NotificationCompat.Builder notificationBuilder =
                    new NotificationCompat.Builder(this, channelId)
                            .setSmallIcon(R.drawable.secret)
                            .setContentTitle(title)
                            .setContentText(messageBody)
                            .setAutoCancel(true)
                            .setSound(defaultSoundUri)
                            .setContentIntent(pendingIntent);
    
            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
            if (notificationManager != null) {
                notificationManager.notify(((int) System.currentTimeMillis()), notificationBuilder.build());
            }
    
            Log.d(TAG, &quot;Lectures notification built with date:&quot;+date);
        }
    
        private void sendNotificationWithURL(String title, String messageBody, String web_url) {
    
            Intent intent;
            intent = new Intent(this, webview_base.class).putExtra(&quot;web_url&quot;, web_url).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
    
            PendingIntent pendingIntent = PendingIntent.getActivity(this, ((int) System.currentTimeMillis()) /* Request code */, intent,
                    0);
    
            String channelId = getString(R.string.newsfeed_channel_id);
            Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            NotificationCompat.Builder notificationBuilder =
                    new NotificationCompat.Builder(this, channelId)
                            .setSmallIcon(R.drawable.secret)
                            .setContentTitle(title)
                            .setContentText(messageBody)
                            .setAutoCancel(true)
                            .setSound(defaultSoundUri)
                            .setContentIntent(pendingIntent);
    
            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
            if (notificationManager != null) {
                notificationManager.notify(((int) System.currentTimeMillis()), notificationBuilder.build());
            }
    
            Log.d(TAG, &quot;Webview notification built with URL:&quot;+web_url);
        }
    }


a while ago i was getting an error in logcat that said something like &quot;default FCM channel is not defined&quot;, but im not quite sure thats the problem.

Even if i searched across the whole web, i would like to see better solutions/suggestions for notification (with its payload) handling when app is killed.

</details>


# 答案1
**得分**: 0

这是我修复了噩梦的方法

由于我无法从通知中打开多个特定活动为什么不直接打开我的应用程序主类并从那里处理额外的变量呢

不再为每个想要的活动添加以下内容

```xml
<intent-filter>
    <action android:name="OPEN_ACTIVITY_???????" />
    <category android:name="android.intent.category.DEFAULT" />
</intent-filter>

我做了这个:

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:configChanges="orientation|keyboardHidden|screenSize">
    <intent-filter>
        <action android:name="OPEN_APP" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

我在通知负载中添加了额外的变量(例如:'activity' => 'webview'),并在我的PHP代码中重命名了click_action。我在MainActivity.class中处理了所有负载,并从那里调用了所需的Android活动。MainActivity 代码:

Bundle extras = getIntent().getExtras();
if(extras == null) {
    Log.e("MainActivity", "No Activities passed in notification extras");
} else {
    //从通知负载中获取要打开的活动
    String activity = extras.getString("activity");
    if( activity != null){
        switch (activity){
            //webview 活动
            case "webview":
                //获取 webview 的 URL
                String web_url = extras.getString("web_url");
                if(web_url != null){
                    finish();
                    startActivity(new Intent(this, webview_base.class).putExtra("web_url", web_url));
                }
                break;
            //lectures 活动
            case "lectures":
                //获取讲座日期
                String lecture_date = extras.getString("lecture_date");
                if(lecture_date != null){
                    finish();
                    startActivity(new Intent(this, Lectures_graph.class).putExtra("lecture_date", lecture_date));
                }
                break;
        }
    }
}

希望这对某天的某人有所帮助。

干杯!

英文:

So i fixed my nightmare and here is how :

Since i cant open more than one specific activity from notifications, why could i just open my apps main class and handle extra variable from there ?

Instead of having for each wanted activity

   &lt;intent-filter&gt;
&lt;action android:name=&quot;OPEN_ACTIVITY_???????&quot; /&gt;
&lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
&lt;/intent-filter&gt;

i made this :

&lt;activity
android:name=&quot;.MainActivity&quot;
android:launchMode=&quot;singleTask&quot;
android:configChanges=&quot;orientation|keyboardHidden|screenSize&quot;&gt;
&lt;intent-filter&gt;
&lt;action android:name=&quot;OPEN_APP&quot; /&gt;
&lt;category android:name=&quot;android.intent.category.DEFAULT&quot; /&gt;
&lt;/intent-filter&gt;
&lt;/activity&gt;

I added extra variable to notifications payload (examle : 'activity' => 'webview') and renamed click_action in my PHP code. I handled all payloads in MainActivity.class and called wanted android activity from there. MainActivity code :

Bundle extras = getIntent().getExtras();
if(extras == null) {
Log.e(&quot;MainActivity&quot;, &quot;No Activities passed in notification extras&quot;);
} else {
//get opening activity from notification payload
String activity = extras.getString(&quot;activity&quot;);
if( activity != null){
switch (activity){
//webview activity
case &quot;webview&quot;:
//gets url for webview
String web_url = extras.getString(&quot;web_url&quot;);
if(web_url != null){
finish();
startActivity(new Intent(this, webview_base.class).putExtra(&quot;web_url&quot;, web_url));
}
break;
//lectures activity
case &quot;lectures&quot;:
//gets lecture date
String lecture_date = extras.getString(&quot;lecture_date&quot;);
if(lecture_date != null){
finish();
startActivity(new Intent(this, Lectures_graph.class).putExtra(&quot;lecture_date&quot;, lecture_date));
}
break;
}
}
}

Hope this helps someone, someday..

Cheers.

huangapple
  • 本文由 发表于 2020年8月4日 01:07:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/63233910.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定