<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matt Catalfamo</title>
    <description>The latest articles on DEV Community by Matt Catalfamo (@matt_catalfamo).</description>
    <link>https://dev.to/matt_catalfamo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F94280%2F6b1822f1-1a9c-479b-ad56-3681f6f69b69.jpg</url>
      <title>DEV Community: Matt Catalfamo</title>
      <link>https://dev.to/matt_catalfamo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matt_catalfamo"/>
    <language>en</language>
    <item>
      <title>Bedrock</title>
      <dc:creator>Matt Catalfamo</dc:creator>
      <pubDate>Sun, 16 Feb 2025 15:37:00 +0000</pubDate>
      <link>https://dev.to/matt_catalfamo/bedrock-39de</link>
      <guid>https://dev.to/matt_catalfamo/bedrock-39de</guid>
      <description></description>
    </item>
    <item>
      <title>How to Build and Manually Sign an iOS App with Fastlane</title>
      <dc:creator>Matt Catalfamo</dc:creator>
      <pubDate>Mon, 11 May 2020 04:48:34 +0000</pubDate>
      <link>https://dev.to/matt_catalfamo/how-to-build-and-manually-sign-an-ios-app-with-fastlane-2256</link>
      <guid>https://dev.to/matt_catalfamo/how-to-build-and-manually-sign-an-ios-app-with-fastlane-2256</guid>
      <description>&lt;p&gt;This post will cover how to build and manually code sign an iOS app with Fastlane. Why would you need to do this? If you want/need to distribute an app to different Apple App Store accounts. For example if you have an Enterprise App Store account and want/need to sign the QA build of your app with the enterprise account to distribute internally and then sign the Release build with a normal/publicly available account to distribute to the public.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to build an iOS app using &lt;a href="https://fastlane.tools"&gt;Fastlane&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;How to manually code sign your iOS app using Fastlane &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prerequisites:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Knowledge of iOS build process&lt;/li&gt;
&lt;li&gt;Knowledge of iOS code signing process&lt;/li&gt;
&lt;li&gt;Basic understanding of Fastlane&lt;/li&gt;
&lt;li&gt;Install Fastlane following their &lt;a href="https://docs.fastlane.tools/getting-started/ios/setup/"&gt;recommended setup&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Assumptions:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are building your app on a macOS image that doesn't have your signing certificates or provisioning profiles installed.&lt;/li&gt;
&lt;li&gt;You have password encrypted signing certificate downloaded to directory on your build machine&lt;/li&gt;
&lt;li&gt;You have a mobile provisioning profile downloaded to a directory on your build machine
&lt;/li&gt;
&lt;li&gt;Automatic code signing is disabled in your Xcode project&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the record, I would recommend if you have a simple iOS project that you use &lt;a href="https://docs.fastlane.tools/actions/match/"&gt;Fastlane match&lt;/a&gt; and Xcode automatic code signing. But sometimes in the real world there are restrictions and external reasons to have to do manual code signing, so we will go through the process of building and signing manually. Here is the process.&lt;/p&gt;

&lt;h1&gt;
  
  
  Lets get started
&lt;/h1&gt;

&lt;p&gt;Create a new Fastfile, this can be done by using Fastlane's cli tool&lt;br&gt;
&lt;code&gt;fastlane init&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This creates a Fastlane directory with a Fastfile.&lt;/p&gt;

&lt;p&gt;Your fastfile will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;default_platform(:ios)

platform :ios do
  desc "Description of what the lane does"
  lane :custom_lane do
    # add actions here: https://docs.fastlane.tools/actions
  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I am going to rename the default lane that was created to "build" and I will add the command line options array &lt;code&gt;|options|&lt;/code&gt; so we can have access to that later on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;platform :ios do
  desc "Build app"
  lane :build do |options|

  end
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that the setup is done we can continue on. First we need to create a new keychain, second install our provisioning profiles, and lastly import the certificates.&lt;/p&gt;

&lt;p&gt;Since we may have different profiles or certificates for different builds of our app, let's create a function called &lt;code&gt;setupCodeSigning&lt;/code&gt;. The function will take 4 parameters- keychainPassword, certificatePassword, profilePath, and certificatePath.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;keychainPassword&lt;/strong&gt;: Made up password to set for your keychain you are creating on the Mac you are building your iOS app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;certificatePassword&lt;/strong&gt;: The certificate password you used to encrypt your signing certificate&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;profilePath&lt;/strong&gt;: Path to the provisioning profile (ie: ./dependencies/profile-release.mobileprovision) on your build machine&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;certificatePath&lt;/strong&gt;: Path to the certificate (ie: ./dependencies/certificate.p12)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def setupCodeSigning(keychainPassword, certificatePassword, profilePath, certificatePath)

