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
toNO
. - 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
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
}
)
)
)
Link your user to the SDK
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)
}
}
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
: iftrue
, 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 isfalse
.
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:
Here is a summary of the text styles used in the main screens of the SDK:
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.
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 theEnvironment
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)
}
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!
-
First, clone or download the code (SDK+Sample are placed on the same git repository):
-
Rename the
secrets.placeholder.xcconfig
assecrets.xcconfig
- 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
, replaceOCTOPUS_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.
- In
- If your are in SSO with all app managed fields:
- In
secrets.xcconfig
, replaceOCTOPUS_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.
- In
- If your are in SSO with some app managed fields:
- In
secrets.xcconfig
, replaceOCTOPUS_SSO_SOME_MANAGED_FIELDS_API_KEY
with your own API key - In
SSOWithSomeAppManagedFieldsViewModel
, set the fields that are associated inappManagedFields
. - Open the third tab
More
, then tap on the SSO Connection cell and then the Some App Managed Fields.
- In
- If your are in SSO without any app managed fields: