KSemenenko / GoogleAnalyticsForXamarinForms

Google Analytics Plugin for Xamarin Forms
https://www.nuget.org/packages/ksemenenko.GoogleAnalytics
MIT License
67 stars 22 forks source link

Crashes when distributing for Xamarin.Mac #37

Open KeithBoynton opened 5 years ago

KeithBoynton commented 5 years ago

Implemented very well into Windows, Xamarin.iOS and Xamarin.Mac and everything is working really well in Debug within Visual Studio.

However when I come to package up and distribute, it crashes on the distributed version with the following stack trace:

Crashed Thread:        0  tid_307  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [497]

Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   com.xxxxx.xxxxxxxxxxx           0x000000010d7b005d eglib_log_adapter + 13 (mono-logger.c:404)
1   com.xxxxx.xxxxxxxxxxx           0x000000010d7ca26e monoeg_g_logv_nofree + 190 (goutput.c:150)
2   com.xxxxx.xxxxxxxxxxx           0x000000010d7ca3ef monoeg_assertion_message + 143 (goutput.c:184)
3   com.xxxxx.xxxxxxxxxxx           0x000000010d5a8a69 mono_jit_thread_attach + 169
4   com.xxxxx.xxxxxxxxxxx           0x000000010d4bd5a0 xamarin_switch_gchandle + 144 (runtime.m:1853)
5   com.xxxxx.xxxxxxxxxxx           0x000000010d4c0217 xamarin_release_trampoline + 103 (trampolines.m:474)
6   libobjc.A.dylib                 0x0000000119a3711a (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 710
7   com.xxxxx.xxxxxxxxxxx           0x000000010d4c79c2 xamarin_main + 1234 (launcher.m:674)
8   com.xxxxx.xxxxxxxxxxx           0x000000010d4c8834 main + 36 (launcher.m:679)
9   libdyld.dylib                   0x000000011a4ec3d5 start + 1

I understand you have listed Xamarin.Mac as "partial" support but I assumed as I've gotten everything running nicely within Visual Studio in Xamarin.Mac I wasn't touching any of the unsupported elements.

I've wrapped it in a static class...

using Plugin.GoogleAnalytics;

namespace Core.Analytics
{
 public static class AppClient
    {
        public static void Initialise()
        {
            GoogleAnalytics.Current.Config.TrackingId = "XXX";
            GoogleAnalytics.Current.Config.AppId = "XXX";
            GoogleAnalytics.Current.Config.AppName = "XXX";
            GoogleAnalytics.Current.Config.AppVersion = "XXX";
            GoogleAnalytics.Current.Config.AppInstallerId = "XXX";
            GoogleAnalytics.Current.Config.StartMessage = "Startup";
            GoogleAnalytics.Current.Tracker.DataSource = "app";

#if __MACOS__
            GoogleAnalytics.Current.Tracker.UserAgentOverride = $"Mozilla/5.0 (Mac OS {Environment.OSVersion.Version.Major}.{Environment.OSVersion.Version.Minor}; Trident/7.0; rv:11.0) like Geko";
#endif

            GoogleAnalytics.Current.InitTracker();
        }
    }
}

And I call it from my app logic....


// Set up analytics
LogWriter.Info ("Setting up analytics");
Analytics.AppClient.Initialise();
LogWriter.Info ("Done");

The Analytics.AppClient.Initialise(); line is where it crashes. The "Setting up analytics" logging gets written but not the "Done" line.

I'm guessing this isn't expected, is there anything special needed to distribute or does that crash indicate anything to you?

KSemenenko commented 5 years ago

Thanks for your feedback, I'm currently working on the .net standard version. I think I can fix it.

KeithBoynton commented 5 years ago

Thanks for your response, it's strange because it's working just fine in the distributed iOS and Windows versions. Is there anything you can suggest as a workaround?

KeithBoynton commented 5 years ago

If I can help progress it in any way then I'd like to help. This has the next release of my app blocked as both the Mac Distribution and Mac App Store versions crash. If you could point me in a direction to look I will be more than happy to try and help out.

KSemenenko commented 5 years ago

@KeithBoynton Hi, can you test it please? https://www.nuget.org/packages/ksemenenko.GoogleAnalytics/1.0.4-pre

KeithBoynton commented 5 years ago

Hi, been away for a few days.. just back.. will test asap

KeithBoynton commented 5 years ago

@KSemenenko Hi again, unfortunately 1.0.4-pre is still crashing for on the distributed xamarin.mac version.

It gives the following trace..

Crashed Thread:        0  tid_307  Dispatch queue: com.apple.main-thread

Exception Type:        EXC_BAD_ACCESS (SIGSEGV)
Exception Codes:       KERN_INVALID_ADDRESS at 0x0000000000000000
Exception Note:        EXC_CORPSE_NOTIFY

Termination Signal:    Segmentation fault: 11
Termination Reason:    Namespace SIGNAL, Code 0xb
Terminating Process:   exc handler [499]

VM Regions Near 0:
--> 
    __TEXT                 0000000101bbb000-0000000101fc8000 [ 4148K] r-x/rwx SM=COW  /Applications/xxxxxxxxxxx.app/Contents/MacOS/xxxxxxxxxxx

Thread 0 Crashed:: tid_307  Dispatch queue: com.apple.main-thread
0   com.xxxxx.xxxxxxxxxxx           0x0000000101edd05d eglib_log_adapter + 13 (mono-logger.c:404)
1   com.xxxxx.xxxxxxxxxxx           0x0000000101ef726e monoeg_g_logv_nofree + 190 (goutput.c:150)
2   com.xxxxx.xxxxxxxxxxx           0x0000000101ef73ef monoeg_assertion_message + 143 (goutput.c:184)
3   com.xxxxx.xxxxxxxxxxx           0x0000000101cd5a69 mono_jit_thread_attach + 169
4   com.xxxxx.xxxxxxxxxxx           0x0000000101bea5a0 xamarin_switch_gchandle + 144 (runtime.m:1853)
5   com.xxxxx.xxxxxxxxxxx           0x0000000101bed217 xamarin_release_trampoline + 103 (trampolines.m:474)
6   libobjc.A.dylib                 0x000000010e1a111a (anonymous namespace)::AutoreleasePoolPage::pop(void*) + 710
7   com.xxxxx.xxxxxxxxxxx           0x0000000101bf49c2 xamarin_main + 1234 (launcher.m:674)
8   com.xxxxx.xxxxxxxxxxx           0x0000000101bf5834 main + 36 (launcher.m:679)
9   libdyld.dylib                   0x000000010ec363d5 start + 1

No code changes since last time and the app logs show me it crashing on the same line.

If there is anything I can do to help please do let me know... any ideas for something for me to investigate?

KeithBoynton commented 5 years ago

Hi @KSemenenko would it be possible for you to give me a steer on what to look at to get this Xamarin.Mac crashing resolved. I'd like to contribute to try and progress this issue as my release path is blocked at the moment because of it.

KSemenenko commented 5 years ago

@KeithBoynton You can try to add the project source code to your project and see what went wrong in the debugger.

KSemenenko commented 5 years ago

Maybe there are some problems with disk access?

DennisWelu commented 5 years ago

Hi @KSemenenko. I'm working with Keith on this issue a bit. I ended up pulling down the repo and tracing through to see what was happening. In a nutshell the Mac implementation is trying to write directly into the app bundle contents. The read and write methods in the DeviceInfo implementation for Mac are here: https://github.com/KSemenenko/GoogleAnalyticsForXamarinForms/blob/master/Plugin.GoogleAnalytics/Plugin.GoogleAnalytics.Mac/DeviceInfo.cs#L117

For these methods, GoogleAnalyticsFolder = "ga-store" and path = "ga-anonymous-id.guid" therefore File.Exists(Path.Combine(GoogleAnalyticsFolder, path)) evaluates to "[AppBundleFolder]/AppPackage/Contents/Resources/ga-store/ga-anonymous-id.guid". While Debug builds can get away with this, Distributed builds cannot write back into the app package to create folders/files.

I modified the methods to do the following, adding a method that uses the SpecialFolders to construct a path to the user's Library folder where application data can be stored. This seemed to work, perhaps something like this could be done instead:

       static string GetFullGaFolder()
        {
            var docsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            var gaFolder = Path.Combine(docsPath, "Library", GoogleAnalyticsFolder);
            return gaFolder;
        }
        public string ReadFile(string path)
        {
            var gaFolder = GetFullGaFolder();

            if (!File.Exists(Path.Combine(gaFolder, path)))
            {
                return string.Empty;
            }

            return File.ReadAllText(Path.Combine(gaFolder, path));
        }

        public void WriteFile(string path, string content)
        {
            var gaFolder = GetFullGaFolder();

            if (!Directory.Exists(gaFolder))
            {
                Directory.CreateDirectory(gaFolder);
            }
            File.WriteAllText(Path.Combine(gaFolder, path), content);
        }

Hopefully that helps! I'm sure @KeithBoynton would be interested in a fix for this ASAP. :)

DennisWelu commented 5 years ago

Just thinking about this a little more...you might consider another segment in that Library path so that multiple applications using the library don't end up writing to the same ga-store folder. Perhaps something with the application name/id in there like Path.Combine(docsPath, "Library", ApplicationNameOrId, GoogleAnalyticsFolder)

KSemenenko commented 5 years ago

@DennisWelu I don't really understand macOS, but is this not an isolated storage?

DennisWelu commented 5 years ago

I'm no Mac expert, but I believe writing back to the app bundle, which is just a zip file essentially, messes up the digital signature (https://stackoverflow.com/a/23803875/1735721) that is applied for any kind of distribution build.

There are various options for storing data depending on what type of data you are storing...user data vs app data, backed up to iCloud vs not, whether the app is sandboxed or not (https://apple.stackexchange.com/a/28930).

Sandboxed apps on Mac have a lot of rules and things to do to get them set up (https://developer.apple.com/library/archive/documentation/Security/Conceptual/AppSandboxDesignGuide/AppSandboxInDepth/AppSandboxInDepth.html#//apple_ref/doc/uid/TP40011183-CH3-SW6).

In fact I just thought to check and the app in question here is actually writing other similarly cached and internal use files to ".../Library/Containers/[InternalAppId]/Data/Caches/[Subfolder]". So it would be really nice to be able to configure it to use that Caches folder and maybe the "ga-store" folder is created under there... Not sure the best way to make that happen with the library you have. I see there are various pieces of config that you can configure like the app name and id, so maybe something from the config could be substituted into that path construction to get the appropriate container folder location?

KeithBoynton commented 5 years ago

Thank you so much for your help @DennisWelu @KSemenenko I'm going to do some testing based on Dennis' findings then when I understand it a little more and am confident it's writing into a place that is going to be workable for the AppStore version I'll submit it to the Mac AppStore for review and let you know the outcome.

Did you have any thoughts on how you want to handle the location of where it writes it's internal files in the Mac version?

KeithBoynton commented 5 years ago

@KSemenenko I can confirm this is now working in both the Xamarin.Mac Distribution and AppStore versions.

KeithBoynton commented 5 years ago

@KSemenenko do you want the fix merging into your codebase or do you have things you'd like to change first?

KSemenenko commented 5 years ago

@KeithBoynton I will be very grateful if you create PR. then I will release a new version with .net standard

KeithBoynton commented 5 years ago

Happy to do that, I had created a branch to make the change but can't push it remotely before making a PR, do I need some other permissions?

KSemenenko commented 5 years ago

@KeithBoynton There are two ways, the first via github:

  1. do you fork
  2. create a branch in your fork, commit changes there
  3. open the country of my repository
  4. you have the option to create a PR

or just archive the project and attach the archive here

KeithBoynton commented 5 years ago

@KSemenenko It's a really simple change.. probably much easier to just attach the updated file here...

Plugin.GoogleAnalytics/Plugin.GoogleAnalytics.Mac/DeviceInfo.cs DeviceInfo.zip