Skip to main content

iOS SDK Setup Guide With SSO Authentication


Install the SDK

Octopus can be installed:

In an Xcode project

Open your workspace (.xcworkspace) or your project (.xcodeproj), open the File menu and open Add Package Dependencies. Then, paste the url of the Octopus Community SDK: https://github.com/Octopus-Community/octopus-sdk-swift.git

On the next window, add both Octopus and OctopusUI to your target.

OR

In a Swift Package

Add the dependency to your package:

dependencies: [
.package(url: "https://github.com/Octopus-Community/octopus-sdk-swift.git", from: "1.0.0"),
],

Add the SDK as a dependency to your target:

.target(
name: "YourTarget",
dependencies: [
.product(name: "Octopus", package: "octopus-sdk-swift"),
.product(name: "OctopusUI", package: "octopus-sdk-swift"),
]
),
Not recommended: Cocoapods

As CocoaPods is starting to be less and less used, some libraries are not available anymore. This is the case of SwiftGrpc on which the Octopus SDK has built its backend exchanges. Hence, if you use the SDK using Cocoapods, you will be using an old version of SwiftGrpc.

If you really have to use the SDK with Cocoapods, here is how to do it:

  • Copy the content of our podfile example in your podfile. Pay attention to the fact that the post_install script is setting iOS 14 as minimum requirement and setting ENABLE_USER_SCRIPT_SANDBOXING to NO.
  • Then you can run pod install

See the Octopus SDK GitHub Release section to get the latest published version.


Use the SDK

As early as possible in your code, you should initialize the OctopusSDK object.

This object is expecting two things:

  • the Octopus Community API key
  • the connection mode
warning

You are reading the SSO connection mode documentation, if your community is configured to use Octopus Authentication, please open the documentation for this mode.

You need to know the app managed fields (also called as associated fields) that your community is configured for.

As a reminder, every associated profile fields (nickname, picture and/or bio) of your users will be used in the Octopus Community profile of this user. The user will only be able to change it in your profile edition interface and the data will be synced to its community profile.
On the oposite, every dissociated profile fields will only be used as prefilled values during Octopus profile creation. After that, if a user changes its nickname in your app, it won't be reflected in Octopus Community, and the user will be able to change its community nickname in the community part.

First, import Octopus:

import Octopus
At least one app managed field

If your community is having at least one associated field, you will have to create the SSO connection mode with:

  • the list of the associated fields
  • the block that will be called when OctopusSDK needs a logged in user. When this block is called, you should start to display your login process.
  • the block that will be called when the user tries to modify some fields related to its profile. When this block is called, you should open the profile edition. This block has a ProfileField optional parameter. It indicates the field that the user tapped to edit if there is one.
let octopus = try OctopusSDK(
apiKey: "YOUR_API_KEY",
connectionMode: .sso(
.init(
appManagedFields: [.nickname, .picture], // the list of associated fields
loginRequired: {
// Put the code here to open your login flow
},
modifyUser: { fieldToEdit in
// Put the code here to open your profile edition screen
// `fieldToEdit` is the field that has been asked to be edited by the user. Nil if the user tapped on "Edit my profile".
}
)
)
)

OR

No app managed fields

When there is no app managed fields (i.e. all fields are dissociated), the API is simpler since it only requires a callback to display the login flow. When this block is called, you should start to display your login process.

let octopus = try OctopusSDK(
apiKey: "YOUR_API_KEY",
connectionMode: .sso(
.init(
loginRequired: {
// Put the code here to open your login flow
}
)
)
)

Since you’re using the sso connection mode, you’ll need to tell the SDK when your user is connected or disconnected.

The connectUser API lets you pass the userId. This userId is the string that will identify your user for Octopus. It needs to be unique and always refer to the same user.

You can also pass profile information (nickname, bio, picture, and whether the user is over 16 years old). These details will be used only to prefill the Octopus Community profile when the user performs their first action requiring authentication (such as creating a post or liking content). However, their community profile remains separate from yours, meaning any updates made to your profile will not be reflected in theirs, and vice versa.

Note that if you inform the SDK that a user is underage, they won't be able to create their community profile until they update their age in your app. This is why we strongly recommend passing null as the age information when a user is underaged (unless you are 100% certain the age is accurate). In this case, Octopus SDK will prompt the user to enter their age during the profile creation process.

Client User Token

For security reasons, to ensure that the connected user is legitimate, the API informing the SDK of a user’s connection includes a callback that provides a signed token for authentication. In other words, the SDK will request a token from you when needed to authenticate the user. Therefore, you must add a route like /generateOctopusSsoToken to your backend to generate this token. Follow the Generate a signed JWT for SSO guide for more information

