Skip to main content

Bugfender iOS SDK - Swift

info

The official iOS SDK code is available at Github Bugfender iOS

Bugfender is a game-changing platform that logs every detail your users experience and feeds the data directly to an easy-to-use web console. Bugfender SDK is multi-platform and available for mobile and web apps, so you can use the same tool for all your apps.

Specifically for iOS developers, Bugfender offers powerful capabilities to remotely monitor and debug any log or error. You can easily reproduce and fix issues using our detailed log viewer and the stack trace of exceptions.

If you don't have a Bugfender account yet, go to Bugfender Signup and come back here.

Supported iOS versions:

  • BugfenderSDK 2.0 works for iOS 12.0 and newer.
  • For iOS 11.0 support you can use BugfenderSDK 1.12.
  • For iOS 10 support you can use BugfenderSDK 1.10.6.
  • For iOS 8 support you can use BugfenderSDK 1.8.

Install

tip

Learn How To Install Bugfender iOS SDK in 10'

Watch this simple tutorial and learn how to receive the NSLog logs and crashes form your iOS users.

In order to get started using the Bugfender JavaScript SDK, you will need to load the Bugfender script to the top of your application, before all other scripts. Alternatively, you can also install the SDK via a package manager.

Please note you will need Xcode 12 or better.

  1. In Xcode go to the target's General tab and press on the icon to add a new library

  2. In the popover choose Add Other and then Add Package Dependency...

  3. Paste the GitHub url from the Bugfender iOS repository https://github.com/bugfender/BugfenderSDK-iOS in the textfield and press Next

  4. Leave the first option checked and press Next

  5. Xcode will download the Bugfender files and you will be prompted with the following menu. Ensure BugfenderSDK is selected and press Finish

  6. Import SystemConfiguration.framework, Security.framework, CoreServices.framework, CoreGraphics.framework and libc++.tbd as well.

Configure

Configuring the Bugfender SDK for your iOS application is super easy! If your application uses SwiftUI and doesn't have an AppDelegate, you might need to create one like this:

@main
struct YourAppNameApp: App {

@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

var body: some Scene {
WindowGroup {
ContentView()
}
}
}

class AppDelegate: NSObject, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
// your Bugfender init code here

return true
}
}

In your AppDelegate class:

@_exported import BugfenderSDK

And add the following to application(_:didFinishLaunchingWithOptions:):

//Next two lines are usually not required
//But in case you have on-premises or custom data centers, you might need to put your URLs
//Bugfender.setApiURL(URL(string: "https://api.bugfender.com/")!)
//Bugfender.setBaseURL(URL(string: "https://dashboard.bugfender.com")!)

// Activate the remote logger with an App Key.
Bugfender.activateLogger("YOUR_APP_KEY")
Bugfender.enableNSLogLogging() // optional, capture logs printed to console automatically
Bugfender.enableUIEventLogging() // optional, log user interactions automatically
Bugfender.enableCrashReporting() // optional, log crashes automatically
note

Remember to change YOUR_APP_KEY with the app key of your app. You can get an app key by signing up to Bugfender.

Usage

Send logs

bfprint("Hello world!") // use bfprint() as you would use print()

You may use BFLog as you would normally use NSLog.

You may also want to specify a logging level by using the following helper functions:

  • Bugfender.print(...): Default log.
  • Bugfender.warning(...): Warning log.
  • Bugfender.error(...): Error log.

We also have support for several logging libraries:

Device associated data

Once your application is running on several devices, it will be useful to know which device belongs to whom. You can associate information to a device as if it were a dictionary:

Bugfender.setDeviceString("value", forKey: "key")

This will later on let you search this device by “key” in the Bugfender Dashboard and you can use any of the associated data to filter our your device list.

Send issues

Bugfender allows you to send issues to the server. An issue is similar to a session but they are showed in the issues section and you can send issues any time from the app, even if the device is not enabled in the system. Issues are useful to keep track of important errors that you can detect in your code.

For sending an issue you can use the following function:

