概要
これまで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
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
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を追加します。
実機での確認
- Xcodeで「Run」を選択し、実機を起動します。
- FirebaseのMessaging APIでキャンペーンを1件作成します。
- しばらくするとメッセージが届き、アプリを開いているとNotification Countが1増えます。
推奨ライブラリへの切り替え
ドキュメントによれば、推奨されるライブラリが変更されたため、以下のように変更します。
target 'App' do
capacitor_pods
- pod 'Firebase/Messaging'
+ pod 'FirebaseCore'
+ pod 'FirebaseMessaging'
end
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つ追加するとこのエラーが発生することが分かりました。
参考にしたサイト