Tutorials on Macos Apps

Learn about Macos Apps from fellow newline community members!

  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL
  • React
  • Angular
  • Vue
  • Svelte
  • NextJS
  • Redux
  • Apollo
  • Storybook
  • D3
  • Testing Library
  • JavaScript
  • TypeScript
  • Node.js
  • Deno
  • Rust
  • Python
  • GraphQL

Converting a React Native for macOS Application into a Menu Bar Application

The status menus (also known as menu bar icons) of a macOS menu bar let users quickly access status information and perform actions without launching an application inside a new, separate window. For example, upon installation, a popular desktop application like Dropbox automatically adds a status menu to the macOS menu bar for monitoring and reporting the status of uploads. With the single click of an icon/title, the status menu toggles open a condensed version of the Dropbox desktop application. You can get the latest uploads and share them immediately without having to change your active window. Status menus helps to maximize your workflow and keep you productive. They run in the background and periodically update with new notifications and content to avoid distracting you while you are focused on completing your work. With so many status bar applications available, you can customize this section of the macOS menu bar and arrange the items in any order to best complement your workflow. However, if you cannot find a status bar application that addresses a specific aspect of your workflow, such as aggregating and displaying relevant information about the status of jobs triggered by a CI build pipeline, then you can build your own status bar application with React Native for macOS . Unlike a desktop application, building a status bar application involves quite a few steps beyond the installation steps listed in the React Native for macOS documentation . Below, I'm going to show you how to convert a React Native for macOS application into a menu bar application. To get started, let's create a new React Native for macOS project from a standard React Native template. Verify that the project was initialized correctly by running it: The status bar application consists of two components: a status item and a popover. A status item is a clickable icon/title that sits in the system menu bar. A popover is a self-contained view that hovers over its surrounding context and displays content within a non-modal dialog. It is anchored to the element responsible for making it appear, which is indicated by the direction of its tooltip arrow. Both of these parts will be implemented in Swift. Unlike a pull-down menu, which simply lists options, the layout of a popover's content is flexible. This content will come directly from the React application whose root component <App /> is registered with AppRegistry inside of the project's index.js file. To transition to Swift, we must first remove the existing Objective-C code from the project. Delete the following files: Even if you delete these files inside of Finder or within your terminal, Xcode still references these from the project navigator. Therefore, open the project inside of Xcode by either... Then, delete those files manually from the project navigator. Keep Xcode opened for the remainder of this tutorial. To add a status bar item and popover into our application, let's first create two new files: Note : The casing of projectname must match the casing of the parent project directory's name. For example, if the project's directory name is rnmacmenubar (despite the project being named rnMacMenubar during initialization via npx react-native init ), then projectname will be rnmacmenubar . The <projectname>-macOS-Bridging-Header.h bridging header file exposes Objective-C libraries to Swift. For this project, the specified libraries provide APIs for integrating React Native into native code and rendering the React Native application within a UIView . ( <projectname>-macOS-Bridging-Header.h ) The AppDelegate.swift file serves as the application's initial entry file and defines a AppDelegate class, which handles application lifecycle events like applicationDidFinishLaunching and how the application responds to these events. ( AppDelegate.swift ) Inside of AppDelegate , define the properties popover and statusBarItem , which will reference the application's popover and status bar item respectively. An additional window property will be defined to reference a "development" window. ( AppDelegate.swift ) Once the application has launched, initialize the React Native application with RCTRootView , which displays the React Native application whose root component <App /> is registered inside of the project's index.js file (development environment) or from the compiled bundle (production build). This base view is embedded within a NSViewController . ( AppDelegate.swift ) Note : #if DEBUG is a pre-processor directive. Code inside of this directive are pre-processed before compilation. In the above code, we initialize the React Native bridge within this directive. Initialize the popover by setting its base dimensions to 700px by 800px and behavior to transient. Enable animation for its dismissal and emergence. Set its content to the NSViewController that has the React application embedded within it. ( AppDelegate.swift ) Initialize the status bar item by allocating 60px (in width) within the macOS status bar for it. Using the button property, we can customize the appearance and behavior of this item. Whenever the status item is clicked, the togglePopover method is called. The status item will be shown in the status bar via the project's name, not a typical icon, to make this example simpler. ( AppDelegate.swift ) The togglePopover dismisses the popover when its opened, and vice-versa. ( AppDelegate.swift ) Note : The @objc attribute marks the method as accessible and executable in Objective-C. The "development" window allows us to iterate upon the React application and immediately see changes without having to open the popover to see changes anytime they occur. Both the window and popover share the same rootViewController to avoid having two separate instances of the application. ( AppDelegate.swift ) Note : Once the popover opens, the window will no longer possess the controller, and the React application will only be rendered in the popover. For development, this is fine. applicationDidFinishLaunching tells the delegate when the application has launched. We will place all of the initialization code within the body of this instance method to execute this code once the application has launched. Altogether... ( AppDelegate.swift ) Note : Replace all instances of <projectName> with your project's name. This is the project name specified during initialization via npx react-native init . Drag and drop the <projectname>-macOS-Bridging-Header.h and AppDelegate.swift files from Finder into Xcode's project navigator (under <projectname>/<projectname>-macOS directory). When presented with the "Choose options for adding these files" modal, accept the default selected options. Inside of Xcode, check that the run destination is "My Mac" in the workspace toolbar. If not, then change the scheme to <projectname>-macOS . This is what the workspace toolbar should display: To avoid Swift linking errors, let's enable dead code stripping by visiting the project's build settings and switching the "Dead Code Stripping" setting to "YES." Now, let's tell Xcode to include Swift standard libraries in the final application bundle. To enable the DEBUG flag only when building and running the application from Xcode, search for the OTHER_SWIFT_FLAGS setting under the "User-Defined" section of the target <projectname>-macOS 's settings. Set the -DDEBUG flag only for the "Debug" mode, not for "Release." Otherwise, when you release the application to users, it will try to connect to the metro packager. If you encounter the following issue: Then resolve it by switching the "Don't Dead-strip Inits and Terms" project setting under the "Linking" section to "Yes" for both "Project" and "Target." To import Objective-C libraries from the Objective-C bridging header file <projectname>-macOS-Bridging-Header.h into Swift code, visit the project's build settings and set the "Objective-C Bridging Header" setting under the "Swift Compiler - General" section to the header file's path. Upon setting this path, SRCROOT and PROJECT_NAME are automatically substituted with their values. To inform the compiler of the AppDelegate.swift source file that must be compiled during the build process, add this source file as a "Compile Source" within the target's "Build Phase" settings. Click on project in project navigator. Clean the project by selecting "Product" from the upper menu and clicking the "Clean Build Folder" option. With the old AppDelegate class deleted (from the deleted AppDelegate.m file), we need to reselect AppDelegate class to ensure the new AppDelegate class (from the AppDelegate.swift file) is selected. Select the Main.storyboard file from the project navigator. Under "Application Scene" in the left-sidebar of the project editor. In the right-sidebar, select the "Attributes Inspector" tab and enter "AppDelegate" as the App Delegate class. Run the application via the shortcut CMD + r . This launches... If you click on the status item labeled with the project's name in the menu bar, a popover pops open and the development window no longer displays the React application. Inside of the popover is the React application. Click on the status item again and the popover is dismissed. The smaller window is an initial window that's automatically launched for the application (in the top-left corner of the above screenshot). The larger window is the development window (in the lower-right corner of the above screenshot). Since the development window shares the same rootViewController , if you resize this window, the content within the popover is also resized. Notice that the dock shows an icon for the application. To omit this icon from the dock when running the application, edit the project's Info.plist file. If you rebuild and rerun the application, then you will notice that the application's icon no longer appears in the dock. To hide the extra, initial (smaller) window, uncheck the "Is initial controller" checkbox in the storyboard's window controller. If you rebuild and rerun the application, then you will notice that this window no longer appears. To generate a release build, run the following command: If you encounter the following error... Then add the EXCLUDED_ARCHS build setting to the command and set it to arm64 . This excludes support for ARM-based simulators. Double-click the release build to verify that the application works properly. Now you can distribute this menu bar application to other macOS users! If you are stuck at any step of this tutorial, feel free to visit the final version of this project here . Try building your next menu bar application with React Native for macOS!

