How to Add Ionic Facebook Login with Capacitor | Devdactic

How to Add Ionic Facebook Login with Capacitor Last update: 2020-12-01

How to Add Ionic Facebook Login with Capacitor

Adding Ionic Facebook login to your app can help to quickly sign in users, and the setup required to make it work with Capacitor is actually not too hard!

After we have seen how to use Google sign in or the new Sign in with Apple, today we will focus on the third major social authentication provider.

To do so we will use the Capacitor Facebook login plugin, which also needs some previous setup inside the Facebook developer tools.

ionic-facebook-login-capacitor

Once we are done, our users will be able to sign in with Facebook using the native dialog, and we will also make a dummy API call to the Facebook Graph API to retrieve some user data as the prove that we are logged in!

Getting started with our Ionic Facebook App

Before we dive into the Facebook part, let’s make sure you have an Ionic app ready. If you want to test things out, go ahead with the following commands:

ionic start devdacticFbLogin blank --type=angular --capacitor --package-id=com.devdactic.fblogin
cd ./devdacticFbLogin
npm i @capacitor-community/facebook-login

ionic build
npx cap add ios
npx cap add android

The important part is to have a real package id and not just the dummy one that Ionic apps usually use, so instead of com.devdactic.fblogin use your own id in there.

If you already have an existing app, simply make sure you have set your own appId inside the capacitor.config.json like:

{
  "appId": "com.devdactic.fblogin",
  "appName": "devdacticFbLogin",
  "bundledWebRuntime": false,
  "npmClient": "npm",
  "webDir": "www",
  "plugins": {
    "SplashScreen": {
      "launchShowDuration": 0
    }
  },
  "cordova": {}
}

This ID will be used within the next step, so make sure everything is right up until here.

Because we will make an Http request we should also quickly change the src/app/app.module.ts and include the HttpClientModule like this:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouteReuseStrategy } from '@angular/router';

import { IonicModule, IonicRouteStrategy } from '@ionic/angular';
import { SplashScreen } from '@ionic-native/splash-screen/ngx';
import { StatusBar } from '@ionic-native/status-bar/ngx';

import { AppComponent } from './app.component';
import { AppRoutingModule } from './app-routing.module';

import { HttpClientModule } from '@angular/common/http';

@NgModule({
  declarations: [AppComponent],
  entryComponents: [],
  imports: [BrowserModule, IonicModule.forRoot(), AppRoutingModule,
    HttpClientModule],
  providers: [
    StatusBar,
    SplashScreen,
    { provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
  ],
  bootstrap: [AppComponent]
})
export class AppModule {}

That’s it for the first app setup, now on to the Facebook app itself.

Facebook App Preparation

To use Ionic Facebook login, you first of all now need to create a Facebook app over at the Facebook developers page.

Simply create an account if you don’t have one yet, and then from within your app dashboard click ”Create App” to start a new dialog.

ionic-facebook-create-app

I’m actually not 100% about the other options available but I picked the third option ”Build Connected Experiences” and everything worked just fine.

Give your app a name and create the app - you will soon be inside the overview page of your app.

From the left menu, select Settings and Basic and scroll down that page until you see the Add Platform button.

Just like we usually do within Firebase, we now create apps in here for iOS and Android.

ionic-facebook-add-platform

The only thing you need to add for iOS is the Bundle ID, which is exactly the ID we have seen in the beginning when setting up our app (or inside the capacitor.config.json).

ionic-fb-ios

Once you got the iOS part, you can go ahead with the Android app for which you now also need the key hash of the keystore that you use to sign your app.

For development, your key is usually located at ~/.android/debug.keystore with the default password android. To get the hash you can simply run:

keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore | openssl sha1 -binary | openssl base64

Copy that hash output into the Android section Key Hashes, and add the bundle ID inside the Google Play Package Name field.

ionic-fb-android

Now we have added both platforms to our Facebook app and we can continue within our Ionic app.

iOS Facebook Changes

At this point you should have added the native iOS platform to your Ionic Capacitor app, and we need to apply a few changes to it.

First, we need to overwrite the CFBundleURLTypes and add some more keys inside the ios/App/App/Info.plist, which you can either open with Xcode or your standard IDE:

<key>CFBundleURLTypes</key>
	<array>
	<dict>
		<key>CFBundleURLSchemes</key>
		<array>
		<string>fb687134308903752</string>
		</array>
	</dict>
	</array>
	<key>FacebookAppID</key>
	<string>YOUR_FACEBOOK_APP_ID</string>
	<key>FacebookDisplayName</key>
	<string>YOUR_FACEBOOK_APP_NAME</string>
	<key>LSApplicationQueriesSchemes</key>
	<array>
	<string>fbapi</string>
	<string>fbauth2</string>
	</array>

Simply overwrite the existing CFBundleURLTypes with the whole snippet above so everything you need is inside the plist.

Note: Of course use your own FacebookAppID and FacebookDisplayName inside that snippet!

For the next step you need to open the ios/App/App/AppDelegate.swift and add the two imports for the Facebook SDK at the top, and then change the two functions that are inside the snippet below.

The rest of that file can stay the same, make sure you only replace the relevant functions:

import UIKit
import Capacitor
import FBSDKCoreKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

  func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    FBSDKCoreKit.ApplicationDelegate.shared.application(application, didFinishLaunchingWithOptions: launchOptions)
    // Override point for customization after application launch.
    return true
  }

  func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
    // Called when the app was launched with a url. Feel free to add additional processing here,
    // but if you want the App API to support tracking app url opens, make sure to keep this call
    if CAPBridge.handleOpenUrl(url, options) {
        return FBSDKCoreKit.ApplicationDelegate.shared.application(app, open: url, options: options)
      }
      else{
       return false
      }
  }
}