Bugfender.sendIssueReturningUrl(withTitle: "Issue title", text: "Description of the issue")

Collect user feedback

Getting feedback from the final users is one of the most important things for an app developer. Good user feedback allows you detect errors in your app and helps you to understand better your product.

Bugfender provides a feature to easily collect app feedback from final users. It takes only two minutes and a few lines of code to integrate. You can think about the User Feedback as a special kind of Issue, every time your users submit their feedback you will get a new issue in Bugfender.

The easiest way to implement Bugfender User Feedback is using the customizable User Feedback View Controller. It provides a convenient view controller with two text fields, one short for the subject and another bigger for the feedback. Both text fields grow automatically.

Using the default UI

Using the convenient UI provided by Bugfender requires only creating a new View Controller and presenting it modally. All you need is to call the following method and complete the required parameters with the title and placeholders for your UI.

// Instantiate new User Feedback

let nvc = Bugfender.userFeedbackViewController(withTitle: "Navigation bar title",
hint: "Give some instructions to your users",
subjectPlaceholder: "Placeholder for subject textfield",
messagePlaceholder: "Placeholder for message textfield",
sendButtonTitle: "Send",
cancelButtonTitle: "Cancel") { (feedbackSent, url) in
if (feedbackSent) {
// Say thanks!
// url is a direct link to the dashboard
// Use it to create automations or send it to your server
} else {
// User decided to not send feedback
}
}

// Present modally
self.present(nvc, animated: true, completion: nil)

Additionally, if you require more customization you can configure the view controller prior to presenting it.

Please note BFUserFeedbackNavigationController is a subclass of navigation controller. You need to access the view controller using the public property feedbackViewController.

// Access the root view controller.
let feedbackViewController: BFUserFeedbackViewController = nvc.feedbackViewController

// Change the background colors
feedbackViewController.mainBackgroundColor = UIColor.lightGray
feedbackViewController.secondaryBackgroundColor = UIColor.white

// Change the font of the hint text
feedbackViewController.hintFont = UIFont(name: "Avenir", size: 14)!

For a complete list of customizable attributes you can inspect "BFUserFeedbackViewController.h" or read the docs.

Using SwiftUI

Here is an example using the BFUserFeedbackNavigationController in SwiftUI:

struct SwiftUIView: View {
@State private var showFeedbackScreen = false

var body: some View {
VStack {
Text("Hello World!")
Button("Show Feedback screen") {
showFeedbackScreen = true
}
}.sheet(isPresented: $showFeedbackScreen) {
FeedbackView() { sent, feedbackUrl in
if sent == true,
let url = feedbackUrl{
BFLog("Sent feedback to URL: \(url.absoluteString)")
} else {
BFLog("User rejected to send feedback")
}
}
}.navigationBarTitle(Text("Swift UI Test"))
}
}

struct SwiftUIView_Previews: PreviewProvider {
static var previews: some View {
SwiftUIView()
}
}

struct FeedbackView: UIViewControllerRepresentable {
typealias UIViewControllerType = BFUserFeedbackNavigationController

let completion: (_ feedbackSent: Bool, _ feedbackUrl: URL?) -> Void

func makeUIViewController(context: Context) -> BFUserFeedbackNavigationController {
BFUserFeedbackNavigationController.userFeedbackViewController(
withTitle: "This title",
hint: "This hint",
subjectPlaceholder: "This subject",
messagePlaceholder: "This message",
sendButtonTitle: "Send",
cancelButtonTitle: "Cancel") { sent, feedbackUrl in
completion(sent, feedbackUrl)
}
}

func updateUIViewController(_ uiViewController: BFUserFeedbackNavigationController, context: Context) {}
}

Using a custom UI

If you need further customization than provided by BFUserFeedbackViewController you can implement your own UI. All you have to do is collect your user feedback as you wish and send it to Bugfender using sendUserFeedback:

let feedbackUrl = Bugfender.sendUserFeedbackReturningUrl(withSubject: "Title of the feedback", message: "message of the feedback")