Inform the SDK that your user is connected:

octopus.connectUser(
ClientUser(userId: yourUser.id,
profile: ClientUser.Profile(nickname: yourUser.name,
bio: yourUser.bio,
picture: yourUser.picture,
ageInformation: .legalAgeReached // if your user is more than 16 years old. Pass .underaged if they are less. Pass nil if you don't know
)
),
tokenProvider: {
// Fetch asynchronously this user token
// by calling your /generateOctopusSsoToken route
}
)

Inform the SDK that your user is disconnected:

octopus.disconnectUser()

Display the Octopus Community UI

Now that you have the SDK properly configured, you can add a button in your app that opens the Octopus Community UI.

First import Octopus UI

import OctopusUI

Octopus handles its own navigation, so you must not embed it in a navigation stack.

@State private var openOctopus = false

var body: some View {
Button("Open Octopus Community") {
openOctopus = true
}.fullScreenCover(isPresented: $openOctopus) {
OctopusHomeScreen(octopus: octopus)
}
}
note

If your using a UITabBarController to display the Octopus UI inside a UIHostingController, you might encounter a safe area bug. This is a known bug not related to the Octopus SDK UI. To fix it, you might want to add the UITabBarController children in the code instead of in the Storyboard. Otherwise, you can add a negative padding to the OctopusUI.

Main screen's navigation bar

You can customize the look of the navigation bar in the main screen (the posts list). There are two params when displaying the OctopusHomeScreen that have an effect on this navigation bar:

  • navBarLeadingItem: it is an enum value that lets you chose what will be displayed in the top left corner.
    Its value is either:
    • .logo to display the logo (see Modify the theme)
    • .text(TextTitle) to display a text. In the case of a text, we highly encourage you to chose it small (less than 18 characters). Default value is .logo.
  • navBarPrimaryColor: if true, the background color of the navigation bar will be set to the primary color (see Modify the theme). Otherwise, it will be the default color. Default value is false.

Here is how to use these two parameters:

OctopusHomeScreen(
octopus: octopus,
navBarLeadingItem: .text(.init(text: "App Name")),
navBarPrimaryColor: true
)

To see a full example of how you can achieve that, you can follow how it is done in the Samples, in the Scenario "Custom theme".


Modify the theme

The Octopus SDK lets you modify its theme so its UI looks more like yours.

You can modify:

  • the colors:
    • the primary colors (a main color, a low contrast and a high contrast variations of the main color). Please note that the high contrast variation of the primary color is not used for the moment. If you do not pass a custom value for it, black/white default values will be used.
    • the color of the elements (mostly texts) displayed over the primary color. If you do not pass a custom value for it, white/black default value will be used.
  • the fonts. You can customize the styles (title1, body2, caption1...) used in the sdk. If you do not pass a custom value for it, default value will be used.
  • the logo. This is an image displayed on the Octopus home page and profile creation view. If you do not pass a custom image for it, Octopus logo value will be used.

To do that, you can override the theme by passing it as environment object:

OctopusHomeScreen(octopus: octopus)
.environment(
\.octopusTheme,
OctopusTheme(
colors: .init(
primarySet: OctopusTheme.Colors.ColorSet(
main: yourPrimaryColor,
lowContrast: lowContrastVersionOfYourPrimaryColor,
highContrast: highContrastVersionOfYourPrimaryColor),
onPrimary: contentOverPrimaryColor),
fonts: .init(
title1: Font.custom("Courier New", size: 26),
title2: Font.custom("Courier New", size: 20),
body1: Font.custom("Courier New", size: 17),
body2: Font.custom("Courier New", size: 14),
caption1: Font.custom("Courier New", size: 12),
caption2: Font.custom("Courier New", size: 10),
navBarItem: Font.custom("Courier New", size: 17)
),
assets: .init(logo: yourLogoAsUIImage)
)
)

All parameters of the Theme have default values. Only override the ones that you want to customize. On the following example, you are creating an OctopusTheme with default colors, default fonts except for the title1 and a custom logo:

let octopusTheme = OctopusTheme(
fonts: .init(
title1: Font.custom("Courier New", size: 26)
),
assets: .init(logo: yourLogoAsUIImage))

Here is a summary of the impacts of the theme you choose: Light Mode Dark Mode

Here is a summary of the text styles used in the main screens of the SDK: Text Styles

tip

If your app supports only light or dark mode, add to your Info.plist UIUserInterfaceStyle with the value Light or Dark to force the sdk to use the mode you specified.


Push Notifications ≥ 1.4.0

