使用博览会推送通知对本机应用程序做出反应,在部署的构建中失败,但在本地失败

问题描述 投票:0回答:1

我有一个 React 本机应用程序,带有 expo 托管工作流程,以及 firebase 中的数据库。当用户登录应用程序时,系统会要求他们同意推送通知。

import { View, Text, StyleSheet, TextInput, Button } from "react-native";
import React, { useState } from "react";
import { useRouter } from "expo-router";
import { getAuth, signInWithEmailAndPassword } from "firebase/auth";
import "../firebaseConfig";
import { TouchableOpacity } from "react-native-gesture-handler";
import validateToken from "../api/validateToken";
import { useUser } from "../UserContext";
import * as Notifications from "expo-notifications";
import Constants from "expo-constants";

import axios from "axios";

const REACT_APP_ANDROID_EMULATOR_BASE_URL = Constants.expoConfig?.extra?.REACT_APP_ANDROID_BASE_URL;
const REACT_APP_EXPO_PROJECT_ID = Constants.expoConfig?.extra?.REACT_APP_EXPO_PROJECT_ID;

const LoginPage = () => {
  const { setUser } = useUser();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const navigation = useRouter();
  const [errorMessage, setErrorMessage] = useState<any>();

  const registerForPushNotificationsAsync = async () => {
    const { status } = await Notifications.requestPermissionsAsync();
    if (status !== "granted") {
      alert("Sorry, we need notification permissions to make this work!");
      return null;
    }

    const token = (
      await Notifications.getExpoPushTokenAsync({
        projectId: REACT_APP_EXPO_PROJECT_ID,
      })
    ).data;

    return token;
  };

  const handleLogin = async () => {
    try {
      const pushToken = await registerForPushNotificationsAsync();
      if (!pushToken) {
        setErrorMessage("Failed to register for notifications.");
        return;
      }

      const auth = getAuth();
      const ordinalCaseEmail = email.toLocaleLowerCase();
      const ordinalCasePassword = password.toLocaleLowerCase();
      const userCredential = await signInWithEmailAndPassword(auth, ordinalCaseEmail, ordinalCasePassword);
      const user = userCredential.user;

      const token = await user.getIdToken();
      const data = await validateToken(token);
      const response = await axios.get(`${REACT_APP_ANDROID_BASE_URL}/api/users/${user.uid}`);

      setUser({
        uid: user.uid,
        jwt: token,
        deviceToken: pushToken,
        userName: response.data.userName,
        email: response.data.email,
        image: response.data.image,
      });

      if (data.isValid) {
        await axios.post(`${REACT_APP_ANDROID_BASE_URL}/api/user/is-online`, {
          id: user.uid,
          online: true,
        });
        navigation.push("/(tabs)");
      } else {
        throw new Error("Invalid token or other server-side error");
      }
    } catch (error: any) {
      const errorMessage = error.response?.data?.error || error.message || "An unexpected error occurred.";
      setErrorMessage(errorMessage);
      console.error("Error: ", error);
    }
  };

这在通过 USB 连接的物理设备和 Android 模拟器上绝对可以正常工作。

但是,一旦部署并在物理设备和模拟器上运行已安装的应用程序,我会收到此错误:

“调用本机方法时遇到异常:在模块 ExpoPushTokenManager 上执行导出方法 getDevicePushTokenAsync 时发生异常:默认 FirebaseApp 在此过程中未初始化 com.teologi.newMotivationalExerciseApp。请确保首先调用 FirebaseApp.initializeApp(context)。”

我的 google-services.json 位于根级别。

{
  "project_info": {
    "project_number": "12345",
    "firebase_url": "https://motivationalexerciseapp-default-rtdb.europe-west1.firebasedatabase.app",
    "project_id": "motivationalexerciseapp",
    "storage_bucket": "motivationalexerciseapp.appspot.com"
  },
  "client": [
    {
      "client_info": {
        "mobilesdk_app_id": "1:132146:android:12345565",
        "android_client_info": {
          "package_name": "com.teologi.newMotivationalExerciseApp"
        }
      },
      "oauth_client": [],
      "api_key": [
        {
          "current_key": "12234665sdffgsdg"
        }
      ],
      "services": {
        "appinvite_service": {
          "other_platform_oauth_client": []
        }
      }
    }
  ],
  "configuration_version": "1"
}

我的 Firebase 配置

import { initializeApp } from "firebase/app";
import { connectFirestoreEmulator, getFirestore, writeBatch } from "firebase/firestore";
import { getAuth, initializeAuth, getReactNativePersistence } from "firebase/auth";
import ReactNativeAsyncStorage from "@react-native-async-storage/async-storage";
import { collection, query, getDocs, deleteDoc, doc } from "firebase/firestore";
import "firebase/firestore";
import "firebase/functions";

import Constants from "expo-constants";
const { apiKey, authDomain, projectId, storageBucket, messagingSenderId, appId } = Constants.expoConfig.extra;

const firebaseConfig = {
  apiKey: apiKey,
  authDomain: authDomain,
  projectId: projectId,
  storageBucket: storageBucket,
  messagingSenderId: messagingSenderId,
  appId: appId,
};

const app = initializeApp(firebaseConfig);

const db = getFirestore(app);

const auth = initializeAuth(app, {
  persistence: getReactNativePersistence(ReactNativeAsyncStorage),
});

export { db, auth };

我在这里读到:https://docs.expo.dev/push-notifications/push-notifications-setup/#android
在这里:https://docs.expo.dev/push-notifications/fcm-credentials/

我需要将我的服务帐户密钥添加到博览会仪表板中,所以我已经添加了,但仍然没有运气。我不确定我错过了什么。非常感谢任何帮助。

编辑 1:我现在注意到我在本节中一直在使用我的网络应用程序 api 密钥:

"extra": {
    "apiKey":"myOldWebApiKey"
}

我从 android 应用程序 google-services.json 文件中获得了一个新的。我没想到要切换它,因为在开发过程中 Web api 密钥从未失败过。这可能是问题所在吗?我将对其进行测试,但由于博览会中的低优先级构建队列,我需要一段时间才能注意到任何差异。

编辑2:仍然是同样的错误,我对我错过的东西感到茫然。

android firebase react-native push-notification expo
1个回答
0
投票

在这里发布对我有用的解决方案。可能看起来很明显,但我找不到任何地方可以证明这种情况。

在我的 google-services.json 中,我有一些看起来像这样的东西

{
  "project_info": {
    ...      },
  "client": [
    {
      "client_info": {
        ...
      },
      "oauth_client": [],
      "api_key": [
        {
          "current_key": "MY-AUTO-GENERATED-ANDROID-APP-API-KEY"
        }
      ],
      "services": {
        "appinvite_service": {
          "other_platform_oauth_client": []
        }
      }
    }
  ],
  "configuration_version": "1"
}

在我的 app.json 中,我有这个:

 "extra": {
      "REACT_APP_ANDROID_EMULATOR_BASE_URL": "...",
      "REACT_APP_EXPO_PROJECT_ID": "...",
      "apiKey": "MY-AUTO-GENERATED-WEB-APP-API-KEY",
      "authDomain": "...",
      "databaseURL": "...",
      "projectId": "...",
      "storageBucket": "...",
      "messagingSenderId": "...",
      "appId": "...",
      "router": {
        "origin": false
      },

所以,我基本上只需将 google-services.json 中的“current_key”值从 app.json 切换到我的 web-app apiKey(为了清楚起见,我在两个地方都使用了 web-app api 密钥)。

也许这是显而易见的,但在多个线程和演练中,我从未见过有人提到这一点,即使是“首先确保你已经检查了 api 密钥匹配”。

希望这对某人有帮助。干杯!

© www.soinside.com 2019 - 2024. All rights reserved.