Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IOS] Unity Crashes on Startup with Deep Link Launch EXC_BAD_ACCESS (code=1, address=0x378) #712

Open
Vitalchek opened this issue Jan 12, 2024 · 21 comments
Labels

Comments

@Vitalchek
Copy link

Vitalchek commented Jan 12, 2024

Checklist

  • I've updated to the latest released version of the Facebook SDK and also set previous versions
  • I've changed Unity versions

Environment

  • Unity 2022.3.14f1
  • Xcode 15.2
  • Facebook SDK Version 15.1
  • MacOs - Sonoma
  • Platform - IOS

Goals

The application was launched via a deep link

Expected Results

The application crashes at startup. When I tried to delete the Facebook SDK, everything works perfectly. This prom=blem only on IOS, Android works fine.

Before updating to Unity 2022 and updating macOs - Sonoma and Xcode 15, it worked perfectly.

Actual Results

Error

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x378) frame #0: 0x00000001171ee5ec UnityFrameworkcore::StringStorageDefault::assign(char const*, unsigned long) + 28
frame #1: 0x000000011791c4b8 UnityFrameworkPlayerSettings::SetAbsoluteURL(core::basic_string<char, core::StringStorageDefault<char>> const&) + 44 frame #2: 0x000000011799e778 UnityFrameworkUnitySetAbsoluteURL + 108
frame #3: 0x00000001155073d8 UnityFramework-[UnityAppController application:openURL:options:] + 192 frame #4: 0x000000019905e724 UIKitCore__58-[UIApplication _applicationOpenURLAction:payload:origin:]_block_invoke + 1024
frame #5: 0x000000019905e174 UIKitCore-[UIApplication _applicationOpenURLAction:payload:origin:] + 788 frame #6: 0x000000019845c3d8 UIKitCore-[UIApplication _callInitializationDelegatesWithActions:forCanvas:payload:fromOriginatingProcess:] + 3256
frame #7: 0x000000019845b22c UIKitCore-[UIApplication _runWithMainScene:transitionContext:completion:] + 856 frame #8: 0x000000019845ae78 UIKitCore-[_UISceneLifecycleMultiplexer completeApplicationLaunchWithFBSScene:transitionContext:] + 132
frame #9: 0x00000001983d7798 UIKitCore_UIScenePerformActionsWithLifecycleActionMask + 112 frame #10: 0x000000019845ee74 UIKitCore__101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke + 216
frame #11: 0x0000000198386778 UIKitCore-[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:] + 220 frame #12: 0x00000001983851f0 UIKitCore-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 608
frame #13: 0x0000000198384b58 UIKitCore-[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:] + 248 frame #14: 0x0000000198384a28 UIKitCore__186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke + 148
frame #15: 0x0000000198384930 UIKitCore+[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] + 736 frame #16: 0x00000001983841b8 UIKitCore_UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion + 224
frame #17: 0x0000000198383e68 UIKitCore-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 316 frame #18: 0x0000000198707620 UIKitCore__64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.225 + 612
frame #19: 0x0000000198382fec UIKitCore-[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 216 frame #20: 0x0000000198382e5c UIKitCore-[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 244
frame #21: 0x000000019849b484 UIKitCore-[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 508 frame #22: 0x000000019849b21c UIKitCore-[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 288
frame #23: 0x00000001ae2c76d4 FrontBoardServices-[FBSScene _callOutQueue_didCreateWithTransitionContext:completion:] + 324 frame #24: 0x00000001ae2c7570 FrontBoardServices__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke.108 + 280
frame #25: 0x00000001ae2c619c FrontBoardServices-[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 168 frame #26: 0x00000001ae2d1f8c FrontBoardServices__92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke + 352
frame #27: 0x000000019dfe5300 libdispatch.dylib_dispatch_client_callout + 20 frame #28: 0x000000019dfe8d48 libdispatch.dylib_dispatch_block_invoke_direct + 284
frame #29: 0x00000001ae2c2520 FrontBoardServices__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52 frame #30: 0x00000001ae2c24a0 FrontBoardServices-[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
frame #31: 0x00000001ae2c2378 FrontBoardServices-[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28 frame #32: 0x000000019605f31c CoreFoundationCFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 28
frame #33: 0x000000019605e598 CoreFoundation__CFRunLoopDoSource0 + 176 frame #34: 0x000000019605cd4c CoreFoundation__CFRunLoopDoSources0 + 244
frame #35: 0x000000019605ba88 CoreFoundation__CFRunLoopRun + 828 frame #36: 0x000000019605b668 CoreFoundationCFRunLoopRunSpecific + 608
frame #37: 0x00000001d94265ec GraphicsServicesGSEventRunModal + 164 frame #38: 0x00000001984782b4 UIKitCore-[UIApplication _run] + 888
frame #39: 0x00000001984778f0 UIKitCoreUIApplicationMain + 340 frame #40: 0x000000011550bc0c UnityFramework-[UnityFramework runUIApplicationMainWithArgc:argv:] + 92`

@Vitalchek Vitalchek added the bug label Jan 12, 2024
@Vitalchek Vitalchek changed the title [IOS] Unity Crashes on Startup with Deep Link Launch [IOS] Unity Crashes on Startup with Deep Link Launch EXC_BAD_ACCESS (code=1, address=0x378) Jan 12, 2024
@StrozhDima
Copy link

StrozhDima commented Jan 15, 2024

Confirm crashes at startup on SDK versions 15.1.0 and 16.0.2 and Unity 2022.3.16f1
UPD: The problem appeared in version 2022.3.13f. Version 2022.3.12f works without this problem.

@Vitalchek
Copy link
Author

Great, thank you very much, I spent so much time. Thanks for the answer

@StrozhDima
Copy link

Unity issue link

@xTheEc0
Copy link

xTheEc0 commented Jan 23, 2024

Seems like FacebookSDK issue.
FixColdStart() is a 9 year old addition, that now misbehaves.
Maybe in the past it worked, but now Unity trampoline function didFinishLaunchingWithOptions looks completely different, so this ends up editing one function below (isBackgroundLaunchOptions) by accident.

I think the whole regex replacement part can be deleted from FacebookSDK, if anyone wants to make a PR.

As a workaround: In the Xcode build, modify the Unity-iPhone/Classes/UnityAppController.mm isBackgroundLaunchOptions last line from return YES; to return NO;

Bad code:

- (BOOL)isBackgroundLaunchOptions:(NSDictionary*)launchOptions
{
    if (launchOptions.count == 0)
        return NO;

    // launch due to location event, the app likely will stay in background
    BOOL locationLaunch = [[launchOptions valueForKey: UIApplicationLaunchOptionsLocationKey] boolValue];
    if (locationLaunch)
        return YES;
    return YES; // <-- ISSUE HERE
}

Good code:

- (BOOL)isBackgroundLaunchOptions:(NSDictionary*)launchOptions
{
    if (launchOptions.count == 0)
        return NO;

    // launch due to location event, the app likely will stay in background
    BOOL locationLaunch = [[launchOptions valueForKey: UIApplicationLaunchOptionsLocationKey] boolValue];
    if (locationLaunch)
        return YES;
    return NO;
}

P.S It looks like Unity regression (You said 2022.3.12f1 -> 2022.3.13f1), but we just refactored our launch code around there recently, so FBSDK started modifying it randomly, which is the root cause.

xTheEc0 added a commit to xTheEc0/facebook-sdk-for-unity that referenced this issue Jan 23, 2024
Due to Unity trampoline changes this is now misbehaving and modifying one function below (`isBackgroundLaunchOptions`) which causes a crash - see facebook#712
@Nezz
Copy link

Nezz commented Feb 19, 2024

@xTheEc0 Was the change in the original code introduced in Unity 2022.3.13 or an earlier version?

@mutluerdm
Copy link

mutluerdm commented Mar 6, 2024

Thx @xTheEc0

build post process fix :

        [PostProcessBuild(10000)]
        public static void IOSBuildPostProcess(BuildTarget target, string pathToBuiltProject)
        {
        .
        .
            FixColdStartFacebook(pathToBuiltProject);  // Call this function from your IOSBuildPostProcess 
        .
        .
        }


        private const string IsBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions.+(?:.*\n)+?\s*return\ )YES(\;\n\})# }";

        public static void FixColdStartFacebook(string path)
        {
            string fullPath = Path.Combine(path, Path.Combine("Classes", "UnityAppController.mm"));
            string data = Load(fullPath);

            data = Regex.Replace(
                data,
                IsBackgroundLaunchOptions,
                "$1NO$2");

            Save(fullPath, data);
        }
        
        static string Load(string fullPath)
        {
            string data;
            FileInfo projectFileInfo = new FileInfo(fullPath);
            StreamReader fs = projectFileInfo.OpenText();
            data = fs.ReadToEnd();
            fs.Close();

            return data;
        }

        static void Save(string fullPath, string data)
        {
            System.IO.StreamWriter writer = new System.IO.StreamWriter(fullPath, false);
            writer.Write(data);
            writer.Close();
        }

@Vitaliy060795
Copy link

