libMacSparkle: unofficial dynamic library of Sparkle updater

libMacSparkle.dylib is an unofficial thin wrapper of Sparkle updater framework for macOS in a form of dynamic library. Use the Sparkle updater with any tech stack.

libMacSparkle

Thin wrapper for Sparkle updater for macOS. This library provides a C API for integrating Sparkle’s automatic update functionality into cross-platform applications (e.g., .NET, Rust, Go, etc.) on macOS.

libMacSparkle on GitHub Download Latest libMacSparkle dylib Download Latest libMacSparkle dylib Buy me a coffee

Table of Contents

Overview

libMacSparkle wraps the Sparkle framework to provide a simple C interface for:

  • Setting appcast URL programmatically
  • Initializing the updater
  • Checking for updates manually
  • Configuring automatic update checks
  • Setting and getting update check intervals
  • Retrieving last update check time
  • Managing automatic update preferences
  • Setting HTTP headers for update requests

The API design is inspired by WinSparkle, providing a similar C interface for cross-platform applications.

See changelog for full details.

Quickstart

Step 1: Download Dependencies

  1. Download Sparkle.framework from the official Sparkle website
  2. Download the latest libMacSparkle zip file from latest GitHub Releases

Extract both and place them in your application’s bundle or alongside your executable.

Step 2: Configure Info.plist

Your application’s Info.plist file must include the following entries for Sparkle to function correctly:

Required Entries:

  • CFBundleIdentifier: Your application’s unique bundle identifier (e.g., com.yourcompany.yourapp)
  • CFBundleVersion: The build version (e.g., 100 or 1.0.0)
  • CFBundleShortVersionString: The display version shown to users (e.g., 1.0.0)
  • SUFeedURL: The URL to your appcast feed. Can be overridden using mac_sparkle_set_appcast_url()
  • SUPublicEDKey: Your EdDSA public key for signature verification.

Optional Sparkle Entries:

  • SUEnableAutomaticChecks: Enable/disable automatic update checks (default: YES). Can be overridden using mac_sparkle_set_automatic_check_for_updates()
  • SUUpdateCheckInterval: Update check interval in seconds (default: 86400 for daily). Can be overridden using mac_sparkle_set_update_check_interval()
  • SUAllowsAutomaticUpdates: Allow automatic installation of updates (default: NO)
  • SUAutomaticallyUpdates: Automatically install updates without user interaction (default: NO)
  • SUEnableSystemProfiling: Enable system profiling for anonymous usage data (default: NO)
  • SUSendProfileInfo: Send system profile information with update checks (default: NO)
  • SUShowReleaseNotes: Show release notes when updates are available (default: YES)
  • SUEnableDownloaderService: Use Sparkle’s built-in downloader service (default: YES)
  • SUScheduledCheckInterval: Background scheduled check interval in seconds (default: 86400)

Example Info.plist:

<key>CFBundleIdentifier</key>
<string>com.yourcompany.yourapp</string>
<key>CFBundleVersion</key>
<string>1.0.0</string>
<key>CFBundleShortVersionString</key>
<string>1.0.0</string>

<key>SUFeedURL</key>
<string>https://example.com/updates/appcast.xml</string>
<key>SUPublicEDKey</key>
<string>your-eddsa-public-key-here</string>

<key>SUEnableAutomaticChecks</key>
<true/>
<key>SUUpdateCheckInterval</key>
<integer>86400</integer>

