NativePHP for Desktop Documentation

repository·main·Indexed 16 days ago

https://github.com/nativephp/desktop

A framework for building native desktop applications using PHP and Electron. It includes tools for managing application lifecycles, process cleanup, deep linking, and auto-updates. The framework provides a specialized Menubar class and Positioner library for creating system tray applications with precise window placement and lifecycle event management.

Tokens
14.3K
Snippets
59
Records
70
Agent score
65%

What's inside NativePHP for Desktop

  1. How NativePHP manages application lifecycle and processes

    main

    NativePHP manages a collection of child processes to ensure the PHP environment and its associated services (like the scheduler) are correctly cleaned up when the Electron application exits.

    Process Cleanup

    When the Electron app receives a before-quit event, NativePHP performs a coordinated shutdown:

    1. Kill Framework Processes: It first stops the framework's own processes (like the PHP server) to prevent new requests from spawning fresh child processes during shutdown.
    2. Stop App Processes: It sends a SIGTERM to the application's child processes, allowing them to perform their own cleanup (flushing data, persisting state).
    3. Graceful Wait: It waits up to 12 seconds for processes to exit naturally before forcing a shutdown.

    Scheduler Lifecycle

    The scheduler runs tasks at minute intervals. It is sensitive to system power states:

    • Suspend: When the system suspends, the scheduler is stopped.
    • Resume: When the system resumes, the scheduler is restarted.

    Security

    To secure communication between the Electron frontend and the PHP backend, NativePHP injects an X-NativePHP-Secret header into all requests sent to the local PHP server (http://127.0.0.1:${state.phpPort}/*).

  2. Configure Deep Linking and Auto-Updates via NativePHP Config

    main

    NativePHP reads configuration from the underlying PHP environment to configure Electron-specific features. The following settings are extracted from the NativePHP configuration:

    • app_id: Used to set the Electron appUserModelId.
    • deeplink_scheme: If provided, NativePHP registers this protocol (e.g., myapp://) with the operating system. It also handles open-url (macOS) and second-instance (Windows/Linux) events to notify the Laravel application of the incoming URL.
    • updater:
      • enabled: Boolean to enable/disable automatic updates.
      • default: The name of the default provider to use.
      • providers: A map of provider configurations. Each provider can have a public_url used to set the autoUpdater feed URL.

    When a deep link is triggered, NativePHP notifies Laravel by dispatching the \Native\Desktop\Events\App\OpenedFromURL event with the URL as the payload.

  3. Configure NativePHP updater providers

    main

    NativePHP uses a configuration-driven approach to manage application updates via different drivers. Providers are defined in your application configuration under the nativephp.updater.providers key. Each provider must specify a driver type.

    Supported drivers identified in the UpdaterManager include:

    • github (via GitHubProvider)
    • s3 (via S3Provider)
    • spaces (via SpacesProvider)

    You can also define a default updater driver using the nativephp.updater.default configuration key.

  4. Configure Menubar application options

    main

    When creating a menubar application, you provide an Options object to define the behavior, appearance, and window properties of the menubar. Key configurations include the window dimensions, the icon used in the system tray, the URL to load, and the positioning of the window relative to the tray.

    Window and URL Configuration

    • browserWindow: An object containing BrowserWindowConstructorOptions (e.g., width, height).
    • dir: The directory containing your application source.
    • index: The URL to load. Defaults to file:// + dir + index.html. Set to false to prevent automatic loading.
    • loadUrlOptions: Options passed directly to Electron's browserWindow.loadURL().

    Appearance and Tray

    • icon: A path to a PNG icon or an Electron.NativeImage. For retina support, provide a 2x sized image with @2x appended to the filename (e.g., icon@2x.png).
    • tooltip: The text displayed when hovering over the menubar tray icon.
    • tray: An optional Electron.Tray instance. If provided, the icon option is ignored.
    • showDockIcon: (macOS only) If false, hides the application dock icon.

    Behavior and Positioning

    • activateWithApp: If true (default), the menubar opens when the app is activated via app.on('activate').
    • preloadWindow: If true, creates the BrowserWindow instance before use to speed up loading at the cost of higher initial resource usage.
    • showOnAllWorkspaces: (macOS) Makes the window available on all OS X workspaces.
    • showOnRightClick: If true, the window shows on a 'right-click' event instead of a regular click.
    • windowPosition: Defines where the window appears relative to the tray or screen corners.
    const options = { height: 640, width: 480 };
    
    const mb = new Menubar({
      browserWindow: options
    });
  5. Troubleshoot bifrost:init errors

    main

    If bifrost:init fails, the command provides specific guidance based on the error encountered:

    • Authentication Failure: If you are not authenticated, run:
      php artisan bifrost:login
    • No Teams Found (403 Error): You must create a team before you can manage projects. Visit the onboarding URL provided in the terminal output.
    • Incomplete Team Setup (422 Error): Your team setup might be incomplete or requires a subscription. Visit your dashboard to complete the setup.
    • General API Errors: If the request fails for other reasons, the command will suggest visiting your dashboard to resolve the issue.
  6. Control the Emoji Panel

    main

    The App class provides methods to interact with the system emoji panel.

    • isEmojiPanelSupported(): Returns a bool indicating if the emoji panel can be displayed on the current platform.
    • showEmojiPanel(): Triggers the display of the emoji panel.
    if ($app->isEmojiPanelSupported()) {
        $app->showEmojiPanel();
    }
  7. Manage the scheduler with runScheduler() and killScheduler()

    main

    The scheduler manages background tasks.

    • runScheduler(): Starts the scheduler process. If a scheduler is already running, it will be killed before a new one starts to prevent multiple instances.
    • killScheduler(): Gracefully terminates the currently running scheduler process if it exists and has not already been killed.
    import { runScheduler, killScheduler } from './server/index.js';
    
    // Start the scheduler
    runScheduler();
    
    // Stop the scheduler
    killScheduler();
  8. Show and hide the Menubar window

    main

    You can manually control the visibility of the menubar window using the following methods:

    • showWindow(trayPos?): Asynchronously shows the window. If trayPos (an Electron.Rectangle) is provided, the window will attempt to position itself relative to those bounds. If not provided, it uses cached bounds or the current tray bounds.
    • hideWindow(): Hides the current window and clears any pending blur timeouts.
    // Manually show the window
    await menubar.showWindow();
    
    // Manually hide the window
    menubar.hideWindow();
  9. Start the PHP application with startPhpApp()

    main

    Use startPhpApp() to launch the PHP application process. This function initializes the app using the current state's random secret, the Electron API port, and PHP INI settings. It also updates the global state with the assigned PHP port and appends necessary cookies. It returns the ChildProcess instance of the running PHP application.

    import { startPhpApp } from './server/index.js';
    
    const phpProcess = await startPhpApp();
    // phpProcess is a ChildProcess instance
  10. Stop, Restart, or Message a child process

    main

    Once a process is running, you can control it using its alias.

    • Stop a process: Use stop(?string $alias = null). If no alias is provided, it stops the process instance the current object represents.
    • Restart a process: Use restart(?string $alias = null). Returns a new ChildProcess instance if successful, or null if it fails.
    • Send a message: Use message(string $message, ?string $alias = null). Sends a string message to the process via its alias.
    // Stop a specific process
    $childProcess->stop('my-alias');
    
    // Restart a specific process
    $newProcess = $childProcess->restart('my-alias');
    
    // Send a message to a process
    $childProcess->message('RELOAD_CONFIG', 'my-alias');