Troubleshoot Issues on iOS Apps
App submission errors can occur when you're publishing your apps to App Store Connect. These errors are accompanied by an error message from Xcode or during Apple's app review.
This error can occur even if you aren't using MobilePush Location Messaging. If you're not using the SDK's location messaging functionality, your users aren't prompted to provide location permissions. This error occurs as the SDK is built with references to CoreLocation.framework
. During app review, the automated binary scanning detects these references and requires purpose strings to be attached.
If you're not using Location Messaging, add a purpose string to your app’s Info.plist
file as a placeholder, as shown in the following example.
To ensure the proper configuration of your Apple Push Notification Service (APNS) server and delivery of push notifications for different types of app builds (development or production), keep the following points in mind.
- APNS Server Selection
Irrespective of the chosen
.p8
key or.p12
certificate, Engagement attempts to contact the Sandbox APNS server when you check the Development radio button, and the Production APNS server when you check the Production radio button.- For Development Apps (Apps Built Using Development Certificates)
To send notifications only to those devices with apps on
Debug
configuration, choose the Development radio button in the MobilePush Administration page.- For Production Apps (Apps Built Using Production or Distribution Certificates)
To send notifications only to those devices with apps on
Release
configuration, select the Production radio button in the MobilePush Administration page.
If you encounter issues receiving messages in your app, consider these troubleshooting steps:
- Check the SDK’s log output
- Send a test push
- Evaluate the SDK's state
- Unblock Network Ports
- Review Additional Troubleshooting Guidance
The MarketingCloudSDK.framework
uses extensive internal logging to record actions performed by the SDK for informational and diagnostic purposes.
General, default-level logging is always enabled. Additionally, the SDK writes error and fault-level logs when conditions occur that must be recorded.
Enable logging using the following call:
When using SDK versions older than version 8.x, enable logging after SDK configuration.
Enable logging with CustomLogOutputter
:
Enable logging with a standard log output and a log filter. For more filtering options, refer to Xcode autocompletion.
Clear previously set filtering options.
Query the state of debug-level logging using this call.
The SDK sends all logging output to Apple’s unified logging system. You can review this information using Xcode’s Devices and Simulators window or the macOS Console application. When SDK debug logging is enabled, the SDK uses the OS_LOG_TYPE_DEBUG
value. Make sure to disable logging in your application for release builds to the App Store.
For more information about unified logging, see Logging on Apple Developer.
To test whether your app can receive a push directly from the Apple Push Notification Service (APNS), follow these steps.
-
Get the push token from the SDK. For testing and troubleshooting purposes, retrieve your device token from a running app by calling
sfmc_deviceToken()
and send the result to yourself via email, alert, or another method. -
Trigger the APNS API directly from the command line if using a
.p8
authentication key.The following script points to the
development
APNS service by default. To trigger push from the APNS production server, change theendPoint
tohttps://api.push.apple.com
in the following script. -
If using a
.p12
certificate (legacy), trigger the APNS API directly from the command line.If your device receives the push notification, you can assume that you've set up your application correctly. The setup includes creating a
.p8
authentication key or.p12
certificate, building the app with the correct bundle ID, and using the appropriate provisioning profiles.
Note the environment (development or production APNS) in which the push was successfully delivered while sending a test push. On the Engagement Administration page, point to the same environment under Sending Services > iOS Sending and send a push notification. Check if your device received the push notification.
Ensuring the selection of the correct APNS environment is crucial for the SDK to trigger push notifications to the appropriate APNS server. If you select the Development radio button, Engagement contacts the Sandbox
APNS server. If you select the Production radio button, Engagement contacts the Production
APNS server.
To retrieve a all of the information the SDK has and its current state, implement getSDKState()
as shown in the following example.
The SDK outputs a JSON string as shown in the following example.
Testing your app while connected to a corporate network can prevent your test device from receiving messages, especially if your IT team doesn't configure port accessibility. Ensure that your IT team unblocks the following TCP ports to facilitate communication between your test device and the APNS servers for MobilePush functionality.
TCP Port | Description |
---|---|
5223 | Used by devices to communicate to the APNS servers |
2195 | Used to send notifications to the APNS servers |
2196 | Used by the APNS feedback service |
443 | Used as a fallback service for Wi-Fi devices when those devices can't communicate with the APNS service on port 5223 |
Refer to the following articles when testing your app, or when troubleshooting why your devices aren't receiving messages or are receiving them sporadically.
- Apple Developer: Technical Note TN2265: Troubleshooting Push Notifications
- Download: APNS Debugging Provisioning File
- Apple Developer: APNS Port Functionality Information
The MobilePush SDK can coexist and work in the same app as other push vendor SDKs. However, we recommend checking with your other SDK vendors to ensure they also support a multi-push provider implementation. The following sections provide considerations for multiple push SDKs to successfully work together.
MPP implementations often affect the following functionalities, hence preventing the SDK from behaving as expected.
- Receiving Device Tokens
- Receiving Push Messages
Without device tokens, the SDK doesn't register the device properly and Engagement is unable to send push notifications to the device. The SDK expects you to pass push notifications to the setNotificationRequest
method. Doing so makes the SDK aware of the notifications and allows it to handle them accordingly (for example, tracking and URL handling).
Apple has specific delegate methods that the consuming application must implement to register with APNS and receive push notifications. Implementing multiple push providers can affect the previously mentioned functionality since other vendors can provide wrapper methods for registration and receiving the notifications. Consuming applications often listen to the wrapper methods instead of actual Apple-provided delegate methods. An example of a common issue is when registration with Apple is done for one push provider without setting the deviceToken
for other push providers.
Method Swizzling is the process of changing the implementation of an existing selector at runtime. If Method Swizzling is enabled, other push providers automatically intercept all the application delegate methods, which differ from the normal flow in setting up the deviceToken
and notification userinfo
.
Method Swizzling can confuse MobilePush SDK users about how and where to set the SDK's required API methods because another provider is changing the implementation without their knowledge.
To determine if non-MobilePush SDK providers use Swizzling, check to see whether they don't use the following methods.
MobilePush SDK users can handle MPP implementations with and without Swizzling enabled.
If Swizzling is enabled, implement the respective push provider’s delegate methods and set the following to the MobilePush SDK.
Configuration With Another Push Provider
Configure the SDK along with the other Push provider.
Handling DeviceToken
API: setDeviceToken(apnsToken)
Handling Notifications
When Swizzling is enabled in the other push provider, respective delegate methods are intercepted. For example, considering Firebase as the other push provider, when a push notification is received from Firebase, the payload received in the UNUserNotificationCenterDelegate
's didReceive
notification method is altered to receive a MessagingMessageInfo
object. This payload alteration results in the message not being reported when passed to the SDK, as the payload expected by the SDK doesn't match.
API:
setNotificationUserInfo(userInfo)
setNotificationRequest(response.notification.request)
Notification messages from other providers are displayed in the device’s notification center. However, any action on the notification message from the SDK (for example, URL handling and reporting) doesn't work.
To disable Swizzling, refer to the other push provider’s documentation. When Swizzling is disabled in the other push provider, the default AppDelegate
methods are called.
Implement AppDelegate Methods
Common areas for poor implementation can include device registration, geolocation, and more.
This isn’t an exhaustive list.
- Registration
You must only make one call to a push SDK to register for push notifications. Otherwise, a single push notification can trigger multiple notification banners, alerts, or sounds. The MobilePush SDK gives the app developer the power to register.
- Notification Settings
An app can invoke
requestAuthorizationWithOptions
andregisterForRemoteNotifications
multiple times. However, only the settings from the last call are used, as each successive call overwrites the previous settings.- Badging
There’s no way to guarantee the value of a badge.
- Custom Payload Keys
If your implementation must distinguish between two notification providers, use custom keys or other payload-specific data to ensure that your app calls the correct SDK handler that supports multiple notification handlers.
Passing a third party’s notification to
setNotificationRequest
orsetNotificationUserInfo
is essentially a no-op call. The SDK only emits logs indicating the origin of the notification wasn’t from Engagement.- Geolocation
If you implement multiple SDKs that use location-enabled services, use only one SDK’s location enablement. Using more than one leads to unknown and unsupportable consequences. For example, the methods used by the other providers to interact with iOS
CoreLocation
services and enable location services are likely to affect each provider.An app can monitor a limited number of geofences at any given time. This number depends on iOS version, device type, and other considerations. With multiple implementations competing for a limited resource, the user experience can suffer. Additionally, permissions needed to use location-enabled SDKs can overlap or conflict.
- Feedback
Not all providers are able to detect if a device has been unregistered.
To see how notifications are handled using Firebase as a push provider, see the iOS LearningApp.
iOS Data Protection affects the SDK as described in the following table.
iOS Data Protection Level | SDK Behavior |
---|---|
No protection | SDK works in the foreground and background |
Complete until first user authentication | SDK works in the foreground and background after the first unlock |
Complete unless open | SDK works in the foreground and background after the first unlock |
Complete | SDK works only in the foreground after the device is unlocked |
The MobilePush SDK requires access to files on the iOS Device file system. Some iOS Data Protection modes can prevent the SDK from accessing the needed files at certain times. During normal operation, the SDK must have access to files while running in the foreground and while running in the background. If the SDK can't access these files due to an iOS Data Protection mode, an error is logged and file access fails.
By default, the SDK sets the file protection type to NSFileProtectionCompleteUntilFirstUserAuthentication
. With this file protection type, files are stored in an encrypted format on disk and can't be read from or written to until the user unlocks the device for the first time. As of version 8.0.9, the SDK continues to retain the default protection type (NSFileProtectionCompleteUntilFirstUserAuthentication
). However, it also provides the capability to override the file protection type within the consuming application. You can choose different file protection types, such as NSFileProtectionComplete
and NSFileProtectionCompleteUnlessOpen
, based on your specific needs.
NSSQLiteErrorDomain
errors can appear in logs if the FileProtectionType
is NSFileProtectionComplete
and the application goes to the background.
The following example shows how you can override the file protection type.
For an additional example of overriding the file protection type, see the learning application.
If you configure iOS data protection such that the file system isn’t accessible during the SDK configuration call, the SDK retries the call for up to 5 seconds. This retry period allows time for a user to unlock the device and make the file system accessible. If the user doesn’t unlock the device within 5 seconds, an error object is returned describing the error, and the configuration call fails, returning false
. In this case, the SDK isn't configured, and no access to SDK methods must be attempted until the configure
method returns true
. The error
object returns the error code configureDatabaseAccessError
.
Certain features of the SDK require access to the file system as the app transitions to the foreground or background. Foreground operations include retrieving messages from Engagement for inbox messaging, location messaging, and sending analytic information back to Engagement. Background operations include sending analytic information back to Engagement. If any of these features are enabled via configuration, then an appropriate iOS Data Protection mode must be selected for them to work correctly.
For iOS applications upgraded from SDK versions 7.x to versions up to 8.0.6, the previous v7.x tags and attributes are retained on the device but not sent to the server. If an application doesn't reset or regenerate tags and attributes, the device sends empty tags and attributes to the system.
The following sections walk through the requirements for merging datasets successfully.
Using SPM, upgrade to the latest version of the MobilePush SDK for iOS and SFMCSDK for iOS.
The merging tool offers two options to merge attributes and tags: automatic merging and manual merging. In some scenarios, you can choose to defer or avoid merging the datasets. The merging tool defaults to an "opted out" state if you don't implement either of the merging methods. In the opted out state, tags and attributes aren't merged from the version 7.x dataset to your current application's dataset.
The automatic merging option attempts to merge old data into the current dataset, with the current data taking precedence over data within the version 7.x dataset.
The following tables illustrate how automatic merging behaves and how data is merged.
In the following tables, key-value pairs are denoted using :
as the separator.
Attributes
Prior Dataset | Current Dataset | Merge Result |
---|---|---|
A | empty | A |
empty | A | A |
A, C | A | A |
A | A: cleared | A: cleared |
Tags
Prior Dataset | Current Dataset | Merge Result |
---|---|---|
SHIRTS | empty | SHIRTS |
empty | PANTS | PANTS |
SHIRTS | PANTS | SHIRTS, PANTS |
SHIRTS | SHIRTS, PANTS | SHIRTS, PANTS |
The following code snippets show you how to configure the SDK to attempt an automatic merge.
To ensure the completion callback passed into setAutoMergePolicy
is set before SDK initialization, place the following code snippets before SDK initialization.
The manual merge option enables you to receive both the prior data and the current data in a callback, providing the opportunity to choose what data ultimately ends up in the final dataset.
You can decide what attributes and tags are set in the current dataset. However, to set attributes and tags accordingly, you must retain the data until the SDK is initialized.
Access to the tags and attributes for versions 7.x and 8.x is provided before SDK initialization.
If you must run the merge tool again, you can attempt the merge multiple times.
Reattempting merges doesn’t roll back the current dataset but enables you to regain access to the data within the old version 7.x dataset.
The following troubleshooting guidance applies only to MobilePush iOS SDK versions up to 8.0.13.
Fatal Keychain Access exceptions occur when an application with an active MobilePush SDK integration tries to access Keychain on a locked device secured with Face ID or passcode-based authentication. iOS Data Protection modes prevent the MobilePush SDK from accessing these files.
The following sections describe common Keychain Access exceptions and provide guidance on resolving them.
The following are common occurrences of the errSecInteractionNotAllowed
exception:
Fatal Exception: com.salesforce.security.keychainException dictionaryItemFromKeychain: Error attempting to look up keychain item: errSecInteractionNotAllowed
Fatal Exception: com.salesforce.security.keychainException setObject:forKey:: Error saving value to the keychain: errSecInteractionNotAllowed.
Fatal Exception: com.salesforce.security.keychainException writeToKeychain: Error adding keychain item: errSecInteractionNotAllowed.
To resolve errSecInteractionNotAllowed
exceptions, follow these steps.
-
Upgrade to MobilePush iOS SDK version 8.0.8 and SFMC SDK version 1.0.6
-
Before initializing the SDK, set the
setKeychainAccessErrorsAreFatal
method tofalse
as shown in the following example.Doing so logs the exception to the console instead of causing the application to crash.
By default, the SDK sets
setKeychainAccessErrorsAreFatal
totrue
.
You can encounter the following error message that indicates a keychain access issue along with an unknown status code (-34018)
.
To resolve this issue, enable Keychain Sharing in Xcode's Signing & Capabilities. While enabling Keychain Sharing, you don't need to add identifiers specific to the SDK.
For an example of an ideal MobilePush iOS SDK implementation, review the iOS LearningApp.
Not all pieces of code used in the LearningApp are mandatory. Depending on your app, you can decide which parts to use or replicate and which ones to ignore.
The following troubleshooting guidance applies only to MobilePush iOS SDK versions up to 8.0.13. Starting version 8.1.0, the SDK automatically includes the bundle in applications, eliminating the need for manual addition.
When upgrading to the latest version of the SDK, changes to MarketingCloudSDK.bundle
are expected. If you don't copy the right versions, your app can crash with exceptions as the older versions of MarketingCloudSDK.bundle
don't have the required resources.
When you don't include the latest MarketingCloudSDK.bundle
in your app, you can encounter the following exceptions.
- NSInvalidArgumentException
Reason:
+entityForName: nil is not a legal NSManagedObjectContext parameter searching for entity name 'SFMCEndpointConfigurationEntity'
- NSInternalInconsistencyException
Reasons:
'NSFetchRequest could not locate an NSEntityDescription for entity name 'SFMCEventConfigurationEntity''
'Cannot create an NSPersistentStoreCoordinator with a nil model'
To resolve these exceptions, upgrade to the latest version of the SDK and then follow these steps.
- Remove the existing
MarketingCloudSDK.bundle
from Xcode under Build phases > Copy Resources Bundle. - Based on your integration method, add the latest
MarketingCloudSDK.bundle
.- If you're using SPM as a dependency manager, following the instructions provided in the iOS Migration Guide.
- If you're using other integration methods, follow the guidance in the Quickstart Guide for iOS.
For every upgrade of the SDK, we recommend pulling MarketingCloudSDK.bundle
each time to ensure your app is using the latest bundle.
Silent push notifications are delivered without an alert message or sound, typically to trigger updates to the app UI or background operations. A silent push notification wakes your app from a "Suspended" or "Not Running" state to update content or run certain background tasks without notifying users.
To use silent push notifications to trigger background tasks, you must configure your app to receive notifications even when it's in the background. To do so, navigate to the Signing & Capabilities pane on Xcode, and add the Background Modes capability to the main app target. Also ensure that you select the Remote notifications checkbox.
To handle silent push notifications, the app must implement the application:didReceiveRemoteNotification:fetchCompletionHandler:
application delegate method. For more information, see Apple's documentation on Pushing background updates to your app.