I launch Unity successfully from a deep link when I add this code in post process, but Application.absoluteURL is empty (

@Vitaliy060795
Copy link

@mutluerdm maybe do you know ? why does it happen ?

@Nezz
Copy link

Nezz commented Mar 12, 2024

The change in Unity 2022.3.13 that triggered the issue is the following:

iOS: Fixed Unity launching in the background on background location event; fix black screen showing between splash screen and first scene (release build only). (UUM-52515)

Affected versions:
2021.3.31f1
2022.3.11f1
2023.1.17f1
2023.2.0b14
2023.3.0a10

@Vitalchek
Copy link
Author

Vitalchek commented Mar 12, 2024

@Nezz Is it possible to somehow fix it so that the game starts on unity
2022.3.14f1 version and reads the parameters from the deeplink?

@Nezz
Copy link

Nezz commented Mar 12, 2024

Yes, see #713

@PierrePlayrion
Copy link

The crash issue would be fixed with this PR but now deeplink data isn't reaching Unity. This persists in version 2022.3.19f.

@PierrePlayrion
Copy link

PierrePlayrion commented Mar 27, 2024

I managed to overcome the problem by saving the deeplink in objective C and retrieving it later on C# side.
If this can help anyone facing the issue while it's not fixed:

In Unity C# side:

public static class IOSCustomDeepLinkBridge
{
#if !UNITY_EDITOR
        [DllImport("__Internal")]
        private static extern string GetDeeplinkString();
#endif

        public static string RetrieveDeepLinkFromNativeSide()
        {
#if !UNITY_EDITOR
            return GetDeeplinkString();
#else
            return string.Empty;
#endif
        }
}

Added objective C files:
DeeplinkManager.h

#import <Foundation/Foundation.h>

@interface DeeplinkManager : NSObject

+ (instancetype)sharedManager;
- (void)handleDeeplinkURL:(NSURL *)deeplinkURL;
- (void)handleLaunchOptions:(NSDictionary*)launchOptions;
- (NSString *)getDeeplinkString;

@end

DeeplinkManager.mm

#import "DeeplinkManager.h"

extern "C"
{
    char* convertNSStringToCString(const NSString* nsString)
    {
        if (nsString == NULL)
            return NULL;
        
        const char* nsStringUtf8 = [nsString UTF8String];
        //create a null terminated C string on the heap so that our string's memory isn't wiped out right after method's return
        char* cString = (char*) malloc(strlen(nsStringUtf8) + 1);
        strcpy(cString, nsStringUtf8);
        
        return cString;
    }

    const char* GetDeeplinkString() {
        NSString* deeplinkString = [[DeeplinkManager sharedManager] getDeeplinkString];
        return convertNSStringToCString(deeplinkString);
    }
}
    
@interface DeeplinkManager ()

@property (nonatomic, strong) NSString* deeplinkString;

@end

@implementation DeeplinkManager

+ (instancetype) sharedManager {
    static DeeplinkManager* sharedInstance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedInstance = [[self alloc] init];
    });
    return sharedInstance;
}

- (void) handleDeeplinkURL:(NSURL*) deeplinkURL {
    // Handle deeplink URL here
    NSLog(@"[DeeplinkManager] Non empty deeplink URL: %@", deeplinkURL);
    
    // Convert URL to string and store it
    self.deeplinkString = [deeplinkURL absoluteString];
}

- (void) handleLaunchOptions:(NSDictionary*) launchOptions {

    NSURL* url = launchOptions[UIApplicationLaunchOptionsURLKey];
    if (url) {
        [self handleDeeplinkURL:url];
    }
}

/**
 * Retrieves the deeplink url stored when the application launched.
 * @return deep link url or empty string if no deeplink.
 */
- (NSString*) getDeeplinkString {
    if (!self.deeplinkString)
    {
        return @"";
    }
    return self.deeplinkString;
}

@end

And finally updating UnityAppController.mm to ensure getting the deeplink data that is not retrieved by Unity when using FBSDK:

 - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
  {
     // rest of the method
    // ...
 
     // Method handleLaunchOption to be called with launchOptions parameter.
     [[DeeplinkManager sharedManager] handleLaunchOption:launchOptions];
 
     // rest of the method, make sure to be called before isBackgroundLaunchOptions check
     if ([self isBackgroundLaunchOptions: launchOptions])
        return YES;
 
     [self initUnityWithApplication: application];
     return NO;
  }

@dhess-zynga
Copy link

I also attempted to apply the workaround posted by @mutluerdm, but I saw the same results as @PierrePlayrion (the crash was fixed, but the deeplink was not being handled properly)

To fix that I changed this line:

private const string IsBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions.+(?:.*\n)+?\s*return\ )YES(\;\n\})# }"

... to this:

