TIL[05/16]

Holyday33·2022년 5월 17일
0
  1. FCM

FCM


o. 노드 패키지 다운

npm i @react-native-firebase/analytics @react-native-firebase/app @react-native-firebase/messaging
npm i react-native-push-notification @react-native-community/push-notification-ios
npm i -D @types/react-native-push-notification
npx pod-install
  1. google-services.json을 android/app에 넣는다.
  2. android/build.gradle에 다음 3줄 추가
buildscript {
  repositories {
    google()   //요거
  }
  dependencies {
    classpath 'com.google.gms:google-services:4.3.10'//요거
  }
}
allprojects {
  repositories {
    google()  //요거

  }
}
  1. android/app/build.gradle에 3줄 추가
apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'//요거


dependencies {

  implementation platform('com.google.firebase:firebase-bom:30.0.1')//요거
  implementation 'com.google.firebase:firebase-analytics'//요거


}
  1. 파베콘솔 사이트에서 프로젝트 설정 -> 서비스 계정 -> Firebase Admin SDK 에서 새 비공개 키 생성을 다운받는다. (본인의 경우 다음과 같은 이름)

    fooddeliveryapp-da18e-firebase-adminsdk-lp6nt-38f98578d8.json

  2. 이 JSON파일을 백엔드에 저장한다. 그리고 node인 경우 app.js에 다음을 복붙한다. (json 파일명을 위의 파일명으로 바꾸는 것을 잊지 말자)

var admin = require("firebase-admin");

var serviceAccount = require("path/to/serviceAccountKey.json");

admin.initializeApp({
  credential: admin.credential.cert(serviceAccount)
});

제로초 강의는 조금 다르다. 다음을 복붙한다. (databaseURL의 주소 내용중fooddeliveryapp-6609a는 GOOGLE_APPLICATION_CREDENTIALS의 이름에서 나온다. 반드시 동일하게 해야한다.)

process.env.GOOGLE_APPLICATION_CREDENTIALS =
  "./fooddeliveryapp-6609a-firebase-adminsdk-nev9a-603a8b9ae6.json";

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
  databaseURL: "https://fooddeliveryapp-6609a.firebaseio.com",
});
  • 자바는 다음을 복붙한다.

FileInputStream serviceAccount =
  new FileInputStream("path/to/serviceAccountKey.json");

FirebaseOptions options = new FirebaseOptions.Builder()
  .setCredentials(GoogleCredentials.fromStream(serviceAccount))
  .build();

FirebaseApp.initializeApp(options);
  1. 다음 코드를 복사해서 android/app/src/main/AndroidManifest.xml에 붙인다.
  • uses-permission에 맞게
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
  • application 태그 안에
   <meta-data  android:name="com.dieam.reactnativepushnotification.notification_foreground"
                    android:value="false"/>
        <!-- Change the resource name to your App's accent color - or any other color you want -->
        <meta-data  android:name="com.dieam.reactnativepushnotification.notification_color"
                    android:resource="@color/white"/> <!-- or @android:color/{name} to use a standard color -->

        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationActions" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <action android:name="android.intent.action.QUICKBOOT_POWERON" />
                <action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
            </intent-filter>
        </receiver>

        <service
            android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
  1. android/app/src/main/res/values/colors.xml에 다음 복붙
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="white">#FFF</color>
</resources>
  1. MainActivity.java에 다음 코드 복붙
@Override
    public void onNewIntent(Intent intent) {
        ...
        super.onNewIntent(intent);
        ...
    }

설정 끝

이제 프론트에서 푸쉬를 보내보자

  1. App.tsx에서 컴포넌트 밖에 붙여넣는다.

import messaging from '@react-native-firebase/messaging';
import PushNotification from 'react-native-push-notification';
import PushNotificationIOS from '@react-native-community/push-notification-ios';


messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('Message handled in the background!', remoteMessage);
});
PushNotification.configure({
  // (optional) 토큰이 생성될 때 실행됨(토큰을 서버에 등록할 때 쓸 수 있음)
  onRegister: function (token: any) {
    console.log('TOKEN:', token);
  },

  // (required) 리모트 노티를 수신하거나, 열었거나 로컬 노티를 열었을 때 실행
  onNotification: function (notification: any) {
    console.log('NOTIFICATION:', notification);
    if (notification.channelId === 'riders') {
      // if (notification.message || notification.data.message) {
      //   store.dispatch(
      //     userSlice.actions.showPushPopup(
      //       notification.message || notification.data.message,
      //     ),
      //   );
      // }
    }
    // process the notification

    // (required) 리모트 노티를 수신하거나, 열었거나 로컬 노티를 열었을 때 실행
    notification.finish(PushNotificationIOS.FetchResult.NoData);
  },

  // (optional) 등록한 액션을 누렀고 invokeApp이 false 상태일 때 실행됨, true면 onNotification이 실행됨 (Android)
  onAction: function (notification: any) {
    console.log('ACTION:', notification.action);
    console.log('NOTIFICATION:', notification);

    // process the action
  },

  // (optional) Called when the user fails to register for remote notifications. Typically occurs when APNS is having issues, or the device is a simulator. (iOS)
  onRegistrationError: function (err: Error) {
    console.error(err.message, err);
  },

  // IOS ONLY (optional): default: all - Permissions to register.
  permissions: {
    alert: true,
    badge: true,
    sound: true,
  },

  // Should the initial notification be popped automatically
  // default: true
  popInitialNotification: true,

  /**
   * (optional) default: true
   * - Specified if permissions (ios) and token (android and ios) will requested or not,
   * - if not, you must call PushNotificationsHandler.requestPermissions() later
   * - if you are not using remote notification or do not have Firebase installed, use this:
   *     requestPermissions: Platform.OS === 'ios'
   */
  requestPermissions: true,
});
PushNotification.createChannel(
  {
    channelId: 'riders', // (required)
    channelName: '앱 전반', // (required)
    channelDescription: '앱 실행하는 알림', // (optional) default: undefined.
    soundName: 'default', // (optional) See `soundName` parameter of `localNotification` function
    importance: 4, // (optional) default: 4. Int value of the Android notification importance
    vibrate: true, // (optional) default: true. Creates the default vibration patten if true.
  },
  (created: boolean) =>
    console.log(`createChannel riders returned '${created}'`), // (optional) callback returns whether the channel was created, false means it already existed.
);
  1. 서버에 보낼 토큰 가져오기 Appinner.tsx의 컴포넌트 안에 복붙하고 폰토큰을 저장할 state를 slice.ts에 추가
  // 토큰 설정
  import messaging from '@react-native-firebase/messaging';

  useEffect(() => {
    async function getToken() {
      try {
        if (!messaging().isDeviceRegisteredForRemoteMessages) {
          await messaging().registerDeviceForRemoteMessages();
        }
        const token = await messaging().getToken();
        console.log('phone token', token);
        dispatch(userSlice.actions.setPhoneToken(token));
        return axios.post(`${Config.API_URL}/phonetoken`, {token});
      } catch (error) {
        console.error(error);
      }
    }
    getToken();
  }, [dispatch]);
	
const initialState = {
  name: '',
  email: '',
  accessToken: '',
  phoneToken:'',
};

...

setPhoneToken:(state, action)=> {
	state.phoneToken = action.payload.phoneToken;
}
    

실제 기기 연결하기


  1. 다음 명령어로 연결된 android기기 확인하기
adb devices
  1. npm run android로 안드로이드기기에 앱 설치하기
  • 에러 : No matching client found for package name
  • 에러 :
    /Users/timothy/project/RN/f2/FoodDeliveryApp/android/app/src/main/AndroidManifest.xml Error:
            android:exported needs to be explicitly specified for <receiver>. Apps targeting Android 12 and higher are required to specify an explicit value for `android:exported` when the corresponding component has an intent filter defined. See https://developer.android.com/guide/topics/manifest/activity-element#exported for details.
    • AndroidManifest.xml에 android:exported="false"추가
    • 해결 : 링크
  • 에러 : app:compileDebugJavaWithJavac
    • cd android ./gradlew -v로 버전체크
      • 에러 : zsh: permission denied: ./gradlew
      • 해결 : chmod +x gradlew  콘솔창에 입력
    • 호환되는 gradle 버전 보는 곳 링크
    • gralde 버전 변경 방법 링크
      • 그냥 숫자를 바꾸고 안드로이드 스튜디오에서 sync now를 누르면된다.
    • ./gradlew clean
      • 에러 : zsh: command not found: gradlew
        • ./gradlew
    • Error: Command failed: ./gradlew app:installDebug 해결 방법 링크
    • :react-native-safe-area-context:compileDebugKotlin
    • ⭐️⭐️⭐️error: cannot find symbol
      public void onNewIntent(Intent intent) {
      ^
      symbol: class Intent
      location: class MainActivity
      • ⭐️⭐️⭐️문제해결 MainActivy.java에 import android.content.Intent; 추가
      • 링크

성공 연결완료

에러 : 아이폰은 axios가 작동되지만 안드로이드에서는 Axios Network 에러 발생한다.


알고보니 Config.API_URL이 작동이 안되고 있었다.


이미 잘 설명해놓은 블로그 글들

profile
Why so serious?

0개의 댓글