开发者问题收集

React Native + Firebase Cloud Messaging - 获取令牌导致服务工作者错误

2022-04-23
1549

我一直在尝试在我的 React Native 应用上配置和设置 Firebase Cloud Messaging,因为我希望我的项目具有点对点推送通知。我想将其发布到 Android,并最终发布到 iOS,但我一直在 Web 视图 (http://localhost:19006) 中测试它。该项目采用 TypeScript 编写,并使用 Stack.Router 和 Expo

./App.tsx

...
import FIREBASE from './src/http/firebase/interface';
...

export default function App() {
  
  React.useEffect(async () => {
    return await FIREBASE.init()
  });

  return (
      <SafeAreaProvider>
        <GlobalContextProvider>
          <Navigation colorScheme={colorScheme} />
          <StatusBar />
        </GlobalContextProvider>
      </SafeAreaProvider>
    );
}

./src/http/firebase

...
// EXPO INSTALL FIREBASE
import { initializeApp } from 'firebase/app';
import { getMessaging, getToken } from 'firebase/messaging';

import { 
    FIREBASE_API_KEY,
    FIREBASE_AUTH_DOMAIN,
    FIREBASE_DATABASE_URL,
    FIREBASE_PROJECT_ID,
    FIREBASE_STORAGE_BUCKET,
    FIREBASE_MESSAGING_SENDER_ID,
    FIREBASE_APP_ID,
    FIREBASE_WEB_VAPID_KEY,
    // @ts-ignore
} from '@env';

const firebaseConfig = {
  apiKey: FIREBASE_API_KEY,
  authDomain: FIREBASE_AUTH_DOMAIN,
  databaseURL: FIREBASE_DATABASE_URL,
  projectId: FIREBASE_PROJECT_ID,
  storageBucket: FIREBASE_STORAGE_BUCKET,
  messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,
  appId: FIREBASE_APP_ID,
};

// @ts-ignore
let firebase;
// @ts-ignore
let messaging;
if (!firebase) {
  firebase = initializeApp(firebaseConfig);
  console.log(firebase);
}

const init = async () => {
    // const registrations = await navigator.serviceWorker.getRegistrations();
    // if (registrations.length === 0) {
    //   const registration = await navigator.serviceWorker.register('./firebase-messaging-sw.js');
    //   console.log(registration)
    // }
    // @ts-ignore
    messaging = await getMessaging(firebase);
    console.log(messaging);

    switch(Platform.OS) {
      // case 'android':
      //   Do Nothing, as of now.

      case 'web': 
        // @ts-ignore
        if (messaging) {
          try {
            // @ts-ignore
            const token = await getToken(messaging, { vapidKey: FIREBASE_WEB_VAPID_KEY })
            if (token) {
              console.log(token);
            }
          } catch(err) {
            // TODO err handling
            console.log(err)
          }
        }
      // init app config
        break;

      case 'ios':
        break;
    }
};

const FIREBASE = {
    init,
    firebase,
    messaging,
};

export default FIREBASE;

版本:

"react-native": "0.64.3",
"react-native-firebase": "5.6",
"firebase": "^9.6.11",
"@react-native-firebase/app": "^14.8.0",
"@react-native-firebase/messaging": "^14.8.0", // Multiple versions of Firebase packages since I was struggling, and followed a handful of different guides.

我已按照指南将常见依赖项添加到 ./android/build.gradle 和 ./android/app/build.gradle

firebasemessaging 的两个日志按预期生成 FirebaseAppImpl 对象和 MessagingService 对象。 在加载应用程序的 Web 实例( expo start 并选择 web)时,我遇到了此错误:

FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker for scope ('http://localhost:19006/firebase-cloud-messaging-push-scope') with script ('http://localhost:19006/firebase-messaging-sw.js'): The script has an unsupported MIME type ('text/html').

firebase-messaging-sw.js 文件放在我的根文件夹和我的 web-build 文件夹中,因为我无权访问单个 /build 文件夹。

尝试在 Android 模拟器(Android Studio、Pixel XL API 30、Android 11.0 w/ Google API,否则为默认设置)中加载应用程序时,我收到以下错误:

[Unhandled promise rejection: TypeError: undefined is not an object (evaluating 'navigator.serviceWorker.addEventListener')]

[Unhandled promise rejection: FirebaseError: Messaging: This browser doesn't support the API's required to use the Firebase SDK. (messaging/unsupported-browser).]

我很感激任何见解或帮助。到目前为止,我觉得我已经浏览了数百篇关于 Firebase 和 React Native 的论坛帖子。

2个回答

firebase 消息传递仅支持 localhost HTTPS 主机

下面是我的 @/plugin/firebase.js

import { initializeApp } from 'firebase/app'
import { getMessaging, onMessage, isSupported } from 'firebase/messaging'

const firebaseConfig = {
  ...
}

const app = initializeApp(firebaseConfig)

let messaging = null

isSupported().then((result) => {
  if (result) {
    const messaging = getMessaging(app)
    onMessage(messaging, (payload) => {
      const options = {
        body: payload.notification.body,
        icon: '/img/icons/android-chrome-192x192.png',
        click_action: payload.data.click_action || '/some/path/for/click/action',
      }

      navigator.serviceWorker.getRegistration().then((reg) => {
        reg.showNotification(payload.notification.title, options)
      })
    })
  }
})

export default messaging

firebase-messaging-sw.js

importScripts('https://www.gstatic.com/firebasejs/9.6.11/firebase-app-compat.js')
importScripts('https://www.gstatic.com/firebasejs/9.6.11/firebase-messaging-compat.js')


const firebaseConfig = {
  ...
}

firebase.initializeApp(firebaseConfig)

let messaging = null

if (firebase.messaging.isSupported()) {
  const messaging = firebase.messaging()
  messaging.onBackgroundMessage(function (payload) {
    console.log('[firebase-messaging-sw.js] Received background message ', payload)
    const options = {
      body: payload.notification.body,
      icon: '/img/icons/android-chrome-192x192.png',
      click_action: payload.data.click_action || '/some/path/for/click/action',
    }

    return self.registration.showNotification(payload.notification.title, options)
  })
}
的代码片段>

希望这些对您有所帮助 :)

Ben Chung
2022-04-24

已修复:

React Native Expo 项目,

添加 web/ 目录,将 firebase-messaging-sw.js 放入其中,然后运行 ​​ expo build:web 以便在构建的 index.html 中正确引用 firebase sw 文件。

Michael S
2022-04-25