private const string IsBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions:\(NSDictionary\*\)launchOptions(?:.*\n)+?\s*return\ )YES(\;\n\})# }"

and now my app links are being handled correctly.

(Context: I think the original RegEx changed more than was intended, not only changing the return value of that method, but also where it was called in application:didFinishLaunchingWithOptions)

Unity 2021.3.35f1
Facebook SDK 14.1.0

@pgv3n0m
Copy link

pgv3n0m commented Apr 2, 2024

I also attempted to apply the workaround posted by @mutluerdm, but I saw the same results as @PierrePlayrion (the crash was fixed, but the deeplink was not being handled properly)

To fix that I changed this line:

private const string IsBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions.+(?:.*\n)+?\s*return\ )YES(\;\n\})# }"

... to this:

private const string IsBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions:\(NSDictionary\*\)launchOptions(?:.*\n)+?\s*return\ )YES(\;\n\})# }"

and now my app links are being handled correctly.

(Context: I think the original RegEx changed more than was intended, not only changing the return value of that method, but also where it was called in application:didFinishLaunchingWithOptions)

Unity 2021.3.35f1 Facebook SDK 14.1.0

with your line change, I get the crash but not with the old one. I am on Unity 2022.3.19f and same FB SDK

Update: Never mind, I had a callback order issue

@keitanxkeitan
Copy link

keitanxkeitan commented Apr 3, 2024

with your line change, I get the crash but not with the old one. I am on Unity 2022.3.19f and same FB SDK

@pgv3n0m Could you provide the log you get?

@pgv3n0m
Copy link

pgv3n0m commented Apr 3, 2024

with your line change, I get the crash but not with the old one. I am on Unity 2022.3.19f and same FB SDK

@pgv3n0m Could you provide the log you get?

Nv, seems to work. I had a callback order issue I did in between the testing

@sebastian-dudzic-spl
Copy link

sebastian-dudzic-spl commented Apr 3, 2024

Few things I have to add:

  • Facebook - I don't understand why it's not fixed yet. It's a big issue and idea to modify not yours code in postprocess is very risky. If you decide to go for it, you need to maintain it...

  • Thanks to all people engaged here, we have a workaround. Thanks a lot guys!

  • If anyone has doubts, full workaround is not breaking deep links logic, all fine.

  • True answer is a bit hidden and I needed to combine code from few replies, so to not cause more people struggle, here it is:

      [PostProcessBuild(10000)]
      public static void IOSBuildPostProcess(BuildTarget target, string pathToBuiltProject)
      {
      .
      .
          FixUniversalLinksColdStartBugInFacebookSDK(pathToBuiltProject);  // Call this function from your IOSBuildPostProcess 
      .
      .
      }
    
      private static void FixUniversalLinksColdStartBugInFacebookSDK(string path)
      {         
    
          string isBackgroundLaunchOptions = @"(?x)(isBackgroundLaunchOptions:\(NSDictionary\*\)launchOptions(?:.*\n)+?\s*return\ )YES(\;\n\})# }";
          string fullPath = Path.Combine(path, Path.Combine("Classes", "UnityAppController.mm"));
          string data = Load(fullPath);
          data = Regex.Replace(
              data,
              isBackgroundLaunchOptions,
              "$1NO$2");
    
          Save(fullPath, data);
          
          static string Load(string fullPath)
          {
              string data;
              FileInfo projectFileInfo = new FileInfo(fullPath);
              StreamReader fs = projectFileInfo.OpenText();
              data = fs.ReadToEnd();
              fs.Close();
    
              return data;
          }
          
          static void Save(string fullPath, string data)
          {
              System.IO.StreamWriter writer = new System.IO.StreamWriter(fullPath, false);
              writer.Write(data);
              writer.Close();
          }
      }
    

@david-a-diaz
Copy link

In case it helps, in Unity 2022.3.22 (and possibly on other versions) the regex replace is changing both the isBackgroundLaunchOptions method and some of it's uses in the .mm file, to make sure only the method is changed you can use this regex instead:

data = Regex.Replace( data, @"(?x)(\(BOOL\)isBackgroundLaunchOptions.+(?:.*\n)+?\s*return\ )YES(\;\n\})# }", "$1NO$2" );

@gagbaghdas
Copy link

Thanks to @Vitalchek for opening the issue. @sebastian-dudzic-spl and @david-a-diaz for providing the final solution and to all participants for providing your workarounds. ❤️ Community is Power ❤️

@ravichandra2012
Copy link

ravichandra2012 commented Apr 29, 2024

Hello Guys,
I am facing the same issue, I followed the solutions you mentioned above which fixed the crash but the deep link is not being handled properly. Can you please mention what other changes are needed in the UnityAppController.mm file?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests