🥑

Expo Firebase FCMでAndroidのフォアグラウンドにバナー通知を実装

2025/01/25に公開

はじめに

こちらの記事の続きです。こちらでFCMから受け取れた値をバナー通知にしました。Androidは、バナー通知を自分で実装しなくてはならないので、ライブラリを使用して実装しました。
https://zenn.dev/yumemi9808/articles/c85c59ca750793

実装

バナー通知はこちらのreact-native-toast-messageというバナー通知を実装するライブラリを使用しました。
https://github.com/calintamas/react-native-toast-message

こちらのライブラリのCreate custom layoutsの実装を参考に実装しました。

_layout.tsxに置いて、全画面に通知がいくように実装します。

apps/mobile/src/app/_layout.tsx
import { Stack, usePathname } from 'expo-router'
import messaging from '@react-native-firebase/messaging'
import React, { useEffect } from 'react'
import { Image, ImageSourcePropType, StyleSheet, Text, View } from 'react-native'
import Toast from 'react-native-toast-message'
import { ENVIRONMENT } from '../../app.config'
import AppIcon from '../../assets/images/adaptive-icon.png'// ここがエラーになる
import { logScreenView } from '../utils/analytics'

type CustomToastProps = {
  text1?: string
  props?: {
    image?: ImageSourcePropType
    body?: string
  }
}

// カスタムしたバナー通知実装
export const toastConfig = {
  custom: ({ text1, props }: CustomToastProps) => (
    <View style={styles.toastContainer}>
      <Image source={props?.image} style={styles.icon} />
      <View style={styles.textContainer}>
        <Text style={styles.text1}>{text1}</Text>
        {props?.body && <Text style={styles.text2}>{props.body}</Text>}
      </View>
    </View>
  ),
}

// ビルド時の関係でTRPCの処理は一時コメントアウト
export default function Layout() {
  ・・・
  useEffect(() => {
    // FCMから受け取った値を入れる
    const unsubscribe = messaging().onMessage(remoteMessage => {
      if (remoteMessage?.notification) {
        const { title, body } = remoteMessage.notification

        // トーストを表示
        Toast.show({
          type: 'custom',
          text1: title || '',
          props: {
            image: AppIcon,
            body: body || '',
          },
        })
      }
    })
    return () => unsubscribe()
  }, [])

  return (
    <>
      <Stack
        screenOptions={{
          headerStyle: {
            backgroundColor: '#333',
          },
          headerTintColor: '#fff',
          headerTitleStyle: {
            fontWeight: 'bold',
          },
        }}
      >
        <Stack.Screen name="home" options={{ title: 'ホーム', headerShown: false }} />
        <Stack.Screen name="about" options={{ title: 'このアプリについて' }} />
        <Stack.Screen name="terms" options={{ title: '利用規約' }} />
      </Stack>
      <Toast config={toastConfig} />// ここに追加
    </>
  )
}

const styles = StyleSheet.create({
  toastContainer: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#FAFAFA',
    padding: 15,
    borderRadius: 12,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 3,
    elevation: 3,
    width: '95%',
    alignSelf: 'center',
  },
  icon: {
    width: 36,
    height: 36,
    borderRadius: 18,
    marginRight: 12,
  },
  textContainer: {
    flex: 1,
  },
  text1: {
    fontSize: 14,
    fontWeight: '600',
    color: '#333',
  },
  text2: {
    fontSize: 12,
    color: '#666',
    marginTop: 4,
  },
})

これで、全画面にバナー通知がいくように実装できました🎉

さいごに

たくさんバナー通知のライブラリはありましたが、一番スター数が多かったのと、カスタマイズができるのでeact-native-toast-messageというライブラリにしました。自分で見つけてライブラリを導入して使ってみたのは初めてだったので、いい経験になりました。Androidだけフォアグラウンドを実装する必要があるので、こちらを参考にぜひ作ってみてください。

Discussion