Now the iOS part is ready and the app knows how to handle the return value after the native Facebook login is finished.

Android Facebook Changes

For Android, we first need to add the Capacitor plugin like always inside theandroid/app/src/main/java/com/devdactic/fblogin/MainActivity.java:

package com.devdactic.fblogin;

import android.os.Bundle;

import com.getcapacitor.BridgeActivity;
import com.getcapacitor.Plugin;

import java.util.ArrayList;

public class MainActivity extends BridgeActivity {
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Initializes the Bridge
    this.init(savedInstanceState, new ArrayList<Class<? extends Plugin>>() {{
      // Additional plugins you've installed go here
      add(com.getcapacitor.community.facebooklogin.FacebookLogin.class);
    }});
  }
}

Simply add the one line inside the init block and you are fine.

For the next step you need to paste the block below under the manifest -> application tag (where you can also see another activity tag).

Open the android/app/src/main/AndroidManifest.xml and insert at that location:

<meta-data android:name="com.facebook.sdk.ApplicationId"
  android:value="@string/facebook_app_id"/>

<activity
    android:name="com.facebook.FacebookActivity"
    android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
    android:label="@string/app_name" />

<activity
    android:name="com.facebook.CustomTabActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.intent.action.VIEW" />
        <category android:name="android.intent.category.DEFAULT" />
        <category android:name="android.intent.category.BROWSABLE" />
        <data android:scheme="@string/fb_login_protocol_scheme" />
    </intent-filter>
</activity>

Finally we need to add our Facebook app id for two values, so open the android/app/src/main/res/values/strings.xml and change it to this (or simply add the two relevant rows since the rest contains my app bundle id!):

<?xml version='1.0' encoding='utf-8'?>
<resources>
    <string name="app_name">devdacticFbLogin</string>
    <string name="title_activity_main">devdacticFbLogin</string>
    <string name="package_name">com.devdactic.fblogin</string>
    <string name="custom_url_scheme">com.devdactic.fblogin</string>
    <string name="facebook_app_id">YOUR_FACEBOOK_APP_ID</string>
    <string name="fb_login_protocol_scheme">fbYOUR_FACEBOOK_APP_ID</string>
</resources>

Make sure you add fb before the FB App ID for the fb_login_protocol_scheme, that’s no typo! So it should be something like “fb1234567”.

That’s it, both of our native platforms are now configured!

Web Facebook Changes

If you also want to test the process on the browser because you want to build an Ionic website or simply for testing, you need to load the Facebook JS SDK inside the src/index.html:

<script>
    window.fbAsyncInit = function () {
      FB.init({
        appId: 'YOUR_FACEBOOK_APP_ID',
        cookie: true, // enable cookies to allow the server to access the session
        xfbml: true, // parse social plugins on this page
        version: 'v5.0' // use graph api current version
      });
    };

    // Load the SDK asynchronously
    (function (d, s, id) {
      var js, fjs = d.getElementsByTagName(s)[0];
      if (d.getElementById(id)) return;
      js = d.createElement(s); js.id = id;
      js.src = "https://connect.facebook.net/en_US/sdk.js";
      fjs.parentNode.insertBefore(js, fjs);
    }(document, 'script', 'facebook-jssdk'));
  </script>

Put that snippet simply below the body of your page and insert your Facebook App id in the relevant place again.

Ionic Facebook Login

Now we can finally trigger the dialog from our Ionic app, which is actually the easiest part.

The only challenge is that the plugin is a bit different for web and native app, so we use a little switch inside the setupFbLogin to check on which platform we are running and either use the web version (which is already registered at the top) or use the according object from the Capacitor plugins object.

Once this is done, you can call all functions on the plugin to login a user with specific permissions, which will give you an accessToken plus more information inside a native app. When you run the app inside the browser preview, the plugin will only return the token and no other user information, so in that case we can directly call the getCurrentToken which will then give us all relevant information.

Finally with the token in place and the user id available, we can make a dummy call to the Graph API inside the loadUserData to retrieve some general information about that user! Now go ahead and change the home/home.page.ts to:

import { Component } from '@angular/core';
import { FacebookLoginPlugin } from '@capacitor-community/facebook-login';
import { Plugins, registerWebPlugin } from '@capacitor/core';
import { isPlatform } from '@ionic/angular';
import { HttpClient } from '@angular/common/http';

import { FacebookLogin } from '@capacitor-community/facebook-login';
registerWebPlugin(FacebookLogin);

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  fbLogin: FacebookLoginPlugin;
  user = null;
  token = null;

  constructor(private http: HttpClient) {
    this.setupFbLogin();
  }

  async setupFbLogin() {
    if (isPlatform('desktop')) {
      this.fbLogin = FacebookLogin;
    } else {
      // Use the native implementation inside a real app!
      const { FacebookLogin } = Plugins;
      this.fbLogin = FacebookLogin;
    }
  }

  async login() {
    const FACEBOOK_PERMISSIONS = ['email', 'user_birthday'];
    const result = await this.fbLogin.login({ permissions: FACEBOOK_PERMISSIONS });

    if (result.accessToken && result.accessToken.userId) {
      this.token = result.accessToken;
      this.loadUserData();
    } else if (result.accessToken && !result.accessToken.userId) {
      // Web only gets the token but not the user ID
      // Directly call get token to retrieve it now
      this.getCurrentToken();
    } else {
      // Login failed
    }
  }

  async getCurrentToken() {
    const result = await this.fbLogin.getCurrentAccessToken();

    if (result.accessToken) {
      this.token = result.accessToken;
      this.loadUserData();
    } else {
      // Not logged in.
    }
  }

  async loadUserData() {
    const url = `https://graph.facebook.com/${this.token.userId}?fields=id,name,picture.width(720),birthday,email&access_token=${this.token.token}`;
    this.http.get(url).subscribe(res => {
      this.user = res;
    });
  }

  async logout() {
    await this.fbLogin.logout();
    this.user = null;
    this.token = null;
  }
}

If you want to test other API calls, simply give the cool Facebook Graph API Explorer a try! The last step is to simply show a few buttons to test our app, so go ahead and replace everything inside the home/home.page.html with:

<ion-header>
  <ion-toolbar color="primary">
    <ion-title>
      Devdactic Facebook
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>

  <ion-card *ngIf="user">
    <img [src]="user.picture.data.url">
    <ion-card-header>
      <ion-card-title>
        {{ user.name }}
      </ion-card-title>
      <ion-card-subtitle>
        {{ user.birthday }}
      </ion-card-subtitle>
    </ion-card-header>
    <ion-card-content>
      {{ user.email }}
      <ion-button (click)="logout()" expand="full">Logout</ion-button>
    </ion-card-content>
  </ion-card>
  <ion-button (click)="login()" expand="full">Login</ion-button>

</ion-content>

That’s it! Now run your app in the preview mode or on a real device and enjoy your Ionic Facebook login.

Conclusion

Adding Facebook login to your Ionic app isn’t very complicated if you follow the exact steps necessary to configure your app correctly upfront.

If you encounter problems, make sure you got the bundle ID correct everywhere and also that you are using the right Android hash.

You can also find a video version of this tutorial below: https://youtu.be/eEBi92zOgzs