Troubleshooting
This guide helps you diagnose and resolve common issues when integrating the StorifyMe iOS SDK.
Widget Not Loading
Widget shows blank/empty space
Symptoms:
- StorifyMeWidget is visible but shows no content
- No stories appear even after calling
load()
Common Causes & Solutions:
-
Invalid Widget ID
// ❌ Wrong
storifyMeWidget.setWidgetId(widgetId: 0)
// ✅ Correct
storifyMeWidget.setWidgetId(widgetId: YOUR_VALID_WIDGET_ID) -
SDK Not Ready
Check if the SDK has finished initializing:
// Check SDK state
print("SDK State: \(StorifyMeInstance.shared.state)")
print("SDK isReady: \(StorifyMeInstance.shared.isReady)")
// Use initialization callback to ensure SDK is ready
StorifyMeInstance.shared.initialize(
accountId: "your-account-id",
apiKey: "your-api-key"
) { result in
switch result {
case .success:
print("SDK ready - widgets will load now")
case .failure(let error):
print("SDK failed: \(error.message)")
}
}Widget Auto-WaitWidgets now automatically wait for SDK initialization. If your widget shows blank, the issue is likely with credentials or network, not timing.
-
Missing SDK Initialization
// ✅ Ensure initialization in AppDelegate or SceneDelegate
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
StorifyMeInstance.shared.initialize(
accountId: "your-account-id",
apiKey: "your-api-key"
)
return true
} -
Network Security Issues
<!-- In Info.plist, add if testing with HTTP -->
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict> -
Widget Not Published
- Check StorifyMe Dashboard to ensure widget is published
- Verify widget contains published stories
Widget fails to load with error
Implement Event Handler:
extension ViewController: StorifyMeStoryEventProtocol {
func onFail(error: StorifyMeError) {
print("StorifyMe Error: \(error.message)")
// Common errors:
// - "Widget not found" - Invalid widget ID
// - "Network error" - Connectivity issues
// - "Unauthorized" - Invalid API key/account ID
}
}
Build Issues
CocoaPods Integration Problems
Pod Installation Issues:
# Clear CocoaPods cache
pod cache clean --all
pod deintegrate
pod install --repo-update
# If using Xcode 15+, you might need:
pod install --verbose
Podfile Configuration:
platform :ios, '12.0'
use_frameworks!
target 'YourApp' do
pod 'StorifyMe', '~> <latest-version>'
# If you encounter issues, try:
# pod 'StorifyMe', :git => 'https://github.com/StorifyMe/sdk-ios.git'
end
# Add this if you have module issues
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['BUILD_LIBRARY_FOR_DISTRIBUTION'] = 'YES'
end
end
end
Swift Package Manager Issues
Package Resolution Problems:
// In Package.swift or Xcode Package Manager
.package(url: "https://github.com/StorifyMe/sdk-ios.git", from: "<latest-version>")
Common SPM Errors:
- Clear derived data:
Product > Clean Build Folder - Reset package caches:
File > Packages > Reset Package Caches - Update to latest:
File > Packages > Update to Latest Package Versions
CocoaPods Deprecation
CocoaPods support is deprecated and will be removed by the end of 2026. We strongly recommend migrating to Swift Package Manager.
Why is CocoaPods being deprecated?
CocoaPods announced they are transitioning to read-only mode in December 2026. To ensure long-term support and better integration with modern iOS development, we're migrating to Swift Package Manager, Apple's official dependency manager.
What does this mean for me?
- v2.6.x (Current): CocoaPods fully supported with deprecation warnings
- v2.7.x (Next): Final CocoaPods release with enhanced migration resources
- v2.8.x (Future): CocoaPods support removed
How do I migrate?
See our comprehensive Migration Guide. Migration typically takes under 5 minutes.
Can I stay on CocoaPods?
You can continue using CocoaPods with StorifyMe v2.7.x (the last supported version), but you won't receive updates after the final CocoaPods version is released. We strongly recommend migrating to SPM to continue receiving:
- Security updates
- New features
- Bug fixes
- Performance improvements
Compilation Errors
Missing Frameworks:
// Ensure these frameworks are linked
// UIKit, Foundation, AVFoundation, WebKit
// Usually handled automatically by CocoaPods/SPM
Bitcode Issues (Legacy):
# In Build Settings, set Enable Bitcode to NO if encountering issues
# (Note: Bitcode deprecated in Xcode 14+)
Runtime Issues
App Crashes
StorifyMe Initialization Crash:
// ❌ Wrong - calling before initialization
StorifyMeInstance.shared.openStoryByHandle(handle: "test")
// ✅ Correct - initialize first
StorifyMeInstance.shared.initialize(accountId: "id", apiKey: "key")
StorifyMeInstance.shared.openStoryByHandle(handle: "test")
Memory Crashes:
// Implement proper memory management
override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
// Clear resources if widget provides cleanup method
storifyMeWidget.cleanup() // If available
}
Thread Safety Issues:
// Always call SDK methods on main thread
DispatchQueue.main.async {
self.storifyMeWidget.load()
}
Performance Issues
Slow Loading
Add Custom Logging:
// For development builds only
#if DEBUG
extension ViewController: StorifyMeStoryEventProtocol {
func onLoad(widgetId: Int, stories: [StorifyMeStoryModel]) {
print("✅ StorifyMe: Widget \(widgetId) loaded with \(stories.count) stories")
}
func onFail(error: StorifyMeError) {
print("❌ StorifyMe: Widget failed - \(error.message)")
}
}
#endif
Monitor Loading Performance:
extension ViewController: StorifyMeStoryEventProtocol {
func onLoad(widgetId: Int, stories: [StorifyMeStoryModel]) {
let loadTime = Date().timeIntervalSince(startTime)
print("Widget loaded in \(loadTime) seconds")
}
}
Optimize for Performance:
// Disable resource-intensive features if needed
storifyMeWidget.setGifPosterEnabled(false)
storifyMeWidget.setVideoPosterEnabled(false)
Memory Issues
High Memory Usage:
// Monitor memory in development
// Use Xcode Instruments to profile memory usage
// Optimize poster settings
storifyMeWidget.setGifPosterEnabled(false) // Reduces memory
storifyMeWidget.setVideoPosterEnabled(false) // Reduces memory
Story Opening Issues
Stories not opening when tapped
Check Event Handler Implementation:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// ❌ Missing event handler assignment
storifyMeWidget.setWidgetId(widgetId: WIDGET_ID)
// ✅ Correct - assign event handler
storifyMeWidget.eventHandler = self
storifyMeWidget.setWidgetId(widgetId: WIDGET_ID)
}
}
extension ViewController: StorifyMeStoryEventProtocol {
func onStoryOpen(widgetId: Int, storyId: Int, storyHandle: String) {
print("Story opened: \(storyHandle)")
}
}
View Controller Hierarchy Issues:
// Ensure widget is added to view hierarchy properly
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(storifyMeWidget)
storifyMeWidget.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
storifyMeWidget.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
storifyMeWidget.leadingAnchor.constraint(equalTo: view.leadingAnchor),
storifyMeWidget.trailingAnchor.constraint(equalTo: view.trailingAnchor),
storifyMeWidget.heightAnchor.constraint(equalToConstant: 120)
])
}
openStoryByHandle not working
Common Issues:
// ❌ Wrong - not initialized
StorifyMeInstance.shared.openStoryByHandle(handle: "test")
// ✅ Correct - ensure initialization
StorifyMeInstance.shared.initialize(accountId: "id", apiKey: "key")
StorifyMeInstance.shared.openStoryByHandle(handle: "test")
// ❌ Wrong - invalid handle
StorifyMeInstance.shared.openStoryByHandle(handle: "")
// ✅ Correct - valid handle
StorifyMeInstance.shared.openStoryByHandle(handle: "valid-story-handle")
Configuration Issues
Stories not playing audio
Check Audio Configuration:
storifyMeWidget.setWidgetAudioOptions(
options: StorifyMeStoryAudioOptions(
behaviour: .applyLastUserChangeForAllFutureStories,
defaultState: .unmuted // Check this setting
)
)
iOS Audio Session Issues:
// In some cases, you might need to configure audio session
import AVFoundation
override func viewDidLoad() {
super.viewDidLoad()
do {
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
try AVAudioSession.sharedInstance().setActive(true)
} catch {
print("Audio session error: \(error)")
}
}
Wrong layout or appearance
Auto Layout Issues:
// Ensure proper constraints
storifyMeWidget.translatesAutoresizingMaskIntoConstraints = false
// Common constraint issues
NSLayoutConstraint.activate([
storifyMeWidget.heightAnchor.constraint(equalToConstant: 120), // Set explicit height
storifyMeWidget.widthAnchor.constraint(equalTo: view.widthAnchor)
])
Dark Mode Issues:
// Test in both light and dark mode
// Override if needed:
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
if traitCollection.userInterfaceStyle != previousTraitCollection?.userInterfaceStyle {
// Handle appearance changes if needed
storifyMeWidget.refreshAppearance() // If available
}
}
Deep Link Issues
Deep links not working
Associated Domains Configuration:
<!-- In YourApp.entitlements -->
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yourdomain.com</string>
<!-- Make sure domain matches exactly -->
</array>
URL Handling Issues:
// SceneDelegate
func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
guard userActivity.activityType == NSUserActivityTypeBrowsingWeb,
let url = userActivity.webpageURL else {
return
}
print("Received URL: \(url)") // Add logging
handleDeepLink(url: url)
}
// AppDelegate (if not using SceneDelegate)
func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
print("Received URL: \(userActivity.webpageURL)") // Add logging
// Handle URL
return true
}
SwiftUI Issues
Widget not displaying in SwiftUI
Use the native StorifyMeWidgetView wrapper instead of manual UIViewRepresentable:
import SwiftUI
import StorifyMe
struct ContentView: View {
@State private var widgetHeight: CGFloat = 150
var body: some View {
StorifyMeWidgetView(widgetId: 54, height: $widgetHeight)
.frame(height: widgetHeight)
.onError { error in
print("Widget error: \(error.message)")
}
}
}
See the SwiftUI Integration Guide for complete documentation.
Memory not releasing on navigation
Problem: GIF memory is not released when navigating away from a screen with widgets.
Solution: Clear GIF cache in onDisappear:
struct StoriesScreen: View {
var body: some View {
StorifyMeWidgetView(widgetId: 54)
.frame(height: 200)
.onDisappear {
StorifyMeWidgetView.clearGifCache()
}
}
}
Height not updating in ScrollView
Problem: Widget height doesn't update dynamically in ScrollView.
Solution: Use the height binding parameter:
struct ScrollViewExample: View {
@State private var widgetHeight: CGFloat = 150
var body: some View {
ScrollView {
StorifyMeWidgetView(widgetId: 54, height: $widgetHeight)
.frame(height: widgetHeight) // Important: Apply frame with binding
}
}
}
iOS 17+ dismantleUIView not called
Problem: In iOS 17+, dismantleUIView may not be called reliably (Apple bug FB11979117).
Solution: The SDK implements fallback cleanup in Coordinator's deinit, but always use explicit cleanup:
.onDisappear {
StorifyMeWidgetView.clearGifCache()
}
Widget not loading in Xcode Preview
Problem: Widget shows blank in Xcode Preview.
Solution: Xcode Previews don't support full SDK initialization. Use conditional compilation:
struct ContentView: View {
var body: some View {
#if DEBUG
if ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1" {
// Show placeholder in preview
Rectangle()
.fill(Color.gray.opacity(0.3))
.frame(height: 200)
.overlay(Text("StorifyMe Widget"))
} else {
StorifyMeWidgetView(widgetId: 54)
.frame(height: 200)
}
#else
StorifyMeWidgetView(widgetId: 54)
.frame(height: 200)
#endif
}
}
SDK State Debugging
Check SDK Initialization State
When debugging issues, start by checking the SDK state:
func debugSDKState() {
let instance = StorifyMeInstance.shared
print("=== StorifyMe SDK Debug Info ===")
print("State: \(instance.state)")
print("isReady: \(instance.isReady)")
switch instance.state {
case .inactive:
print("⚠️ SDK has not been initialized or was shut down")
case .initializing:
print("⏳ SDK is currently initializing...")
case .ready:
print("✅ SDK is ready to use")
case .failed(let error):
print("❌ SDK failed to initialize:")
print(" Error Type: \(error.type)")
print(" Message: \(error.message)")
}
print("================================")
}
Monitor SDK Lifecycle Events
Use notifications to track SDK state changes throughout your app:
class SDKStateMonitor {
init() {
NotificationCenter.default.addObserver(
self,
selector: #selector(sdkDidBecomeReady),
name: .storifyMeSDKDidBecomeReady,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(sdkDidFail(_:)),
name: .storifyMeSDKDidFailToInitialize,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(sdkDidShutdown),
name: .storifyMeSDKDidShutdown,
object: nil
)
}
@objc private func sdkDidBecomeReady() {
print("📗 SDK became ready at \(Date())")
}
@objc private func sdkDidFail(_ notification: Notification) {
if let error = notification.userInfo?[StorifyMeSDKErrorKey] as? StorifyMeError {
print("📕 SDK failed at \(Date()): \(error.message)")
}
}
@objc private func sdkDidShutdown() {
print("📙 SDK was shut down at \(Date())")
}
}
Resolve Memory Issues with shutdown
If you're experiencing memory issues or need to reset the SDK:
// Clean up SDK resources when no longer needed
StorifyMeInstance.shared.shutdown {
print("SDK resources released")
// Optionally re-initialize if needed
// StorifyMeInstance.shared.initialize(...)
}
Common scenarios for using shutdown:
-
Memory Warnings
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// If stories are not currently visible, release SDK resources
if !isStoriesVisible {
StorifyMeInstance.shared.shutdown()
}
} -
User Logout
func logout() {
// Clean up SDK before logging out
StorifyMeInstance.shared.shutdown {
// Proceed with logout
self.clearUserSession()
}
} -
Account Switching
func switchToAccount(_ accountId: String, apiKey: String) {
StorifyMeInstance.shared.shutdown { [weak self] in
StorifyMeInstance.shared.initialize(
accountId: accountId,
apiKey: apiKey
) { result in
// Handle result
}
}
}
Debug Tools
Enable SDK Debug Logging
The fastest way to debug issues is to enable SDK logging:
// Enable verbose logging for maximum detail
StorifyMeInstance.shared.logLevel = .verbose
// Or debug level for standard debugging
StorifyMeInstance.shared.logLevel = .debug
View logs in:
- Xcode Console: Real-time during debugging
- Console.app: Filter by subsystem
com.storifyme.sdk
Log output format:
[StorifyMe] [DEBUG] [Widget] Loading widget configuration
[StorifyMe] [ERROR] [Network] Request failed: timeout
Set logLevel before calling initialize() to capture initialization logs. See the Logging section for more details.
Add Comprehensive Logging
#if DEBUG
extension ViewController: StorifyMeStoryEventProtocol {
func onLoad(widgetId: Int, stories: [StorifyMeStoryModel]) {
print("✅ StorifyMe-Debug: Widget \(widgetId) loaded with \(stories.count) stories")
}
func onFail(error: StorifyMeError) {
print("❌ StorifyMe-Debug: Widget failed - \(error.message)")
}
func onStoryOpened(story: StorifyMeStoryModel?, index: Int) {
print("📖 StorifyMe-Debug: Story opened at index \(index)")
}
func onStoryClose(story: StorifyMeStoryModel?) {
print("📕 StorifyMe-Debug: Story closed")
}
}
#endif
Console Logging
// Add comprehensive logging
extension ViewController: StorifyMeStoryEventProtocol {
func onLoad(widgetId: Int, stories: [StorifyMeStoryModel]) {
print("✅ Loaded \(stories.count) stories for widget \(widgetId)")
}
func onFail(error: StorifyMeError) {
print("❌ Failed to load widget: \(error.message)")
}
func onStoryOpened(story: StorifyMeStoryModel?, index: Int) {
print("📖 Story opened at index \(index)")
}
func onStoryClose(story: StorifyMeStoryModel?) {
print("📕 Story closed")
}
}
Network Debugging
// Monitor network requests (if SDK provides callback)
// Use Xcode Network debugging or Charles Proxy to monitor requests
Testing Tools
Simulator Testing
# Test deep links in simulator
xcrun simctl openurl booted "https://yourdomain.com/story-handle"
Device Testing
- TestFlight: Use TestFlight builds to test in production-like environment
- Debug Builds: Use debug builds with detailed logging
- Network Conditions: Test with poor network conditions
Getting Help
Information to Provide
When reporting issues, include:
- SDK Version: Check your Podfile.lock or Package.resolved
- iOS Version: Device OS version
- Xcode Version: Development environment version
- Device Model: iPhone/iPad model
- Integration Method: CocoaPods, SPM, or manual
- Error Logs: Complete console output
- Configuration Code: Your widget setup code
Useful Debug Commands
# Check CocoaPods setup
pod --version
pod outdated
# Check Xcode build settings
xcodebuild -showBuildSettings -target YourApp
# Test deep links
xcrun simctl openurl booted "https://yourdomain.com/test-handle"
Xcode Debugging Tools
- Console: View real-time logs
- Instruments: Profile memory and performance
- Network Link Conditioner: Test with poor network
- Accessibility Inspector: Test accessibility features
Best Practices for Debugging
- Always test on physical devices
- Use debug mode during development only
- Test with different iOS versions
- Verify network connectivity
- Check StorifyMe Dashboard configuration
- Use Xcode Instruments for performance debugging
- Test in both light and dark mode
Performance Monitoring
// Monitor key metrics
class PerformanceMonitor: StorifyMeStoryEventProtocol {
private var loadStartTime: Date?
func startMonitoring() {
loadStartTime = Date()
}
func onLoad(widgetId: Int, stories: [StorifyMeStoryModel]) {
if let startTime = loadStartTime {
let duration = Date().timeIntervalSince(startTime)
print("Load time: \(duration)s for \(stories.count) stories")
}
}
}
For additional support, refer to the StorifyMe Documentation or contact the support team with the debug information listed above.