end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now let's create the keychain. We can use the &lt;a href="https://docs.fastlane.tools/actions/create_keychain/"&gt;create_keychain&lt;/a&gt; plugin.&lt;/p&gt;

&lt;p&gt;Make sure you set a name for the keychain because we will reference it when importing the certificates. If your use case needs other parameters, refer to the create_keychain plugin documentation for more details.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def setupCodeSigning(keychainPassword, certificatePassword, profilePath, certificatePath)
  create_keychain(
    name: "CI",
    password: keychainPassword,
    default_keychain: true,
    unlock: true,
    timeout: 3600,
    lock_when_sleeps: false
  )
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that we have the keychain created we need to install the provisioning profile(s). We can use the &lt;a href="http://docs.fastlane.tools/actions/install_provisioning_profile/#install_provisioning_profile"&gt;install_provisioning_profile&lt;/a&gt; plugin. Be sure to pass the &lt;em&gt;profilePath&lt;/em&gt; parameter as the &lt;em&gt;path&lt;/em&gt; variable to the plugin.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def setupCodeSigning(keychainPassword, certificatePassword, profilePath, certificatePath)
  create_keychain(
    name: "CI",
    password: keychainPassword,
    default_keychain: true,
    unlock: true,
    timeout: 3600,
    lock_when_sleeps: false
  )
  install_provisioning_profile(path: profilePath)
end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Last, import the certificate(s) to the keychain by passing the certificate path, keychain name that we called our keychain, and the password we made up for the keychain.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;setupCodeSigning&lt;/em&gt; function should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def setupCodeSigning(keychainPassword, certificatePassword, profilePath, certificatePath)
  create_keychain(
    name: "CI",
    password: keychainPassword,
    default_keychain: true,
    unlock: true,
    timeout: 3600,
    lock_when_sleeps: false
  )
  install_provisioning_profile(path: profilePath)
  import_certificate(
    certificate_path: certificatePath,
    certificate_password: certificatePassword,
    keychain_name: "CI",
    keychain_password: keychainPassword
  )
end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now that the hard part is over we can call the &lt;em&gt;setupCodeSigning&lt;/em&gt; function in the build lane before we build the app.  The build lane will now look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;lane :build do |options|
    begin
      setupCodeSigning(ENV["MATCH_PASSWORD"], ENV["CERTIFICATE_PASSWORD"], './path-to-your-profile/your-profile.mobileprovision', './path-to-your-certificate/certificate.p12')

      cocoapods(clean_install: true, use_bundle_exec: false, error_callback: true)

      build_app(
        scheme: "your-scheme", 
        configuration: 'Release'
      )

      upload_to_testflight(
        username: options[:appStoreEmail],
        skip_waiting_for_build_processing: true,
        skip_submission: true)

    rescue =&amp;gt; exception
      on_error(options[:slackUrl], "Build Failed", "#slack-channel", exception)
    end
  end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Optional: I like to add a "begin, rescue" block around the build to catch any errors and send them to a slack channel if anything fails for convenience. &lt;a href="http://docs.fastlane.tools/actions/slack/#slack"&gt;slack plugin&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our complete fast file should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;platform :ios do
  desc "Build app"
  lane :build do |options|
    begin
      setupCodeSigning(ENV["KEYCHAIN_PASSWORD"], ENV["CERTIFICATE_PASSWORD"], './path-to-your-profile/your-profile.mobileprovision', './path-to-your-certificate/certificate.p12')

      cocoapods(clean_install: true, use_bundle_exec: false, error_callback: true)

      build_app(
        scheme: "your-scheme", 
        configuration: 'Release'
      )

      upload_to_testflight(
        username: options[:appStoreEmail],
        skip_waiting_for_build_processing: true,
        skip_submission: true)

    rescue =&amp;gt; exception
      on_error(options[:slackUrl], "Build Failed", "#slack-channel", exception)
    end
  end
end


def setupCodeSigning(keychainPassword, certificatePassword, profilePath, certificatePath)
  create_keychain(
    name: "CI",
    password: keychainPassword,
    default_keychain: true,
    unlock: true,
    timeout: 3600,
    lock_when_sleeps: false
  )
  install_provisioning_profile(path: profilePath)
  import_certificate(
    certificate_path: certificatePath,
    certificate_password: certificatePassword,
    keychain_name: "CI",
    keychain_password: keychainPassword
  )
end