The returned URL is a direct link to the Bugfender's dashboard. Use it to create automations or to keep a reference in your servers.

Advanced Usage

Collecting system logs

Automatic os_log collection

Bugfender can collect os_log and NSLog messages from your customers' iOS devices. To enable the automatic collection, call:

Bugfender.enableNSLogLogging()

Customizing os_log collection

Bugfender also provides the enableNSLogLogging(withInterceptor:) function which to enable the log system collection but allows you tu use an interceptor to do an advanced filtering of the messages you want to send to our systems.

First you need to create a class that implements BFLogInterceptor protocol:

import Foundation
import BugfenderSDK

class CustomLogInterceptor: NSObject, BFLogInterceptor {
func intercept(_ interceptedLog: BFInterceptedLog) -> BFInterceptedLog? {
// Implement your filtering logic here
// For example, only log messages that contain a specific keyword
if interceptedLog.text.contains("ImportantKeyword") {
return interceptedLog
} else {
return nil // Returning nil will block the log entry
}
}
}

Then, in your AppDelegate or the place where you initialize Bugfender, you can enable NSLog logging with your custom interceptor:

import UIKit
import BugfenderSDK

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Activate Bugfender with your app key
Bugfender.activateLogger("YOUR_APP_KEY")
//... other Bugfender options ...

// Create an instance of your custom interceptor
let interceptor = CustomLogInterceptor()

// Enable NSLog interception with your custom interceptor
Bugfender.enableNSLogLogging(withInterceptor: interceptor)

// ... other setup code ...

return true
}
}

Check the signature of BFInteceptedLog to see all the properties you can use.

Having your app decide when to send logs

In some special circumstances you may want to send logs, regardless of the enabled state of the device in the Bugfender console, for example in a custom exception handler. Use forceSendOnce to force sending the logs once, and use setForceEnabled: to force it for some period of time.

Manually sending crashes in iOS

If you have your own crash reporting system and need to send crashes, you can do so by calling directly sendCrashWithTitle

[Bugfender sendCrashWithTitle:@"My Crash" text:@"The app crashed on my code"]

Sometimes you want to integrate Bugfender with a third party tool. For this purpose, the SDK provides a method that returns the URL for the session. You can send it to the third party tool to easily go to the logs of the current session from the other tool.

Bugfender.sessionIdentifierUrl();

Sometimes you want to integrate Bugfender with a third party tool. For this purpose, the SDK provides a method that returns the URL for the current device. You can send it to the third party tool and easily navigate back to the logs of the device from the other tool.

Bugfender.deviceIdentifierUrl()

Log buffer size

Bugfender keeps up to 5 MB worth of log data in the device. This way Bugfender can work offline, and you can get some log data from the past when enabling a device. You can change that limit with setMaximumLocalStorageSize.

// Setting maximum cache size to 1 Mb
Bugfender.setMaximumLocalStorageSize(1024*1024)

Automate Symbols Uploading

You can use the Bugfender XCode Script to automatically upload dSYM bundle for symbolicating crashes.

Note: At the moment, Bitcode enabled apps are not supported by the script.

To add the script to XCode:

  1. Copy the script to your project directory.
  2. Go to your App settings.
  3. Select Target from the left.
  4. Select the Build Settings tab, find Build Options > User Script Sandboxing and set it to No.
  5. Go to Build Phases.
  6. Open menu under the + sign and select New Run Script Phase.
  7. Under the shell portion of Run Script add a script call: BUGFENDER_SYMBOLICATION_URL=https://dashboard.bugfender.com/ <path_to_the_script>/upload-symbols.sh YOUR_SIMBOLICATION_TOKEN
    • It is also possible to drag & drop it from Finder and XCode will fill in the path.
note

Remember to change YOUR_SIMBOLICATION_TOKEN with the symbolication token for your app. You can get an app key by signing up to Bugfender.

Xcode Symbols Script

API Reference

For a complete API Reference you can visit: https://bugfender.github.io/BugfenderSDK-iOS/Classes/Bugfender.html