Thumbnail Image of Tutorial Converting a React Native for macOS Application into a Menu Bar Application

Building macOS Applications with React Native for macOS

Did you know Slack 's and Discord 's desktop clients are built with the Electron framework? Using Electron allows developers to bring their web applications to desktop faster without having to rewrite them completely as standalone, native clients that run on multiple operating systems. However, a major downside of building desktop applications with Electron is its high memory consumption and size because it packages the final build with a copy of Chromium, an open-source alternative of the Chrome browser, and Node.js to run an application written with HTML, CSS and JavaScript. At a high level, an Electron application behaves like a Chrome browser and loads and renders an HTML document inside of a window ( BrowserWindow ). To avoid the extra overhead of Chromium and Node.js and make the UI appear consistent with a platform's trademark design by rendering it with native APIs and components, consider using a different framework like React Native for Windows and macOS . Launched in 2019 and forked from Facebook's React Native project, React Native for Windows and macOS is an open source project maintained by Microsoft and allows developers to create Windows and macOS applications with a single React Native codebase. To interact with native APIs, the macOS port uses Objective-C or Swift while the Windows port uses C# or C++/WinRT. React Native for Windows and macOS comes with React components that are transformed into native components of each platform at runtime and can readily be imported from the react-native library. Composing an interface with native components instead of wrapping an entire web application inside of an application shell results in faster and smaller desktop applications. With all the tooling and CLI utilities provided by React Native for Windows and macOS, a developer can easily get started and deliver an application with a solid desktop experience. Below, I'm going to... Like any other piece of technology and library/framework, you need to decide whether React Native for Windows and macOS is appropriate for your particular use case by weighing its upsides against its downsides. Being aware of its strengths and weaknesses ensures our application best meets expectations. Here are several advantages for using React Native for Windows and macOS: Here are several disadvantages for using React Native for Windows and macOS: Remember. By spending a bit of time upfront to pick the best framework for your project, it will save you much more time during development. To get started with React Native for Windows and macOS, initialize a standard React Native project via the react-native init command. Specify the template version to match the latest minor version of React Native for Windows and macOS . Note : projectName cannot contain any spaces or hyphens; it must be alphanumeric and camelcased. Otherwise, the react-native CLI tool prints the following error message: error "<projectName>" is not a valid name for a project. Please use a valid identifier name (alphanumeric). During the initialization of the project, you may be prompted with the following question: CocoaPods (https://cocoapods.org/) is not installed. CocoaPods is necessary for the iOS project to run correctly. Do you want to install it? CocoaPods is a dependency manager for languages (Swift, Objective-C, etc.) that execute inside the Objective-C runtime. Select "Yes, with Homebrew" if you already have Homebrew installed on your machine. Otherwise, select "Yes, with gem (may require sudo)." Note : Make sure Homebrew and packages are up-to-date! Otherwise, you may eventually encounter the following error: dyld: Library not loaded . Inside of the new project, install the macOS-specific packages via the react-native-macos-init command: Note : Install Windows-specific packages via the react-native-windows-init command. This creates a macos directory at the root of the project directory, and it contains the macOS project. Run the macOS application (with hot-reloading) via the react-native run-macos command: Note : Run the Windows application via the react-native run-windows command. This may take some time as it needs to compile all the native code necessary to run the application. In the above screenshot, you may notice an additional terminal window that opens when running the application. This window contains Metro , the React packager. This window must be kept open for the application to work properly during development. If you run into the following error: Then inside of the macos/<projectname>-macOS/ViewController.m file, correct the casing of moduleName , which must follow the same casing as your project's name (camelcased), not lowercased. Anytime you modify the App.js file, watch those changes be automatically reflected in the application! ( App.js ) To build a release (a .app file) for distribution, add the following script to package.json : ( package.json ) Note : projectname is projectName , but lowercased. Here, the build configuration of xcodebuild is set to "Release." Also, the build takes a while to complete. Once completed, the path to the release is printed within the logs. When you double-click on the release, the application opens. Feel free send a copy of the application to other team members to test on their macOS machines. As opposed to Electron applications, React Native for Windows and macOS applications consume less memory and spawn less processes. If you run barebone applications built with these frameworks on the same machine and compared them side-by-side, then you will notice these differences. Here, we will compare three applications: When we run these three applications on the same macOS machine and open Activity Monitor, even though the Electron applications display static content, they each spawn four processes (one main and three helper processes based on Chromium's multi-process architecture ). Altogether, these processes consume more than twice the amount of memory consumed by the single React Native for Windows and macOS application's process. Similarly, if you run the top command, which displays CPU and memory utilization information, inside of a terminal, you will also make the same observation. Space-wise, the application built with React Native for Mac takes up significantly less space on your machine than the applications built with Electron. Download this repository with the source code of these applications to replicate these findings. Try building your next desktop application with React Native for Windows and macOS!

Thumbnail Image of Tutorial Building macOS Applications with React Native for macOS

I got a job offer, thanks in a big part to your teaching. They sent a test as part of the interview process, and this was a huge help to implement my own Node server.

This has been a really good investment!

Advance your career with newline Pro.

Only $30 per month for unlimited access to over 60+ books, guides and courses!

Learn More