Flutter Desktop Single-Instance Applications

May 13, 2025

Werner Scholtz

void main(List<String> args) async {
	WidgetsFlutterBinding.ensureInitialized();
  	// Initialize the window manager to control the app window
	await windowManager.ensureInitialized();

	 // Enforce single-instance behavior based on the platform
	if (Platform.isLinux || Platform.isMacOS) {
	  if (!await unixSingleInstance(args, _onSecondInstance)) exit(0);
	} else if (Platform.isWindows) {
	  await WindowsSingleInstance.ensureSingleInstance(
		  args,
		  "custom_identifier",
		  onSecondWindow: _onSecondInstance,
	  );
	}

  runApp(const MyApp());
}

// Handle what happens when a second instance is launched
void _onSecondInstance(List<dynamic> decodedArgs) async {
  windowManager.waitUntilReadyToShow(null, () async {
    await windowManager.show();
    await windowManager.focus();
  });
}
MyApplication* my_application_new() {
  return MY_APPLICATION(
	g_object_new(
		my_application_get_type(), 
		"application-id", APPLICATION_ID,
		// "flags", G_APPLICATION_NON_UNIQUE,
    	nullptr)
	);
}
// Implements GApplication::activate.
static void my_application_activate(GApplication* application) {
    MyApplication* self = MY_APPLICATION(application);

    GList* list = gtk_application_get_windows(
GTK_APPLICATION(application));

    GtkWindow* existing_window = list ? GTK_WINDOW(list->data) : NULL;

    if (existing_window) {
        gtk_window_present(existing_window);
    } else {
        // ...
		// Generated flutter code
		// ...
    }
}
#define APP_MUTEX_NAME L"Global\\MyUniqueFlutterAppMutex"

int APIENTRY wWinMain(...) {
	HANDLE hMutex = CreateMutex(NULL, TRUE, APP_MUTEX_NAME);
	if (GetLastError() == ERROR_ALREADY_EXISTS) {
    	// App is already running.
	}

	...
}
HWND hwnd = FindWindow(NULL, APP_WINDOW_NAME);
if (hwnd) {
    ShowWindow(hwnd, SW_RESTORE);
    SetForegroundWindow(hwnd);
}
return 0;
#define APP_WINDOW_NAME L"unique_title"

if (!window.Create(APP_WINDOW_NAME, origin, size)) {
    return EXIT_FAILURE;
}
if (hMutex) {
    ReleaseMutex(hMutex);
}
override func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows flag: Bool) -> Bool {
  if !flag {
      sender.windows.forEach { $0.makeKeyAndOrderFront(self) }
  }
  return true
}
override func applicationDidFinishLaunching(_ notification: Notification) {
  super.applicationDidFinishLaunching(notification)

  let appBundleIdentifier = Bundle.main.bundleIdentifier!

  let runningApps = NSRunningApplication.runningApplications(withBundleIdentifier: appBundleIdentifier)
  if runningApps.count > 1 {
      // App is already running, activate the existing instance
      runningApps.first?.activate(options: .activateIgnoringOtherApps)
      NSApp.terminate(nil)
  }
}

1 comment on "Flutter Desktop Single-Instance Applications"

Sravdar

May 14, 2025, 5:48 AM

Thanks for the article. Nice to see clear examples of how to handle single instance apps in Flutter desktop. It’s a niche topic but definitely useful for certain use cases.

Reply to Sravdar

Your Email address will not be published

Leave a Comment

Your Email address will not be published