OneSignal integration for notifications - Notifications for Supabase

After multiple days of trying to add OneSignal to my FF app, I've finally managed. So here I'll share my findings so I save a couple of days for someone else. So here I will go in-depth on how to do this from start to finish. From not having an account to deploying your app to Google Play/App Store. It is quite a journey and takes a while. Here are the steps in general:

  1. Create OneSignal account and apps

  2. Deploy your FF app to Github

  3. Modify Xcode and pod file

  4. Push to git

  5. Deploy to stores from git

Now in-depth step by step with pictures.

Head to OneSignal (OS later - https://onesignal.com/) and create an account. When you create an account create two apps. First let's create the Google app as it's simpler. It's actually only one step and that is downloading the Service Account JSON and uploading it inside OS's console. It can be found in: Firebase -> Project Settings -> Service Accounts. On that page scroll down and click "Generate new private key". Upload that into OS's console when prompted. On the app part press "Flutter". That's Google set up (save your android key). Now let's do Apple. Create new app and press Apple, on the next page you will need some info from your Apples consoles. The .p8 needs to be created in here: https://developer.apple.com/account/resources/authkeys/list. That page will pretty much generate all the data you need (.p8 file, key ID and the team number (top right corner)). Your bundle is the only thing left, for that you can find it in FF in Settings -> App Details. App setup is complete (save your iOS key).

Now that we have these apps created, let's run through changes needed in FF. Create 3 new actions: onesignalInitialise, onesignalLogin & onesignalLogout. The code for each:

onesignalInitialise:

import 'package:onesignal_flutter/onesignal_flutter.dart';

Future onesignalInitialise() async {
  final String oneSignalAppId = isAndroid
      ? "your android key"
      : "your iOS key";

  OneSignal.Debug.setLogLevel(OSLogLevel.verbose);
  OneSignal.initialize(oneSignalAppId);
  OneSignal.Notifications.requestPermission(true);
}

Also add a dependency here (add latest version from here: https://pub.dev/packages/onesignal_flutter):

Add this action to your main.dart file to the "Final Actions":

Now onesignalLogin:

import 'package:onesignal_flutter/onesignal_flutter.dart';

Future onesignalLogin(String pUserId) async {
  OneSignal.login(pUserId);
}

Add this action to every instance of your user logging in (Create Account & Login). Add it like the following:

And lastly logout:

import 'package:onesignal_flutter/onesignal_flutter.dart';

Future onesignalLogout() async {
  OneSignal.logout();
}

Add this action to every logout instance:

Okay and that's all the code for Google we need! This will by itself make the app work on Android devices. No extra work is needed so if you only need it for Android devices, you're all set!

Before we continue, go to Firebase -> Settings -> Cloud Messaging. Here select you iOS app below and add the same .p8 file from the first step along with the key ID and team ID:

I am not sure this is needed, but just in case. Okay now back to the app. Regenerate you Firebase Configuration files and we're done with FF.

However, for iOS there is a lot more work to be done unfortunately. I won't be covering pushing your app to Git as that is covered here: https://docs.flutterflow.io/settings-and-integrations/integrations/github, however, the tutorial isn't the best as step 3 is completely false and irrelevant. For step 3 you should be going here: https://github.com/apps/flutterflow-github-app and pressing on install. Once that is done and you selected your app, you can push it to Github. Push it to Github and pull it locally to your machine. Create a new branch from the FF branch called dev-onesignal-notif. Great, let's start with the implementation now.

  1. open your Podfile (in the iOS folder) and add the following to the bottom:

target 'OneSignalNotificationServiceExtension' do
  use_frameworks!
  pod 'OneSignalXCFramework', '>= 5.0.0', '< 6.0'
end
  1. open Xcode and run the Runner.xcworkspace file:

Now in here we got some work to do. First let's add Push Notifications. For this, I will take an image from OneSignals website but everything is the same except their "Demo Momenta" will be "Runner" for you.

Then add "Background Modes" and "Remote Notifications" under that:

  1. Go to your "AppDelegate.swift" file and add the following:

Add this under "import UIKit"

import OneSignalFramework

And add the following inside the function (before the line with "return" and after the "GeneratedPluginRegistrant" if you have it, or after the "{" if you don't:

OneSignal.Debug.setLogLevel(.LL_VERBOSE)
  
  // OneSignal initialization
  OneSignal.initialize("YOUR_ONESIGNAL_APP_ID", withLaunchOptions: launchOptions)
  
  // requestPermission will show the native iOS notification permission prompt.
  // We recommend removing the following code and instead using an In-App Message to prompt for notification permission
  OneSignal.Notifications.requestPermission({ accepted in
    print("User accepted notifications: \(accepted)")
  }, fallbackToSettings: true)

*DISCLAIMER: don't forget to change your one signal app id (this is your iOS key for one signal that you got in step 1)

  1. Now go to File > New > Target and add a new target.

Add the target Notification Service Extension and name it "OneSignalNotificationServiceExtension". Select "Swift" as language. On the pop-up that will come, press "Cancel". Press on "Runner" -> "General" now to check your Minimum Deployments. Now make sure that the Minimum Deployments under that new target is the same as on your Runner target. My Runner MDs is iOS 13, so I put iOS 13 here as well:

  1. Now go to "NotificationService.swift" and delete all the code inside it and paste the following:

import UserNotifications

import OneSignalExtension

class NotificationService: UNNotificationServiceExtension {
    
    var contentHandler: ((UNNotificationContent) -> Void)?
    var receivedRequest: UNNotificationRequest!
    var bestAttemptContent: UNMutableNotificationContent?
    
    override func didReceive(_ request: UNNotificationRequest, withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
        self.receivedRequest = request
        self.contentHandler = contentHandler
        self.bestAttemptContent = (request.content.mutableCopy() as? UNMutableNotificationContent)
        
        if let bestAttemptContent = bestAttemptContent {
            /* DEBUGGING: Uncomment the 2 lines below to check this extension is executing
                          Note, this extension only runs when mutable-content is set
                          Setting an attachment or action buttons automatically adds this */
            // print("Running NotificationServiceExtension")
            // bestAttemptContent.body = "[Modified] " + bestAttemptContent.body
            
            OneSignalExtension.didReceiveNotificationExtensionRequest(self.receivedRequest, with: bestAttemptContent, withContentHandler: self.contentHandler)
        }
    }
    
    override func serviceExtensionTimeWillExpire() {
        // Called just before the extension will be terminated by the system.
        // Use this as an opportunity to deliver your "best attempt" at modified content, otherwise the original push payload will be used.
        if let contentHandler = contentHandler, let bestAttemptContent =  bestAttemptContent {
            OneSignalExtension.serviceExtensionTimeWillExpireRequest(self.receivedRequest, with: self.bestAttemptContent)
            contentHandler(bestAttemptContent)
        }
    }  
}
  1. Now the notifications are set, but we need to add groups so that we have confirmation receipts and that we have badges on the app stating that there is a notification to be read on your app. To do that, add App Groups to your Runner target:

Click "+" and add the following group: group.YOUR_BUNDLE_IDENTIFIER.onesignal.

Do the same for your notification target:

Click "+" and also add the same group (it should already be there).

  1. Now open your info.plist file and add the following:

  • Add a new OneSignal_app_groups_key as a String type.

  • Enter the group name you checked in the last step as it's value.

  • Make sure to do the same for the Info.plist under the  OneSignalNotificationServiceExtension folder.

Perfect. You just set up OneSignal for iOS devices.

Now the work is pretty much over. Commit and push changes to Github. In the Github console merge this with the main branch. Go back to FF and publish from Github, type branch "main" and let Codemagic do their magic.

Let me know below if you struggle on any step and I'll be happy to assist anyone as I really don't want anyone to go through the pain of implementing this and debugging like I did 😢 .

27
106 replies