def on_error(slackUrl, message, channel, exception)
  slack(
    slack_url: slackUrl,
    channel: channel,
    message: "iOS App :appleinc: " + message,
    success: false,
    payload: {},
    default_payloads: [],
    attachment_properties: { # Optional, lets you specify any other properties available for attachments in the slack API (see https://api.slack.com/docs/attachments).
      color: "#FC100D",
      fields: [
        {
          title: "Error",
          value: exception.to_s,
        },
      ]
    }
  )

  raise exception
end

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>fastlane</category>
      <category>ios</category>
      <category>codesign</category>
      <category>manual</category>
    </item>
    <item>
      <title>Runtime Configurations with React</title>
      <dc:creator>Matt Catalfamo</dc:creator>
      <pubDate>Thu, 10 Oct 2019 02:55:04 +0000</pubDate>
      <link>https://dev.to/matt_catalfamo/runtime-configurations-with-react-22dl</link>
      <guid>https://dev.to/matt_catalfamo/runtime-configurations-with-react-22dl</guid>
      <description>&lt;p&gt;Most of the time using custom &lt;a href="https://create-react-app.dev/docs/adding-custom-environment-variables"&gt;build time environment variables&lt;/a&gt; are suitable but runtime variables can be valuable in addition to or in place of environment variables.&lt;/p&gt;

&lt;p&gt;Runtime configurations or variables, can be beneficial when you need to change a configuration at run time. Some examples of variables you could load at runtime is theme data or api urls.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Do not store any secrets (such as private API keys) in your environment or runtime variables!&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why runtime variables?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Build app only once and deploy the same build to multiple environments (i.e. dev, qa, prod) &lt;/li&gt;
&lt;li&gt;Configurations can be changed/updated after the app is deployed&lt;/li&gt;
&lt;li&gt;Load configurations from an external source&lt;/li&gt;
&lt;li&gt;Save time - Build pipelines can take long periods of time some with many steps (i.e. infrastructure steps, build steps, tests, etc). Loading configurations during runtime can help reduce the amount of times your app is built.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How do runtime variables work?
&lt;/h3&gt;

&lt;p&gt;Runtime variables get loaded into the browser's window object when the index.html of a single page application gets loaded.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; of the html file we can run a Javascript snippet that sets up the configurations on the window object.&lt;/p&gt;

&lt;p&gt;Javascript code in the index.html file will get loaded synchronously from top to bottom as long as the &lt;code&gt;async&lt;/code&gt; flag is not present. By placing the code to load our snippet before the main bundle it can be guaranteed that the values will be set on the window object and accessible when your main javascript bundle is loaded.&lt;/p&gt;

&lt;p&gt;Let’s look at how this can be accomplished.&lt;/p&gt;

&lt;p&gt;Create a new file called runtime-config.js and setup some variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// runtime-config.js
window['runConfig'] = {
    apiUrl: 'test.com/api'
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;To load the script in the index.html file add the script tag to the file inside either the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;body&amp;gt;&lt;/code&gt; tag. If you are starting with Create React App the file will be located at &lt;code&gt;&amp;lt;project_root&amp;gt;/public/index.html&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;script src="%PUBLIC_URL%/runtime-config.js"&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;// index.html
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"utf-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1, shrink-to-fit=no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#000000"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"manifest"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"%PUBLIC_URL%/manifest.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"shortcut icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"%PUBLIC_URL%/favicon.ico"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="c"&gt;&amp;lt;!-- runtime config --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"%PUBLIC_URL%/runtime-config.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- runtime config --&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;React App&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;noscript&amp;gt;&lt;/span&gt;
      You need to enable JavaScript to run this app.
    &lt;span class="nt"&gt;&amp;lt;/noscript&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"root"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  How to use in a React component
&lt;/h3&gt;

&lt;p&gt;To access the variables that are setup in the runtime-config file, from your app files you can reference the window object. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;window['runConfig']&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example usage in a React component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export const MyComponent = () =&amp;gt; {
  const { apiUrl } = window['runConfig'];
  return (
    &amp;lt;div&amp;gt;Runtime config apiUrl: {apiUrl}&amp;lt;/div&amp;gt;
  )
}


&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;p&gt;Full Example: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/mattcat10/react-runtime-config"&gt;https://github.com/mattcat10/react-runtime-config&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Don't use runtime configurations if your configurations are really large. They are loaded synchronously and could slow down your initial load time of your app &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This post explains how to use runtime configurations in a react app, but the same concept can be applied to any SPA framework.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>react</category>
      <category>spaconfig</category>
      <category>runtime</category>
      <category>configurations</category>
    </item>
  </channel>
</rss>