To increase user engagement, you can provide informations to the Octopus SDK so your users can receive push notifications when other users interact with them inside the community.

note

Octopus SDK is not asking for push notification permissions, we let you handle that part where it makes more sense in your app.

If your app does not support Push Notifications yet, you can follow the official Apple documentation.

Our servers need to have a key in the .p8 format in order to send push notifications to your app on your behalf

If you don't have this key yet, follow this tutorial
  • Go to the Apple Dev Website and create a new key.
  • Name it and check Apple Push Notifications service (APNs)
  • Click on configure of this line and select Sandbox & Production in the Environment menu if you intend to have the same key for sandbox and production builds.
  • Download the key and be sure to store it in a secured and retrievable place

Once you have that file, you should send it using the secure form provided by the Octopus Team, along with:

  • the key ID: can be found in the list of keys on the Apple Dev Website
  • your Bundle ID: can be found in your Xcode project
  • your Team ID: can be found here in the Membership details card

Once your project is correctly setup for push notifications, you should forward the notification device token to the Octopus SDK:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
let token = deviceToken.map { String(format: "%02.2hhx", $0) }.joined()
octopus.set(notificationDeviceToken: token)
}
note

You are in charge of registering for remote notifications by calling

UIApplication.shared.registerForRemoteNotifications()

and for getting the user's authorizations by calling

notifCenter.requestAuthorization(options: [.alert, .badge, .sound])

When you receive a notification response (i.e. when the user tapped a notification), first check if it is an Octopus notification by calling:

OctopusSDK.isAnOctopusNotification(notification: notificationResponse.notification)

If it is one, display the Octopus UI and pass it the notification response as a Binding:

OctopusHomeScreen(octopus: octopus, notificationResponse: $octopusNotification)

Not seen notifications ≥ 1.3.0

To increase user engagement, let your users know that they have new notifications from the Octopus notification center. Displaying a badge with the number of new notifications in your app can be a great way to suggest your users to look at what's new in the community again.

To do that, the Octopus SDK exposes a @Published var notSeenNotificationsCount: Int.

If you want to update this value with the latest count, simply call :

try await octopus.updateNotSeenNotificationsCount()

To see a full example of how you can achieve that, you can follow how it is done in the Samples, in the Scenario "Notification Badge".


Analytics

Octopus Community provides analytics to help you better understand your users' behavior within the community. To improve the quality of these analytics, we offer features that allow you to provide additional information about your users.

Custom events ≥ 1.4.0

You can tell the SDK to register a custom event. This event can be merged into the reports we provide.

try await viewModel.octopus?.track(customEvent: CustomEvent(
name: "Purchase",
properties: [
"price": .init(value: "\(String(format: "%.2f", 1.99))"),
"currency": .init(value: "EUR"),
"product_id": .init(value: "product1"),
]))

To see a full example of how you can achieve that, you can follow how it is done in the Samples, in the Scenario "Custom events".

Configure Community Visibility ≥ 1.3.0

If you enable access to the community for only a subset of your users and want the analytics we provide to take this into account, you can inform the SDK accordingly.

This information is reset at each SDK launch so be sure to call the function everytime and as soon as possible after SDK init.

octopus.set(hasAccessToCommunity: canAccessCommunity)

To see a full example of how you can achieve that, you can follow how it is done in the Samples, in the Scenario "A/B Tests".


Follow the Samples

Want to see a code examples on how to use the SDK, no worries, we have that for you!

  1. First, clone or download the code (SDK+Sample are placed on the same git repository):

    iOS SDK

  2. Rename the secrets.placeholder.xcconfig as secrets.xcconfig

  1. According to your connection mode, this matches how your app should integrate the SDK:
    • If your are in SSO without any app managed fields:
      • In secrets.xcconfig, replace OCTOPUS_SSO_NO_MANAGED_FIELDS_API_KEY with your own API key
      • Open the third tab More, then tap on the SSO Connection cell and then the No App Managed Fields.
    • If your are in SSO with all app managed fields:
      • In secrets.xcconfig, replace OCTOPUS_SSO_ALL_MANAGED_FIELDS_API_KEY with your own API key
      • Open the third tab More, then tap on the SSO Connection cell and then the With all App Managed Fields.
    • If your are in SSO with some app managed fields:
      • In secrets.xcconfig, replace OCTOPUS_SSO_SOME_MANAGED_FIELDS_API_KEY with your own API key
      • In SSOWithSomeAppManagedFieldsViewModel, set the fields that are associated in appManagedFields.
      • Open the third tab More, then tap on the SSO Connection cell and then the Some App Managed Fields.