I have found a solution to Sparkle issue. It took me much longer than I expected and it is kind of funny because in the end it is just one line of code... So here is a little story:
The initial problem was that Sparkle didn't work on Java 1.6. It didn't work because the dynamic library with the native code couldn't be loaded, and it couldn't be loaded because it was not compiled for x86_64 architecture. The library was not compiled for x86_64 because the Sparkle.framework itself did not support 64 bit architecture.
So we decided to update the Sparkle to the latest version which supports x86_64 and in addition has some major security enhancements. Then it turned out that native code in the Sparkle library doesn't work anymore. Sparkle is normally configured via Info.plist in application bundle and I found out that it actually reads the properties correctly, but still does not start the update checking. I have spent a lot of time trying different ways to trigger the update checking, but with no luck.
Then I noticed that if I remove the checkForUpdatesInBackground method call, the update checking initiated from Menu Bar actually works. But it stopped working as soon as the programatic update checks were reintroduced. At that point I had no choice but to start digging the Sparkle source code for clues.
After reading the source code, I found out that Sparkle uses different "drivers" for different update checks. This suggested me that the one that is used for background checks doesn't work correctly and thus needs some modifications. However, it didn't look that different from the "driver" that was used in user initiated update checks and worked perfectly fine.
These small differences between two drivers really puzzled me because they were only related to UI. So I modified the framework to use the driver that is normally used in background checks for user initiated checks. And after that updating worked just fine! At that point it was clear that the drivers themselves work just fine and the problem is in initiating the update checks programatically in the dylib.
The next step was to track down which piece of code fails when the update check is initiated programmatically. It was the creation of NSURLConnection which did not call some delegate methods that indicate the successful creation of the connection and the data downloading. The class reference for NSURLConnection says that "For the connection to work correctly the calling thread’s run loop must be operating in the default run loop mode." I made some stupid things trying to satisfy this condition Then I simply changed the asynchronous loading of data to synchronous and the programmatically initiated update checks finally started to work!
However, after a few runs I got several crashes which were caused by threading issues. Crash reports reminded me Apple technical note TN2147 about JNI programming which I read before. After reading "When you make calls to AppKit that may result in a view refresh or some other event-based action, you must make those calls on the main AppKit thread" I had a big "aha!" moment and understood that all I needed to do was to call the checkForUpdatesInBackground method in the dylib on the main thread and do so asynchronously.
So in the end it is just
[suUpdater performSelectorOnMainThread: @selector(checkForUpdatesInBackground) withObject:nil waitUntilDone:NO]
and no modifications to Sparkle.framework.
To unsubscribe, e-mail: firstname.lastname@example.org
For additional commands, e-mail: email@example.com