Step 3: Create a Wrapper Class (C# Example)

Create a wrapper class to handle P/Invoke calls and initialization:

using System.Runtime.InteropServices;

internal static class MacSparkleWrapper
{
    private const string LIB = "libMacSparkle.dylib";

    [DllImport(LIB, EntryPoint = "mac_sparkle_set_appcast_url", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_set_appcast_url([MarshalAs(UnmanagedType.LPStr)] string url);

    [DllImport(LIB, EntryPoint = "mac_sparkle_init", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_init();

    [DllImport(LIB, EntryPoint = "mac_sparkle_check_update_with_ui", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_check_update_with_ui();

    [DllImport(LIB, EntryPoint = "mac_sparkle_check_update_without_ui", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_check_update_without_ui();

    [DllImport(LIB, EntryPoint = "mac_sparkle_set_automatic_check_for_updates", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_set_automatic_check_for_updates(int state);

    [DllImport(LIB, EntryPoint = "mac_sparkle_get_automatic_check_for_updates", CallingConvention = CallingConvention.Cdecl)]
    public static extern int mac_sparkle_get_automatic_check_for_updates();

    [DllImport(LIB, EntryPoint = "mac_sparkle_set_update_check_interval", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_set_update_check_interval(int interval);

    [DllImport(LIB, EntryPoint = "mac_sparkle_get_update_check_interval", CallingConvention = CallingConvention.Cdecl)]
    public static extern int mac_sparkle_get_update_check_interval();

    [DllImport(LIB, EntryPoint = "mac_sparkle_get_last_check_time", CallingConvention = CallingConvention.Cdecl)]
    public static extern long mac_sparkle_get_last_check_time();

    [DllImport(LIB, EntryPoint = "mac_sparkle_set_http_header", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
    public static extern void mac_sparkle_set_http_header([MarshalAs(UnmanagedType.LPStr)] string name, [MarshalAs(UnmanagedType.LPStr)] string value);

    [DllImport(LIB, EntryPoint = "mac_sparkle_clear_http_headers", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_clear_http_headers();

    [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
    public delegate void MacSparkleErrorCallback();

    [DllImport(LIB, EntryPoint = "mac_sparkle_set_error_callback", CallingConvention = CallingConvention.Cdecl)]
    public static extern void mac_sparkle_set_error_callback(MacSparkleErrorCallback callback);

    public static void Initialize(string appcastUrl)
    {
        mac_sparkle_set_appcast_url(appcastUrl);
        mac_sparkle_init();
    }

    public static void CheckForUpdates()
    {
        mac_sparkle_check_update_with_ui();
    }
}

Step 4: Initialize on Application Startup

public class App
{
    public static void Main(string[] args)
    {
        try
        {
            MacSparkleWrapper.Initialize("https://example.com/updates/appcast.xml");
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Failed to initialize Sparkle: {ex.Message}");
        }

        // Continue with your application startup...
    }
}

Step 5: Configure Update Settings (Optional)

You can configure automatic update checking and intervals:

public static void SetAutomaticUpdates(bool enabled)
{
    try
    {
        mac_sparkle_set_automatic_check_for_updates(enabled ? 1 : 0);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to set automatic updates: {ex.Message}");
    }
}

public static bool GetAutomaticUpdates()
{
    try
    {
        return mac_sparkle_get_automatic_check_for_updates() == 1;
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to get automatic updates state: {ex.Message}");
    }
    return false;
}

public static void SetUpdateCheckInterval(int seconds)
{
    try
    {
        mac_sparkle_set_update_check_interval(seconds);
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to set update interval: {ex.Message}");
    }
}

public static int GetUpdateCheckInterval()
{
    try
    {
        return mac_sparkle_get_update_check_interval();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to get update interval: {ex.Message}");
    }
    return 86400; // Default 24 hours
}

public static long GetLastCheckTime()
{
    try
    {
        return mac_sparkle_get_last_check_time();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to get last check time: {ex.Message}");
    }
    return -1;
}

Step 6: Check for Updates (Optional)

Add a “Check for Updates” menu item or button:

private void OnCheckForUpdatesClicked(object sender, EventArgs e)
{
    try
    {
        MacSparkleWrapper.CheckForUpdates();
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Failed to check for updates: {ex.Message}");
    }
}

Development

Install dependencies.

swift package resolve

Build the library using the provided build script:

./build.sh

This will generate libMacSparkle.dylib in the .build/universal/release directory.

Public API

The library exposes the following C functions via mac_sparkle.h:

mac_sparkle_set_appcast_url

void mac_sparkle_set_appcast_url(const char* url);

Sets the appcast URL for Sparkle. This allows you to programmatically set the feed URL instead of relying on Info.plist. Must be called before mac_sparkle_init.

mac_sparkle_init

void mac_sparkle_init(void);

Initializes the Sparkle updater. Must be called first time after UI started.

mac_sparkle_check_update_with_ui

void mac_sparkle_check_update_with_ui(void);

Triggers a manual update check with user interface feedback.

mac_sparkle_check_update_without_ui

void mac_sparkle_check_update_without_ui(void);

Triggers an update check in the background without user interface feedback.

Caution: Use this function with caution and generally not recommended. By default Sparkle schedules background checks automatically, and calling this manually may interfere with Sparkle’s scheduler.

mac_sparkle_set_automatic_check_for_updates

void mac_sparkle_set_automatic_check_for_updates(int state);

Sets whether Sparkle should automatically check for updates. Pass 1 for true, 0 for false.

mac_sparkle_get_automatic_check_for_updates

int mac_sparkle_get_automatic_check_for_updates(void);

Gets the current automatic update check state. Returns 1 if enabled, 0 if disabled.

mac_sparkle_set_update_check_interval

void mac_sparkle_set_update_check_interval(int interval);

Sets the update check interval in seconds. The default is 86400 seconds (24 hours).

mac_sparkle_get_update_check_interval

int mac_sparkle_get_update_check_interval(void);

Gets the current update check interval in seconds.

mac_sparkle_get_last_check_time

time_t mac_sparkle_get_last_check_time(void);

Gets the last update check time as a Unix timestamp. Returns -1 if updates have never been checked.

mac_sparkle_set_http_header

void mac_sparkle_set_http_header(const char* name, const char* value);

Sets an HTTP header to be sent with update requests (appcast checks, release note downloads, and update downloads). The header is stored on the updater’s httpHeaders dictionary; calling it again with the same name replaces the previous value. Pass NULL for either argument to ignore the call.

mac_sparkle_clear_http_headers

void mac_sparkle_clear_http_headers(void);

Clears all HTTP headers previously set using mac_sparkle_set_http_header.

mac_sparkle_set_error_callback

typedef void (__cdecl *mac_sparkle_error_callback_t)();

void mac_sparkle_set_error_callback(
  mac_sparkle_error_callback_t callback
);

Sets a callback to be called when the updater encounters an error. The callback is invoked on the main thread with no arguments. Pass NULL to clear the previously set callback. The callback is not invoked for the normal “no update found” outcome or for a user-canceled installation.

Platform Considerations

  • macOS Only: This library only works on macOS.

  • Library Placement: Ensure libMacSparkle.dylib and Sparkle.framework are in your application’s bundle or in a location where the system can find it (e.g., alongside your executable or in @rpath).

Examples

See the examples/dotnet directory for complete working examples:

License

See LICENSE file for details.