Push Notifications with Laravel, Ionic-Vue, and Firebase
Tags: laravel, ionic, firebase, javascript
Published: 2022-02-14 17:06:42

## To get started
This article will cover implementing push notifications on iOS using Laravel, Ionic-Vue, Capacitor, and Firebase.

This article will not cover how to create a Laravel or Ionic-Vue application.

The technologies that will be needed for this tutorial:

- Laravel application

- Ionic-Vue application

- Capacitor

- Firebase Account

## Let us start with Ionic-Vue
Once you have a working Ionic-Vue application, make sure you run the `ionic cap build` command and choose the `ios` option.

![ionic cap build command](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4gt9fchsdve608yl0r6c.png)
 

As per the [documentation](https://capacitorjs.com/docs/apis/push-notifications), the push notifications capabilities will need to be enabled. To do this, you will need to open Xcode and make sure that you are on the project navigator folder in the left navigation bar. Then click on your application, and you will see a screen with an option for Signing and Capabilities.

![Signing and Capabilities](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/11bu80qhjal1ej1kcv79.png)

Click the `+ Capability` and choose Background Modes and Push Notifications. There will be two options you will need to check for the Background Modes: background fetch and remote notifications.

As per the documentation you will also need to paste these two snippets of code into your AppDelegate file in Xcode.

```swift
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
  NotificationCenter.default.post(name: .capacitorDidRegisterForRemoteNotifications, object: deviceToken)
}

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
  NotificationCenter.default.post(name: .capacitorDidFailToRegisterForRemoteNotifications, object: error)
}
```

![AppDelegate file](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/54u1et17ztx5yexxybqw.png)

## Setting up our APNS key
An APNS key will need to be generated in order to communicate between Firebase and Apple. To do this, visit [this link](https://developer.apple.com/account/resources/authkeys/list) and click the blue plus sign to generate a new key.

![Generate apns keys](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ybmykkk731b45fd2essw.png)
 
Then you'll need to name your key and make sure to select the **Apple Push Notifications service (APNs)**. Once you've done this you will then have the option to download the key, make sure to download it and store it somewhere easy to grab because you will need it to upload to Firebase.

## Uploading your APNS key to Firebase
To upload your APNS key to Firebase, you will need to visit your Firebase Console and go to the project settings. In here there is an option for Cloud Messaging. This is where you will upload your APNS key. In the section Apple app configuration you will click the upload button to upload your APNS key. Once you've done this Firebase will be able to communicate with Apple to push notifications.

## Frontend code
Most of the setup has been completed so now we can dive into some code. First, let's setup Firebase with Ionic-Vue. To do this we're going to need the capacitor community fcm package which can be found [here](https://github.com/capacitor-community/fcm). Once you've installed the package you'll need to go into Xcode and inside your project click on the AppDelegate file and import firebase like so:

```swift
import Firebase

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    FirebaseApp.configure()
    return true
}
```
Now that we set that up, let's jump into the vue portion of the code to add the ability to subscribe to a topic. Inside your Ionic-Vue project you will need to go to your main App.vue file and inside the mounted lifecycle hook paste in the following code:

```js
import { PushNotifications } from '@capacitor/push-notifications';

async mounted () {

    let permStatus = await PushNotifications.checkPermissions();

    if (permStatus.receive === 'prompt') {
      permStatus = await PushNotifications.requestPermissions();
    }

    if (permStatus.receive !== 'granted') {
      throw new Error('User denied permissions!');
    }

    await PushNotifications.register();

    await PushNotifications.getDeliveredNotifications();
}
```
The above snippet of code checks to see if permission has been granted, if not ask the user for permission. Then we register push notifications and get delivered push notifications.

Now we need a way to register the user to a topic, so you'll need to provide a link or a button on the screen for the user to click which will subscribe them to a topic. This is how I accomplished this:

```html
<template>
  <div id="container">
    <a @click.prevent="subscribe">Click to subscribe to sales topic</a>
  </div>
</template>
```

```js
<script>
import { defineComponent } from 'vue';
import { FCM } from '@capacitor-community/fcm';

export default defineComponent({
  name: 'ExploreContainer',
  props: {
    name: String
  },

  methods: {
    subscribe () {
      FCM.subscribeTo({ topic: "sales" })
          .then(() => alert(`subscribed to topic`))
          .catch((err) => console.log(err));
    }
  }
});
</script>
```

Before we jump to the Laravel portion, if you plan to use a custom sound effect for your notifications you'll need to upload that file to your project. To do this you'll want to store the file in the ios directory of your project and you will also need to open Xcode and right click on your project and click Add file to "App" and select your custom sound file to upload. Once you've done that you will be able to use that custom sound file for your push notifications.

**_Important Note: push notifications do not work with the simulator so in order to test this you have to push your application to apple and download the update to your phone_**

##Backend Code (Laravel)
To get Firebase working with Laravel we need to pull in the following [package](https://github.com/kreait/laravel-firebase). Once you've added the package you will then need to visit your Firebase console, visit your project settings, and click the service accounts option. Then you'll need to generate a new private key and download the json file which you will then need to upload to your server. I store mine in the storage directory. Next you'll need to add `FIREBASE_CREDENTIALS=` to your env file using the path to your firebase credentials. You can ignore the FIREBASE_DATABASE_URL=.

Once that is setup we can now add the code to trigger the notifications. For me, I wanted to trigger a notification everytime an invoice was paid on Stripe so that I received a chaching sound on my phone. I did this by using stripe webhooks which you can see below:

```php
if ($event->payload['type'] === 'invoice.payment_succeeded') {
    $data = $event->payload['data']['object'];

    $messaging = app('firebase.messaging');

    $message = CloudMessage::withTarget('topic', 'sales')
        ->withNotification(Notification::create('You got paid!', 'You just received $' . number_format($data['amount_paid'] / 100, 2) . '.'))
        ->withApnsConfig(
            ApnsConfig::new()
                ->withSound('sale_sound.mp3')
                ->withBadge(1)
        );

    $messaging->send($message);
}
```
The `withTarget` method accepts two parameters the first being the type of the target, in this case we chose topic and the second parameter being the name of the topic the user is subscribed to, in my case we called it sales.

The `withSound` method takes a string which is the name of your custom sound file.

And that's it, I hope I'm not forgetting something. If I am I'll make sure to update this article. I know this was a long article, but as it turns out, implementing push notifications is a little more difficult then I had initially thought.

I wasn't able to find a lot of information on how to do this via the web and using the stack that I used so I'm hoping that by writing this article it helps someone else out. Feel free to leave a comment if you know a better way to do this or a way to improve this.