BranchMetrics / ios-branch-deep-linking-attribution

The Branch iOS SDK for deep linking and attribution. Branch helps mobile apps grow with deep links / deeplinks that power paid acquisition and re-engagement campaigns, referral programs, content sharing, deep linked emails, smart banners, custom user onboarding, and more.
https://help.branch.io/developers-hub/docs/ios-sdk-overview
MIT License
728 stars 229 forks source link

Thread 1: EXC_BAD_ACCESS (code=1, address=0x0) #818

Closed blakedallen closed 6 years ago

blakedallen commented 6 years ago

Getting a EXC_BAD_ACCESS error in iOS 11.3, Swift 4 when tapping on a deep link. I have created a separate new project to make sure that the branch library wasn't interacting with any other libraries. Followed the steps in the SDK install instructions.

Error occurs when: Tapping a deep link in google inbox --> user is successfully routed to the app --> the app crashes when loading. https://cl.ly/30351I1s0G2j

App Delegate

import UIKit
import Branch

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        let branch: Branch = Branch.getInstance()
        branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: {params, error in
            if error == nil {
                // params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
                // params will be empty if no data found
                // ... insert custom logic here ...
                print("params: %@", params as? [String: AnyObject] ?? {})
            }
        })

        return true
    }

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

    // Respond to URI scheme links
    func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
        // pass the url to the handle deep link call
        let branchHandled = Branch.getInstance().application(application,
                                                             open: url,
                                                             sourceApplication: sourceApplication,
                                                             annotation: annotation
        )
        if (!branchHandled) {
            // If not handled by Branch, do other deep link routing for the Facebook SDK, Pinterest SDK, etc
        }

        // do other deep link routing for the Facebook SDK, Pinterest SDK, etc
        return true
    }

    // Respond to Universal Links
    func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
        // pass the url to the handle deep link call
        Branch.getInstance().continue(userActivity)

        return true
    }

}

Important note: When opening the app the branch parameters are there, so we know deferred deep linking is working, however there seems to be a crash on load with deep linking.

Would love to know if there is something I'm missing here. Thanks in advance!

E-B-Smith commented 6 years ago

Hmm, this works for me with both deferred deep linking and regular deep linking. I'm using Xcode 9.3 / iOS 11.3 / iPhone 7 Plus.

Try change the casting so that it matches the actual parameters that are passed:

print("Params: %@", params as [AnyHashable: AnyObject]? ?? {})

Here's the whole code snippet of my application:didFinishLaunchingWithOptions: method:

    func application(_ application: UIApplication,
            didFinishLaunchingWithOptions launchOptions:[UIApplicationLaunchOptionsKey: Any]?
        ) -> Bool {
        AppData.shared.initialize()
        let branch: Branch = Branch.getInstance()
        branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: {params, error in
            if error == nil {
                // params are the deep linked params associated with the link that the
                // user clicked -> was re-directed to this app
                // params will be empty if no data found
                // ... insert custom logic here ...
                print("Params: %@", params as [AnyHashable: AnyObject]? ?? {})
            }
        })
        return true
    }
E-B-Smith commented 6 years ago

@blakedallen Did you resolve your issue?

E-B-Smith commented 6 years ago

If you're still crashing you can re-open this issue.

blakedallen commented 6 years ago

@E-B-Smith Thank you for your response! This was tricky to debug but I looked into this and found out how to reproduce. So in our setup we're using branch to deeplink a user from an email to the app. The flow currently works like so:

User taps email link --> user is sent to our server --> our server requests a branch link --> user is redirected to the branch link --> user opens the app --> app crashes

The issue it turns out, stems from us using a redirect. When I just tap the branch link directly, things work fine. If I redirect the user to a branch link, the app crashes on load.

As a simple solution, we could just include the link as-is in the email, which would require us to request the deeplink from branch and then include that in the email (rather than my system generating these links when the user taps and redirecting the user)

Is this a known issue with the branch SDK? We used this flow about a year ago and it seemed to work fine then, if it's not how to properly use branch links we can adjust, but thought it was worth mentioning the problem here.

E-B-Smith commented 6 years ago

I still don't quite understand why you're getting a crash here, but I'm glad you solved it.

Branch has a deep-linked email solution. Here's a link to the docs: https://docs.branch.io/pages/emails/get-started/

This may save you some grief.