LoginSignup
3
0

CapacitorとReactを使用したFCMによるiOSプッシュ通知機能の実装についての体験談

Last updated at Posted at 2023-12-20

概要

これまでFlutterを用いて簡易的なiOSアプリ開発の経験はありましたが、Flutterの学習は時間がかかるため、JavaScriptを使用してiOSアプリを開発できる「Capacitor」に興味を持ち、その機能を試してみることにしました。

前提

  • Apple Developer Program に加入済みであること。

実装プロセス

この記事では、Capacitorのドキュメントや他のウェブサイトを参考にしながら、Push通知機能を作成した流れの説明を行なっています。

アプリの構築

ReactとCapacitorの初期化コマンドを使ってアプリを構築する方法について説明します。

1. Reactアプリの作成

npx create-react-app capacitor-tutorial
cd capacitor-tutorial

2. Capacitorを導入

npm i @capacitor/core
npm i -D @capacitor/cli
npx cap init

Capacitorアプリの初期設定では、プロジェクト名とアプリのPackage IDを入力します。
Package IDはFirebaseの設定にも使用されます。

3. iOSのプロジェクトを作成

npm i @capacitor/ios
npx cap add ios

Firebaseの設定

1. Firebaseの設定
Firebaseの設定に関しては、以下のサイトを参照してください。

2. Firebase/Messagingを導入

Podfileに Firebase/Messaging を追加

Podfile
Podfile
require_relative '../../node_modules/@capacitor/ios/scripts/pods_helpers'

platform :ios, '13.0'
use_frameworks!

# workaround to avoid Xcode caching of Pods that requires
# Product -> Clean Build Folder after new Cordova plugins installed
# Requires CocoaPods 1.6 or newer
install! 'cocoapods', :disable_input_output_paths => true

def capacitor_pods
  pod 'Capacitor', :path => '../../node_modules/@capacitor/ios'
  pod 'CapacitorCordova', :path => '../../node_modules/@capacitor/ios'
  pod 'CapacitorPushNotifications', :path => '../../node_modules/@capacitor/push-notifications'
  pod 'CapacitorToast', :path => '../../node_modules/@capacitor/toast'
end

target 'App' do
  capacitor_pods
  # Add your Pods here
  pod 'Firebase/Messaging'
end

post_install do |installer|
  assertDeploymentTarget(installer)
end

Reactでの実装

Reactを使った具体的な実装方法

1. ライブラリをインストール

npm i @capacitor/push-notifications @capacitor/toast
npx cap update ios

2. App.jsを更新

プッシュ通知を受け取れ、簡単に確認できるようにApp.jsを更新しました。
@capacitor/push-notificationsの詳細についてはまだ完全に理解していないため、主にコピペを使用しました。

以下のサイトのIonic Reactのコードを参考にしました。

App.js
App.js
import React, { useEffect, useState } from 'react';
import logo from './logo.svg';
import './App.css';
import { PushNotificationSchema, PushNotifications, Token, ActionPerformed } from '@capacitor/push-notifications';
import { Toast } from "@capacitor/toast";

function App() {
  const nullEntry = []
  const [notifications, setnotifications] = useState(nullEntry);

  useEffect(()=>{
      PushNotifications.checkPermissions().then((res) => {
          if (res.receive !== 'granted') {
            PushNotifications.requestPermissions().then((res) => {
              if (res.receive === 'denied') {
                showToast('Push Notification permission denied');
              }
              else {
                showToast('Push Notification permission granted');
                register();
              }
            });
          }
          else {
            register();
          }
        });
  // eslint-disable-next-line react-hooks/exhaustive-deps
  },[])

  const register = () => {
      // Register with Apple / Google to receive push via APNS/FCM
      PushNotifications.register();

      // On success, we should be able to receive notifications
      PushNotifications.addListener('registration',
          (token: Token) => {
              showToast('Push registration success');
          }
      );

      // Some issue with our setup and push will not work
      PushNotifications.addListener('registrationError',
          (error: any) => {
              alert('Error on registration: ' + JSON.stringify(error));
          }
      );

      // Show us the notification payload if the app is open on our device
      PushNotifications.addListener('pushNotificationReceived',
          (notification: PushNotificationSchema) => {
              setnotifications((notifications: any) => [...notifications, { id: notification.id, title: notification.title, body: notification.body, type: 'foreground' }])
          }
      );

      // Method called when tapping on a notification
      PushNotifications.addListener('pushNotificationActionPerformed',
          (notification: ActionPerformed) => {
              setnotifications((notifications: any) => [...notifications, { id: notification.notification.data.id, title: notification.notification.data.title, body: notification.notification.data.body, type: 'action' }])
          }
      );
  }

  const showToast = async (msg: string) => {
      await Toast.show({
          text: msg
      })
  }

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React.
        </a>
        <div>
          <h2>Push Notification</h2>
          <p>Notification Count: {notifications.length}</p>
        </div>
      </header>
    </div>
  );
}

export default App;

3. webのコードをiOSに同期

npm run build
npx cap sync

Xcodeでの設定

Xcodeでの設定手順

1. Xcodeを開く

npx cap open ios

2. 確認デバイスを実機に変更

Runnerをsimulatorから実機に変更

3. Teamを選択

「Targets > App > Signing & Capabilities」で「Team」を選択します(デフォルトはNone)

4. Capabilityを追加

「Targets > App > Signing & Capabilities」で「+ Capability」を選択し、Push Notificationを追加します。

実機での確認

  1. Xcodeで「Run」を選択し、実機を起動します。
  2. FirebaseのMessaging APIでキャンペーンを1件作成します。
  3. しばらくするとメッセージが届き、アプリを開いているとNotification Countが1増えます。

推奨ライブラリへの切り替え

ドキュメントによれば、推奨されるライブラリが変更されたため、以下のように変更します。

Podfile
target 'App' do
  capacitor_pods
- pod 'Firebase/Messaging'
+ pod 'FirebaseCore'
+ pod 'FirebaseMessaging'
end
AppDelegate.swift
    import UIKit
    import Capacitor
- import Firebase
+ import FirebaseCore
+ import FirebaseMessaging

遭遇した問題と解決策

Firebase SDK の重複

iOSの設定に不慣れな中、Firebaseのドキュメントに従って設定した後、「FirebaseMessaging」を追加すると、Swift Package ManagerとCocoaPodsでのインストールが干渉し、エラーが発生しました。

[FirebaseCore][I-COR000003] The default Firebase app has not yet been configured. Add `FirebaseApp.configure()` to your application initialization. This can be done in in the App Delegate's application(_:didFinishLaunchingWithOptions:)` (or the `@main` struct's initializer in SwiftUI). Read more: https://goo.gl/ctyzm8.

このエラーに関する検索では、「GoogleService-Info.plistが正しく配置されていない」「Firebase.configure()が正しく記述されていない」といった内容の記事が多く、時間の浪費となりました。

新規にアプリを作成し直したところ問題なく動作し、SDKを2つ追加するとこのエラーが発生することが分かりました。

参考にしたサイト

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0