MainActivity
MainActivity
Honnêtement, il n'y avait pas beaucoup de matériel auquel je pouvais me référer sur iOS, donc je l'ai implémenté moi-même, mais pour Android cet article a été très utile. Cependant, j'avais besoin de connaissances supplémentaires sur ce que je voulais mettre en œuvre cette fois, donc cet article l'inclut également.
Tout d'abord, l'activité principale. Ceci est ** juste une ligne, ajout de rubrique ** pour l'initialisation FCM. ** Si vous n'en avez même pas besoin, vous n'avez besoin de rien **, mais vous ne pourrez pas envoyer de notifications séparément entre ici et l'application de la version iOS.
MainActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseMessaging.getInstance().subscribeToTopic("TOPICNAME");
// other initializing...
}
Ensuite, récupérez le jeton d'appareil généré / mis à jour.
Ceci est essentiel si vous voulez des notifications différentes pour différents périphériques [^ 1], mais l'heure exacte à laquelle vous pouvez le faire est FirebaseInstanceIdService # onTokenRefresh
. Vous pouvez remplacer cela et envoyer le jeton d'appareil à votre propre serveur à ce moment-là.
Mais cette fois, j'ai juste besoin de pouvoir envoyer des notifications à tous les utilisateurs à la fois, et je ne sais pas si j'ai encore besoin du service FirebaseInstanceIdService
.
Si vous n'en avez pas besoin, ce sera ** encore une fois "vous n'avez rien à faire" **. Cependant, j'étais un peu mal à l'aise, alors j'ai décidé de ne laisser fonctionner que le service, donc je l'ai configuré pour démarrer la superclasse directement en tant que service sans créer de sous-classe. Est-ce correct?
AndroidManifest.xml
<service android:name="com.google.firebase.iid.FirebaseInstanceIdService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
</intent-filter>
</service>
Même dans FCM, article GCM que j'ai écrit dans mon travail précédent (chapitre de "balise qui peut automatiquement écraser et mettre à jour les notifications Android") -2.html) n'a pas modifié la spécification d'actualisation ** "Si vous recevez des notifications standard sur Android / uniquement en arrière-plan, vous n'avez pas besoin d'écrire de code" **.
Mais cette fois, vous devez également gérer la notification au premier plan.
Pour ce faire, vous pouvez remplacer FirebaseMessagingService # onMessageReceived
et le faire. Parmi eux, vous pouvez générer le même contenu que la notification affichée en arrière-plan et l'enregistrer comme intention en attente.
Je veux dire, c'est l'article de @ kirimin C'est presque la même chose. C'est juste une tempête de pluie reconnaissante (mot mort). Cependant, seule la génération de l'intention lorsque la notification affichée par ce code est appuyée est légèrement modifiée.
Fondamentalement, cette intention a glissé dans le processus, oh, cerveau COM (et pour une raison quelconque en tapant ceci) De plus, comme il n'est utilisé que dans la propre application, pas dans le cerveau pro-less où le doigt glisse et frappe sans problème), je me demande si la constante de chaîne de caractères doit être définie dans MainActivity
et utilisée. C'est «MainActivity.ARG_FRAGMENT» et «MainActivity.PUSH_NOTIFICATION_ACTION».
FirMessagingService.java
public class FirMessagingService extends FirebaseMessagingService {
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
Map<String, String> data = remoteMessage.getData();
if (data == null) {
return;
}
String fragment = data.get(MainActivity.ARG_FRAGMENT);
if (fragment == null) {
return;
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext());
builder.setSmallIcon(R.drawable.notification);
builder.setContentTitle(remoteMessage.getNotification().getTitle());
builder.setContentText(remoteMessage.getNotification().getBody());
builder.setDefaults(Notification.DEFAULT_SOUND
| Notification.DEFAULT_VIBRATE
| Notification.DEFAULT_LIGHTS);
builder.setAutoCancel(true);
//Créer une intention en attente
Intent intent = new Intent(this, MainActivity.class);
intent.setAction(MainActivity.PUSH_NOTIFICATION_ACTION);
intent.putExtra(MainActivity.ARG_FRAGMENT, fragment);
PendingIntent contentIntent = PendingIntent.getActivity(
getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
//Affichage des notifications
NotificationManagerCompat manager = NotificationManagerCompat.from(getApplicationContext());
manager.notify(0, builder.build());
}
}
Bien entendu, n'oubliez pas d'enregistrer cette sous-classe en tant que service.
AndroidManifest.xml
<service android:name=".FirMessagingService">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT"/>
</intent-filter>
</service>
À ce propos, le règlement «Le mode de lancement est une tâche unique» fonctionne de manière extrêmement efficace, et il n'y a que deux modèles qui peuvent se produire lorsque vous appuyez sur une notification. (Notez que ce règlement n'a rien à voir avec FCM, c'est une méthode courante pour toujours démarrer une seule application sur Android, et c'est très courant [^ 2])
Activité | Appelé lorsque vous appuyez surAppCompatActivity méthode de |
Comment obtenir une intention |
---|---|---|
Au démarrage | onNewIntent |
onNewIntent Arguments de |
Pas commencé | onCreate |
getIntent Méthode |
Et dans les deux cas, vous pouvez recevoir une intention contenant exactement les mêmes informations, vous pouvez donc la gérer avec une méthode commune.
MainActivity.java
public static final String PUSH_NOTIFICATION_ACTION = "FCM";
public static final String ARG_FRAGMENT = "fragment";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FirebaseMessaging.getInstance().subscribeToTopic("TOPICNAME");
int fragmentId = onIntent(getIntent());
if (fragmentId == 0) {
//Obtenez la valeur d'ID du fragment le plus récemment affiché
fragmentId = PreferenceManager.getDefaultSharedPreferences(this).getInt(PreferenceKey.RECENT_FRAGMENT_POSITION, 0);
}
// other initializing
changeFragment(fragmentId, true);
}
@Override
public void onNewIntent(Intent intent) {
super.onNewIntent(intent);
changeFragment(onIntent(intent), false);
}
//Obtenez l'ID du fragment que vous souhaitez afficher à partir de l'intention de notification
//Dans cette implémentation, pour les notifications{"fragment":"info"}Si le KV est inclus, j'essaye d'afficher l'écran d'information
//Si vous utilisez la réflexion, vous n'avez pas besoin de branchement conditionnel,(^^ゞ
private int onIntent(Intent intent) {
if (intent != null && "info".equals(intent.getStringExtra(ARG_FRAGMENT))) {
return R.id.info;
} else {
return 0;
}
}
//Méthode unique pour basculer vers Fragment spécifié par fragmentId s'il existe
//Si isFirst est true, affiche le Fragment par défaut si fragmentId est 0
//Si faux, ne faites rien
private void changeFragment(int fragmentId, boolean isFirst) {
//Faisons de notre mieux
}
Ensuite, définissez correctement le filtre d'intention afin que MainActivity
puisse recevoir l'intention de la notification. La raison sera expliquée plus tard, mais le nom de l'action «" FCM "» doit être la même chaîne que ** «MainActivity.PUSH_NOTIFICATION_ACTION» **.
AndroidManifest.xml
<activity android:label="@string/app_name" android:name=".MainActivity"
android:taskAffinity="com.wsf_lp.oritsubushi.map" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="FCM" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
En fait, si vous ne le faites pas correctement non seulement du côté de l'application mais aussi du côté de votre propre serveur, vous tomberez quelque part dans la série de mouvements «d'envoi et de réception de notifications et de changement d'affichage».
Donc, j'ai résumé la liste des littéraux de chaîne qui sont sortis jusqu'à présent dans la série de codes et leurs significations.
Chaîne | Lieu d'apparence | sens | Le cas échéant |
---|---|---|---|
"FCM" | Manifeste Activité principale |
Nom de l'action d'intention | De la charge utile de notification FCMclick_action La valeur duonMessageReceived Intention créée aveconNewIntent Intention transmise àonCreate À l'intérieurgetIntent Intention obtenue en appelant |
"fragment" | FirebaseMessagingService Activité principale |
Nom de la clé de données utilisateur | Nom de clé dans la charge de données FCMonMessageReceived Nom de la clé dans les données distantes pouvant être obtenues avec |
"info" | FirebaseMessagingService Activité principale |
Valeur des données utilisateur | De la charge utile des données FCM"fragment"La valeur duonMessageReceived で取得できるリモートデータ内La valeur du |
C'est simple à résumer, mais "FCM payload" apparaît dans tous les éléments du tableau. En fait, il est très important de comprendre ** la charge utile sur votre propre serveur qui transmet les données à envoyer à FCM **. En d'autres termes, cela signifie également que ** lors de la liaison du fonctionnement de l'application avec des notifications push, l'omission de "saisir facilement le contenu de la notification depuis l'écran de notification de la console Firebase et cliquer (mot mort)" n'est pas autorisée **. (Bien sûr, compte tenu du problème d'icône décrit plus loin, la console actuelle est inutile depuis le début).
En ce qui concerne la charge utile FCM, Elle est répertoriée dans le document officiel, mais il ne suffit pas de simplement l'utiliser, [Tous les formats] Il semble indispensable de lire correctement (https://firebase.google.com/docs/cloud-messaging/http-server-ref).
Dans cet esprit, voici les JSON que j'envoie de mon propre serveur au serveur FCM.
{
"to": "Nom du sujet enregistré dans l'application",
"notification": {
"title": "Titre de la notification",
"body": "Corps de notification",
"click_action": "FCM",
"icon": "notification"
},
"data": {
"fragment": "info"
}
}
La chose la plus importante dans FCM est la notification
, la charge utile de notification.
En plus de title
et body
, click_action
est l'une des clés. Il s'agit exactement de la valeur de l'action contenue dans l'intention de notification push Android [^ 3]. Et avec la valeur de cette action, c'est le paramètre du filtre d'intention dans le manifeste qui empêche l'activité de l'application de recevoir des intentions supplémentaires.
Par conséquent, * le click_action
de la charge utile de notification envoyée au serveur FCM et le nom d'action du filtre d'intention défini dans le manifeste doivent correspondre *, et * l'intention générée par l'utilisateur d'afficher la notification même au premier plan. Les noms d'action doivent également être identiques *.
D'un autre côté, la "data", qui est facultative dans FCM, c'est-à-dire la charge utile de données, est un dictionnaire normal. Et c'est celui qui est passé tel quel au RemoteMessage
qui est passé dans l'argument de FirebaseMessagingService # onMessageReceived
, et il est également obtenu par l'argument de getIntent
et ʻonNewIntent appelé à l'intérieur de ʻonCreate
de l'activité. Il s'agit de la valeur définie comme le supplément de l'intention qui peut être effectuée.
Donc * ces noms de clé doivent correspondre * et * la même valeur doit être copiée en tant qu'extra avec le même nom de clé dans l'intention qu'ils génèrent pour afficher la notification même au premier plan. *.
De plus, comme il ne sera pas internationalisé cette fois, c'est comme écrire du japonais tel qu'il est dans title
et body
, mais si l'internationalisation est nécessaire article GCM écrit dans mon travail précédent (: //www.mate-en.com/techblog/google-cloud-messaging-2.html) devrait être utile tel quel.
Et encore une fois, mais pas directement lié au code.
Sur Android, une icône peut être affichée dans l'affichage des notifications. Et dans les anciennes versions de GCM avant FCM, GCMListenerService # onMessageReceived
est * toujours appelé * indépendamment du fait que l'application soit au premier plan ou en arrière-plan * (donc GCM ListerService
doit être un service. Je ne l'ai pas fait), et j'ai toujours créé les notifications moi-même (juste dans le processus dans ʻonMessageReceived au premier plan dans le FCM actuel). Bien sûr, j'étais libre d'y définir l'icône de notification. Cependant, le nouveau GCM après cela, qui est presque le FCM actuel, a introduit la spécification que * ʻonMessageReceived
n'est pas appelé en arrière-plan * ".
Et par conséquent, vous ne pourrez pas définir l'icône en arrière-plan. Pour éviter cela, le nom de clé «icône» a été ajouté à la charge utile de notification de GCM, et il est transféré au FCM actuel.
{
"notification": {
"icon": "notification"
}
}
Et c'est aussi une métamorphose, mais supposons que vous définissiez la valeur notification
sur ʻiconcomme ci-dessus. Cette valeur de «notification» a été mappée sur «R.drawable.notification» du côté de l'application. Bien sûr, ce symbole est une valeur d'identification, et si l'icône est un fichier image, en particulier un fichier appelé
res / drawable / notification.png (bien sûr, la substance a été divisée par résolution / version SDK / local, etc. (Distribué en dossiers) est utilisé comme icône. Le fait est que ** le nom de fichier (à l'exclusion de l'extension) de l'image PNG pour l'icône sera la valeur de la clé ʻicon
de la charge utile de notification **. En d'autres termes, pour afficher l'icône de notification, vous pouvez généralement créer (beaucoup!) D'images d'icônes, les placer de manière appropriée sous res / drawable / et transmettre le nom de fichier au serveur FCM.
Bien sûr, la même icône doit être placée dans ʻonMessageReceived` pour afficher la notification même au premier plan.
Ce sentiment que "la chaîne de caractères du nom de fichier devient un nom de symbole dans le code Java et il devient une valeur entière lorsqu'elle est référencée, mais lors de l'appel depuis le serveur, spécifiez-le avec une chaîne de caractères", il fait le tour et revient au sentiment d'origine .. Comme prévu, il s'agit d'Android (poitrine brûlée) [^ 4].
[^ 1]: s'il s'agit d'une application SNS ou de chat, le contenu à notifier dépend de l'utilisateur. Par conséquent, les jetons de périphérique de l'utilisateur et du terminal (bien sûr, le même utilisateur peut utiliser plusieurs périphériques, donc RDB le gère dans la table n: m) sont liés du côté du serveur pour notifier un utilisateur spécifique. Le processus d'envoi uniquement à tous les appareils de cet utilisateur est requis. Et cette notification de l'appareil de cet utilisateur particulier ne nécessite qu'un jeton d'appareil, et Android peut changer ce jeton d'appareil, donc chaque fois qu'il change, il informe son propre serveur. Doit être.
[^ 2]: Ah, à l'ère Win32, cela a été fait avec un Mutex nommé ... La première version de Windows Eclipse a juste trop cliqué sur l'icône et a démarré plusieurs fois, donc pour éviter de casser l'espace de travail, un lanceur dédié Je l'ai écrit avec CreateMutex
... (À cause de vieux yeux, de yeux lointains)
[^ 3]: Au fait, click_action
, qui est un bouton qui apparaît lorsque vous faites glisser une notification sur iOS (si l'application le prend en charge) = est lié à une action personnalisée. C'est une clé héritée de GCM, mais il est étonnant qu'elle soit compatible avec les deux OS! C'est un éloge.
[^ 4]: Bien sûr, la conversion de symboles en valeurs entières et la construction auraient été nécessaires sur les anciens Androïdes, qui avaient des ressources incroyablement pauvres. Et même à l'ère actuelle où ce n'est pas le cas, il y a un avantage que l'achèvement du code de l'EDI fonctionne facilement (même dans l'ancien temps, il a été abusé comme un mauvais savoir-faire de VC ++ en fourrant tout dans une classe mystérieuse). Non, mais je pense aussi qu'une partie importante du caractère déraisonnable de l'API Win32 est qu'elle a été trop traînée par Win16 pour rendre le code des contrôles OLE que la société a fait en interne pour VB compatible (ou plutôt mal). La racine peut être VB plus ancienne que Win16 ??), Android est également entraîné par diverses choses comme la limitation de la méthode 64k (du coup, il est très difficile de faire Scala) ... Est-ce quelque chose qui a une histoire? ..
Recommended Posts