<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Cristian Gutu</title>
    <description>I&apos;m making apps, end-to-end, from paper to production, pixel perfect, all-in, ready to go.</description>
    <link>https://www.cristiangutu.pro/</link>
    <atom:link href="https://www.cristiangutu.pro/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Fri, 30 Oct 2026 20:19:55 +0000</pubDate>
    <lastBuildDate>Fri, 30 Oct 2026 20:19:55 +0000</lastBuildDate>
    <generator>Jekyll v4.3.2</generator>
    
      <item>
        <title>react-native-get-random-values for the New Architecture</title>
        <description>&lt;p&gt;When working with cryptographic operations in JavaScript, especially in libraries like &lt;code&gt;@aws-amplify/react-native&lt;/code&gt;, access to a secure random number generator is essential. In browsers, the &lt;code&gt;crypto.getRandomValues()&lt;/code&gt; method is typically used for this purpose. On React Native, we have been using &lt;code&gt;react-native-get-random-values&lt;/code&gt;, but this is no longer compatible with the new architecture.&lt;/p&gt;

&lt;h3 id=&quot;new-architecture-replacement&quot;&gt;New Architecture Replacement&lt;/h3&gt;

&lt;p&gt;A good replacement is &lt;a href=&quot;https://github.com/kore-koi/react-native-get-random-values&quot;&gt;react-native-get-random-values&lt;/a&gt;, this one requires &lt;code&gt;react-native-nitro-modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This library is great but it’s not compatible with React Native 0.76 or newer. Here is a fork to address this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/cristiangu/react-native-get-random-values&quot;&gt;https://github.com/cristiangu/react-native-get-random-values&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;use-the-old-library-name&quot;&gt;Use the old library name&lt;/h3&gt;

&lt;p&gt;This new library has a different name and libs like AWS Amplify will break if the old name is not present. Take a look at &lt;a href=&quot;https://github.com/aws-amplify/amplify-js/blob/main/packages/react-native/src/moduleLoaders/loadGetRandomValues.ts&quot;&gt;how Amplify loads it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You should add it into your &lt;code&gt;package.json&lt;/code&gt; like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; &quot;react-native-get-random-values&quot;: &quot;https://github.com/cristiangu/react-native-get-random-values.git&quot;,
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;how-to-use-it&quot;&gt;How to use it&lt;/h3&gt;

&lt;p&gt;The polyfill needs to be applied at import time, you can import it in &lt;code&gt;index.js&lt;/code&gt; and before importing the AWS Amplify lib.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// index.js

// Enables native support for crypto.getRandomValues()
import &apos;react-native-get-random-values&apos;;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;

&lt;p&gt;If you’re upgrading to React Native 0.76+, want to use the New Architecture and rely on AWS Amplify or similar libraries, be sure to update your implementation of &lt;code&gt;react-native-get-random-values&lt;/code&gt;.&lt;/p&gt;

</description>
        <pubDate>Sat, 02 Aug 2025 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/react-native-random-values-polyfill/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/react-native-random-values-polyfill/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>Cut React Native Build Times by 75% with Artifact Caching</title>
        <description>&lt;p&gt;Reducing your build times is achievable by recycling your native build artifacts. In this guide, I will walk you through the steps required to implement this process effectively.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/circleci-faster-build-times.png&amp;amp;w=960&quot; alt=&quot;assets/images/circleci-faster-build-times.png&quot; width=&quot;966&quot; height=&quot;150&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/circleci-faster-build-times.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/circleci-faster-build-times.png&amp;amp;w=960 960w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;the-native-builds-are-expensive&quot;&gt;The native builds are expensive&lt;/h3&gt;

&lt;p&gt;Every time you trigger the CI to create a new build, it will create new IPA and APK files. This can take a lot of time, depending on your project size. These builds will contain the latest JS bundle. Most of the time, you don’t change native code, so why not keep the previous IPA/APK and just replace the new JS bundle?&lt;/p&gt;

&lt;h3 id=&quot;when-to-go-native&quot;&gt;When to go native&lt;/h3&gt;

&lt;p&gt;In this article we will use CircleCI and Fastlane to do the job, most of the code is shell based, so this can be adjusted to any other CI service.&lt;/p&gt;

&lt;p&gt;The first step is to know when a new native build is required, we will run a &lt;code&gt;git diff&lt;/code&gt; and here are the paths and files to check:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;No cached IPA/APK found - this means that even if our diff contains JS code only, we cannot recycle a non-existent native build.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/ios&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/android&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/src/assets&lt;/code&gt;, in theory this could also be recycled, but we will keep it simple for now.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/.env*&lt;/code&gt;. Depending on the env lib that you use, these env variables can be used inside native code.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/patches&lt;/code&gt;, if you’re using &lt;code&gt;patch-package&lt;/code&gt;, you’re probably patching native code.&lt;/li&gt;
  &lt;li&gt;Any change in &lt;code&gt;/yarn.lock&lt;/code&gt;, this one is useful to trigger Android builds, on iOS we already know if a native dependency was changed because the &lt;code&gt;/ios/Podfile.lock&lt;/code&gt; will be changed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The order of these checks is important here.&lt;/p&gt;

&lt;p&gt;Here is the CircleCI command for this:&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;d8e24f88f580519238d681cb09def782&quot; data-gist-line=&quot;53-139&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and it can be used like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;steps:
    - is-native-build-required:
        platform: android
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;save-and-restore-a-cached-ipaapk&quot;&gt;Save and restore a cached IPA/APK&lt;/h3&gt;

&lt;p&gt;Here are four important things that we need here:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Cache the IPA/APK after a native build was finished.&lt;/li&gt;
  &lt;li&gt;Store the build in a different location for each environment and platform.&lt;/li&gt;
  &lt;li&gt;Have a way to manually reset this cache.&lt;/li&gt;
  &lt;li&gt;Use the latest cached build for a specific platform (iOS/Android) and for a specific environment (dev/staging/prod).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CircleCI doesn’t have the best tool for this job, but something close enough, is to use the &lt;code&gt;save_cache&lt;/code&gt; and &lt;code&gt;restore_cache&lt;/code&gt; commands.&lt;/p&gt;

&lt;p&gt;Here is how to do this for the Android builds:&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;d8e24f88f580519238d681cb09def782&quot; data-gist-line=&quot;36-47&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This command has one param, &lt;code&gt;env&lt;/code&gt;, to know for which environment we save the APK.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;key&lt;/code&gt; param from the &lt;code&gt;save_cache&lt;/code&gt; is constructed using:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;env&lt;/code&gt; - a variable to know for which environment we store.&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;v1&lt;/code&gt; - a hard coded string, to be able to manually reset the cache by changing it to v2, v3, […]&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;pipeline.git.revision&lt;/code&gt; - the git SHA that is being built. This is added automatically by CircleCI, it may have a different name on other CI services. We want this to make sure we use the latest cached build, even if it’s a recycled one. Ideally, we would recycle only the native builds and ignore the recycled ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;paths&lt;/code&gt; param is used to tell CircleCI where is the file/dir that we need to cache, here you can specify multiple paths if you output multiple APKs.&lt;/p&gt;

&lt;p&gt;The next step is to restore this cache when needed, we will use this command:&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;d8e24f88f580519238d681cb09def782&quot; data-gist-line=&quot;26-35&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Really similar to the previous command except the &lt;code&gt;key&lt;/code&gt; param from &lt;code&gt;restore_cache&lt;/code&gt;. We don’t add the last part. CircleCI  will choose the latest cache entry that matches the first parts of the key.&lt;/p&gt;

&lt;p&gt;The iOS part is really similar to this one, you can see it &lt;a href=&quot;https://gist.github.com/cristiangu/d8e24f88f580519238d681cb09def782#file-config-yml-L4-L25&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;restore-android-apk-cache&lt;/code&gt;, &lt;code&gt;restore-ios-ipa-cache&lt;/code&gt; must be called before &lt;code&gt;is-native-build-required&lt;/code&gt; and &lt;code&gt;save-android-apk-cache&lt;/code&gt;, &lt;code&gt;save-ios-ipa-cache&lt;/code&gt; must be called after the build part is finished.&lt;/p&gt;

&lt;h3 id=&quot;have-the-new-version-and-build-number-ready&quot;&gt;Have the new version and build number ready&lt;/h3&gt;

&lt;p&gt;Before refreshing the APK/IPA files, we need to know the next version and build number, depending on your setup this may vary but a good practice for React Native projects is to use the &lt;code&gt;version&lt;/code&gt; field from &lt;code&gt;package.json&lt;/code&gt;. Let’s define a new command in CircleCI to read this and keep it in an env variable.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;d8e24f88f580519238d681cb09def782&quot; data-gist-line=&quot;48-52&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The build number should be fetched from Firebase/TestFlight/AppStore Connect/Google Play and incremented or updated as you wish, this will not be covered here. Fastlane has a lot of tools for this:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.fastlane.tools/actions/latest_testflight_build_number/#latest_testflight_build_number&quot;&gt;latest_testflight_build_number&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/firebase/fastlane-plugin-firebase_app_distribution/blob/master/lib/fastlane/plugin/firebase_app_distribution/actions/firebase_app_distribution_get_latest_release.rb&quot;&gt;firebase_app_distribution_get_latest_release&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.fastlane.tools/actions/google_play_track_version_codes/#google_play_track_version_codes&quot;&gt;google_play_track_version_codes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;refresh-the-recycled-apk-file&quot;&gt;Refresh the recycled APK file&lt;/h3&gt;

&lt;p&gt;Having the cached builds ready to be used and the flag env variables (&lt;code&gt;NATIVE_ANDROID_BUILD_REQUIRED&lt;/code&gt;, &lt;code&gt;NATIVE_IOS_BUILD_REQUIRED&lt;/code&gt;) to know when to use them, we can start on Android and refresh the APK file with the new JS bundle.&lt;/p&gt;

&lt;p&gt;This implementation may vary from project to project but here is what we want:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Unarchive the APK file using &lt;code&gt;apktool&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Delete the old JS bundle from there.&lt;/li&gt;
  &lt;li&gt;Create a new un-minified JS bundle using the current source files.&lt;/li&gt;
  &lt;li&gt;Compile the JS bundle to bytecode (if you’re using Hermes).&lt;/li&gt;
  &lt;li&gt;Copy the new JS bundle inside the APK dir.&lt;/li&gt;
  &lt;li&gt;Update APK’s build number and version.&lt;/li&gt;
  &lt;li&gt;Zip back the APK dir.&lt;/li&gt;
  &lt;li&gt;Sign the APK file.&lt;/li&gt;
  &lt;li&gt;Move it back in the cached path defined in the &lt;code&gt;save_cache&lt;/code&gt; command, so CircleCI will be able to find it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This time, we will do it inside &lt;code&gt;Fastfile&lt;/code&gt;, but this is basically a shell script so feel free to adjust it for your project.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# [...]

new_build_number = latest_release[:buildVersion].to_i + 1
if ENV[&quot;NATIVE_ANDROID_BUILD_REQUIRED&quot;] == &quot;true&quot;
    # Do your regular fastlane steps
    # [...]
else 
    UI.message(&quot;Skipping native Android build&quot;)
    refresh_apk_js_bundle(
        build_number: new_build_number.to_s
    )
    # Distribute the new build, the path is &quot;./mobile_app.apk&quot;
end

# [...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;refresh_apk_js_bundle&lt;/code&gt; action can be defined in the same directory as your Fastfile, &lt;code&gt;actions/refresh_apk_js_bundle.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This fastlane action will use &lt;code&gt;wget&lt;/code&gt;, &lt;code&gt;yq&lt;/code&gt;, &lt;code&gt;apktool&lt;/code&gt; and &lt;code&gt;bundletool&lt;/code&gt;, if your CI machine does not contain these, you can install them by creating a new file inside the &lt;code&gt;fastlane&lt;/code&gt; dir, &lt;code&gt;install-tools-android.sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;573fc71c79203cf027cef5ed42a5e11e&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now having these tools ready, we can refresh the APK file. In the first part we call the &lt;code&gt;install-tools-android.sh&lt;/code&gt; script, use &lt;code&gt;apktool&lt;/code&gt; to unzip the APK file and delete the old JS bundle file.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;287212f0e0abbb5cba479824bf4508ab&quot; data-gist-line=&quot;10-21&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the next part we create a new JS bundle, compile it to bytecode using Hermes and copy the new bundle inside the APK dir.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;287212f0e0abbb5cba479824bf4508ab&quot; data-gist-line=&quot;23-43&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The last steps are to upload the new source maps to your favorite crash reporting service, set the new version and build number inside &lt;code&gt;apktool.yml&lt;/code&gt;, create the new APK and sign it.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;287212f0e0abbb5cba479824bf4508ab&quot; data-gist-line=&quot;45-71&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Complete source for the &lt;code&gt;refresh_apk_js_bundle.rb&lt;/code&gt; can be found &lt;a href=&quot;https://gist.github.com/cristiangu/287212f0e0abbb5cba479824bf4508ab&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;refresh-the-recycled-ipa-file&quot;&gt;Refresh the recycled IPA file&lt;/h3&gt;

&lt;p&gt;The iOS part is similar to the Android one, first we unzip the IPA file, create a new JS bundle, compile it to bytecode using Hermes and copy it back in the original location.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;17b2be4759634f0eef7b56bca514e383&quot; data-gist-line=&quot;9-38&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next, we sign the IPA using a &lt;code&gt;signing_identity&lt;/code&gt; and &lt;code&gt;provisioning_profile(s)&lt;/code&gt; defined by Fastlane in some ENV variables. You can replace &lt;code&gt;com.bundle.identifier&lt;/code&gt; with your own identifier. This fastlane action has a new parameter, &lt;code&gt;match_type&lt;/code&gt;, it can have the following values: &lt;code&gt;adhoc&lt;/code&gt;, &lt;code&gt;appstore&lt;/code&gt;, &lt;code&gt;development&lt;/code&gt; or &lt;code&gt;enterprise&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code data-gist-id=&quot;17b2be4759634f0eef7b56bca514e383&quot; data-gist-line=&quot;40-62&quot; data-gist-hide-footer=&quot;true&quot;&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Complete source for the &lt;code&gt;refresh_ipa_js_bundle.rb&lt;/code&gt; can be found &lt;a href=&quot;https://gist.github.com/cristiangu/17b2be4759634f0eef7b56bca514e383&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the iOS lane, this action can be used like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# [...]

latest_release = firebase_app_distribution_get_latest_release(app: firebase_app_id)
if ENV[&quot;NATIVE_IOS_BUILD_REQUIRED&quot;] == &quot;true&quot;
    update_project_settings(
        profile_type: &quot;AdHoc&quot;,
        build_number: (latest_release[:buildVersion].to_i + 1).to_s
    )
    # Do your regular fastlane steps
    # [...]
else
    UI.message(&quot;Skipping native iOS build&quot;)
    refresh_ipa_js_bundle(
        match_type: &quot;adhoc&quot;,
        build_number: (latest_release[:buildVersion].to_i + 1).to_s
    )
    # Distribute the new build, the path is &quot;./mobile_app.ipa&quot;
end

# [...]
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;good-to-know&quot;&gt;Good to know&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;On Android, this will not work for &lt;code&gt;.aab&lt;/code&gt; files, they are really different compared to an APK.&lt;/li&gt;
  &lt;li&gt;It would be nice to create a new env variable to store the artifact file name and use it inside the shell scripts in both fastlane actions, &lt;code&gt;sh(&quot;something #{ENV[&quot;PRODUCT_NAME&quot;]}.apk&quot;)&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;The &lt;code&gt;save_cache&lt;/code&gt; and &lt;code&gt;restore_cache&lt;/code&gt; commands are saving every new build even if it’s a recycled one. Unfortunately, there is no way to delete the old cache or skip certain build steps in CircleCI. This cache &lt;a href=&quot;https://circleci.com/docs/caching/&quot;&gt;expires automatically after 15 days&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;The APK sign logic is duplicated on Android, if you change something inside &lt;code&gt;./android/app/build.gradle&lt;/code&gt; make sure to also update the &lt;code&gt;refresh_apk_js_bundle.rb&lt;/code&gt; file.&lt;/li&gt;
  &lt;li&gt;This article assumes that you use the default JS bundle file names, &lt;code&gt;index.android.bundle&lt;/code&gt; and &lt;code&gt;main.jsbundle&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;If your project is using &lt;code&gt;productFlavors&lt;/code&gt; &amp;amp; &lt;code&gt;flavorDimensions&lt;/code&gt; on Android and multiple &lt;code&gt;build schemes&lt;/code&gt; &amp;amp; &lt;code&gt;build configs&lt;/code&gt; on iOS, more customizations are needed to accommodate the things explained above.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;sources&quot;&gt;Sources&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/cristiangu/d8e24f88f580519238d681cb09def782&quot;&gt;config.yml&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/cristiangu/573fc71c79203cf027cef5ed42a5e11e&quot;&gt;install-tools-android.sh&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/cristiangu/287212f0e0abbb5cba479824bf4508ab&quot;&gt;refresh_apk_js_bundle.rb&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://gist.github.com/cristiangu/17b2be4759634f0eef7b56bca514e383&quot;&gt;refresh_ipa_js_bundle.rb&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;that-was-it&quot;&gt;That was it&lt;/h3&gt;

&lt;p&gt;Recycling native build artifacts can significantly reduce build times and improve the efficiency of your CI/CD pipeline, especially for React Native projects. By leveraging this, you can save valuable time.&lt;/p&gt;

&lt;p&gt;While the approach outlined in this article focuses on CircleCI and Fastlane, the scripts are platform agnostic or at least easily adjustable to other CI/CD tools and workflows.&lt;/p&gt;

</description>
        <pubDate>Sat, 29 Mar 2025 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/react-native-recycle-native-builds/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/react-native-recycle-native-builds/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>Forward third-party Push Notifications to React Native Firebase Messaging</title>
        <description>&lt;p&gt;Sometimes your React Native app has multiple sources for push notifications. In this article I will explain how to forward push notifications received on the native side from a third-party like Klaviyo to React Native Firebase Messaging library. This is really useful because you can re-use one set of callbacks on the JS side for multiple native “clients”, in this case Firebase Cloud Messaging and Klaviyo.&lt;/p&gt;

&lt;h3 id=&quot;ios&quot;&gt;iOS&lt;/h3&gt;

&lt;p&gt;Include these imports in your &lt;code&gt;*-Bridging-Header.h&lt;/code&gt; so we can use them in Swift. If you don’t have a bridging header in place, please follow this &lt;a href=&quot;https://developer.apple.com/documentation/swift/importing-objective-c-into-swift&quot; target=&quot;_blank&quot;&gt;article&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#import &amp;lt;RNFBApp/RNFBRCTEventEmitter.h&amp;gt;
#import &quot;RNFBMessagingSerializer.h&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now it’s time to implement &lt;code&gt;UNUserNotificationCenterDelegate&lt;/code&gt; in your &lt;code&gt;AppDelegate.swift&lt;/code&gt; file.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import RNFBMessaging
import KlaviyoSwift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
  var window: UIWindow?
  var bridge: RCTBridge!

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
    ) -&amp;gt; Bool {
    FirebaseApp.configure()
    UNUserNotificationCenter.current().delegate = self
    //[...]
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s implement some methods from that protocol. This one can be useful if you want to display push notifications while your app is in foreground.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;extension AppDelegate {
    func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    willPresent notification: UNNotification
    ) async -&amp;gt; UNNotificationPresentationOptions {
    if #available(iOS 14.0, *) {
      return [.banner]
    } else {
      return [.alert]
    }
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the next method, we will receive the notification object, then we will convert it to a dictionary using some functions from &lt;code&gt;RNFBMessaging&lt;/code&gt;. Once the dictionary data is ready we will use the &lt;code&gt;sendEvent()&lt;/code&gt; function and send it to the JS realm. This event will trigger the callback passed to &lt;code&gt;messaging().onNotificationOpenedApp(callback)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last part is also handling the case when the app is opened from scratch, and on the JS side &lt;code&gt;messaging().getInitialNotification()&lt;/code&gt; is expected to return the push notification.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;func userNotificationCenter(
    _ center: UNUserNotificationCenter,
    didReceive response: UNNotificationResponse
) async {
    // This will check if the notification is from Klaviyo
    let handled = KlaviyoSDK().handle(notificationResponse: response) { }
    if(!handled) {
        return
    }
    // https://github.com/invertase/react-native-firebase/blob/9b5c405b2933c84daad561117a3eebacc65cbb7e/packages/messaging/ios/RNFBMessaging/RNFBMessaging%2BUNUserNotificationCenter.m#L151
    let userInfo = response.notification.request.content.userInfo
    let dict = RNFBMessagingSerializer.notification(toDict: response.notification)
    RNFBRCTEventEmitter.shared().sendEvent(withName: &quot;messaging_notification_opened&quot;, body: dict)

    // Making sure the getInitialNotification() func will return something on app cold start.
    // https://github.com/invertase/react-native-firebase/blob/9b5c405b2933c84daad561117a3eebacc65cbb7e/packages/messaging/lib/modular/index.d.ts#L104
    RNFBMessagingUNUserNotificationCenter.sharedInstance().initialNotification = dict
}

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

&lt;h3 id=&quot;android&quot;&gt;Android&lt;/h3&gt;

&lt;p&gt;On Android we need to patch the library in order to expose a private field. Here is a &lt;code&gt;@react-native-firebase+messaging+20.4.0.patch&lt;/code&gt; file that is only adding the &lt;code&gt;public&lt;/code&gt; keyword for &lt;code&gt;ReadableMap initialNotification&lt;/code&gt; from &lt;code&gt;ReactNativeFirebaseMessagingModule.java&lt;/code&gt;. More details on how to patch a library can be found &lt;a href=&quot;https://github.com/ds300/patch-package&quot; target=&quot;_blank&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;diff --git a/node_modules/@react-native-firebase/messaging/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingModule.java b/node_modules/@react-native-firebase/messaging/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingModule.java
index 3b89817..e5d4c64 100644
--- a/node_modules/@react-native-firebase/messaging/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingModule.java
+++ b/node_modules/@react-native-firebase/messaging/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingModule.java
@@ -40,7 +40,7 @@ import java.util.Map;
 public class ReactNativeFirebaseMessagingModule extends ReactNativeFirebaseModule
     implements ActivityEventListener {
   private static final String TAG = &quot;Messaging&quot;;
-  ReadableMap initialNotification = null;
+  public ReadableMap initialNotification = null;
   private HashMap&amp;lt;String, Boolean&amp;gt; initialNotificationMap = new HashMap&amp;lt;&amp;gt;();
 
   ReactNativeFirebaseMessagingModule(ReactApplicationContext reactContext) {

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

&lt;p&gt;In this case, Klaviyo already has a service to create and display the push notification on Android, if your push provider doesn’t offer this, feel free to check out their &lt;a href=&quot;https://github.com/klaviyo/klaviyo-android-sdk/blob/master/sdk/push-fcm/src/main/java/com/klaviyo/pushFcm/KlaviyoPushService.kt&quot; target=&quot;_blank&quot;&gt;implementation&lt;/a&gt;. Don’t forget to also register that service in your &lt;code&gt;AndroidManifest.xml&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The following must be added inside &lt;code&gt;&amp;lt;application&amp;gt; [...] &amp;lt;/application&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;service android:name=&quot;com.klaviyo.pushFcm.KlaviyoPushService&quot; android:exported=&quot;false&quot;&amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name=&quot;com.google.firebase.MESSAGING_EVENT&quot; /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
&amp;lt;/service&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To make use of that patch, when the app is started, in &lt;code&gt;MainActivity.kt&lt;/code&gt; we check for a notification bundle in the intent. If we find something, we are sending the bundle to a &lt;a href=&quot;https://gist.github.com/cristiangu/2c77d185de680f4e499b39288921637b&quot; target=&quot;_blank&quot;&gt;helper function&lt;/a&gt; to convert it to a &lt;code&gt;WritableMap&lt;/code&gt;. This dictionary is set to &lt;code&gt;initialNotification&lt;/code&gt;, this field is part of the already running instance of a native module called &lt;code&gt;ReactNativeFirebaseMessagingModule&lt;/code&gt;. On the JS side &lt;code&gt;messaging().getInitialNotification()&lt;/code&gt; will return this push notification.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import com.facebook.react.bridge.WritableNativeMap
import com.klaviyo.analytics.Klaviyo
import com.klaviyo.analytics.Klaviyo.isKlaviyoIntent
import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter
import io.invertase.firebase.messaging.ReactNativeFirebaseMessagingModule

// [...]

override fun onCreate(savedInstanceState: Bundle?) {
    // https://github.com/software-mansion/react-native-screens/issues/17#issuecomment-424704067
    super.onCreate(null)

    if(intent.isKlaviyoIntent) {
        // Only for Analytics
        Klaviyo.handlePush(intent)
        // Cold app start after tapping on a push notification from Klaviyo
        val remoteMessageMap =
            ReactNativeFirebaseMessagingSerializer.klaviyoExtrasToWritableMap(intent.extras)
        val newInitialNotification = WritableNativeMap()
        newInitialNotification.merge(remoteMessageMap!!)

        val modules = this.reactInstanceManager.currentReactContext?.nativeModules
        val messagingModule = modules?.first { it.name == &quot;RNFBMessagingModule&quot; } as ReactNativeFirebaseMessagingModule
        messagingModule.initialNotification = newInitialNotification
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the app is already running in background or in foreground, the &lt;code&gt;onNewIntent()&lt;/code&gt; method will be called on notification tap. Here we will convert again the bundle extras to a dictionary and send it as an event. On the JS side, this event will trigger the callback passed inside &lt;code&gt;messaging().onNotificationOpenedApp(callback)&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;override fun onNewIntent(intent: Intent?) {
    super.onNewIntent(intent)
    if (intent?.isKlaviyoIntent != true) {
        return
    }
    // Only for Analytics
    Klaviyo.handlePush(intent)
    val remoteMessageMap =
        ReactNativeFirebaseMessagingSerializer.klaviyoExtrasToWritableMap(intent.extras)
    val emitter = ReactNativeFirebaseEventEmitter.getSharedInstance()
    emitter.sendEvent(
        io.invertase.firebase.messaging.ReactNativeFirebaseMessagingSerializer.remoteMessageMapToEvent(
            remoteMessageMap, true
        )
    )
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;that-was-it&quot;&gt;That was it&lt;/h3&gt;

&lt;p&gt;Now your push notifications from third-party providers will show up on the JS side when using &lt;code&gt;@react-native-firebase/messaging&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;import messaging from &apos;@react-native-firebase/messaging&apos;;

const unsubscribe = messaging().onNotificationOpenedApp(callback);
const notification = await messaging().getInitialNotification();
&lt;/code&gt;&lt;/pre&gt;

</description>
        <pubDate>Fri, 10 Jan 2025 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/react-native-forward-third-party-push-notifications-to-firebase/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/react-native-forward-third-party-push-notifications-to-firebase/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>Using Swift in Fabric components and Turbo Modules</title>
        <description>&lt;p&gt;React Native’s new architecture is here, a few more releases, and it will be enabled by default for new library projects.&lt;/p&gt;

&lt;p&gt;A lot of &lt;a href=&quot;https://github.com/reactwg/react-native-new-architecture/discussions/6&quot; target=&quot;_blank&quot;&gt;important libraries&lt;/a&gt; have already started to migrate or completed the migration to this new architecture.&lt;/p&gt;

&lt;p&gt;Scroll to the end and clone the example project where Swift is being used in Fabric components and Turbo Modules, or stay with us and learn how to do this step-by-step.&lt;/p&gt;

&lt;p&gt;While Turbo Modules fully support Swift, the &lt;code&gt;create-react-native-library&lt;/code&gt; doesn’t offer a template for this. Here’s how you can use it:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Make sure to add &lt;code&gt;@objc public&lt;/code&gt; to classes and methods you want to expose in Objective-C/C++.&lt;/li&gt;
  &lt;li&gt;Import the Swift headers: &lt;code&gt;#import (your podspec name)-Swift.h&lt;/code&gt;, in your Objective-C++ file (.mm).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When trying to build a Fabric component in Swift I saw this &lt;a href=&quot;https://github.com/reactwg/react-native-new-architecture/discussions/143&quot; target=&quot;_blank&quot;&gt;discussion&lt;/a&gt; where I saw that Swift is not supported yet.&lt;/p&gt;

&lt;p&gt;At first, I was surprised by this, then I quickly realised that although Objective-C is easily interoperable with Swift, in this new architecture there is a layer that is completely OS-agnostic and written in C++. That layer is called Fabric, basically the RN team created a fully cross-platform implementation for the &lt;a href=&quot;https://reactnative.dev/architecture/glossary#react-shadow-tree-and-react-shadow-node&quot; target=&quot;_blank&quot;&gt;React Shadow Tree&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/fabric-explanatory-graphic.png&amp;amp;w=1440&quot; alt=&quot;assets/images/fabric-explanatory-graphic.png&quot; width=&quot;1992&quot; height=&quot;1192&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/fabric-explanatory-graphic.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/fabric-explanatory-graphic.png&amp;amp;w=960 960w, /.netlify/images?url=/assets/images/fabric-explanatory-graphic.png&amp;amp;w=1440 1440w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;p&gt;This wasn’t enough for me, so I started digging more. I was thinking that perhaps there are some C++ parts that might not be compatible with Swift because C++ interoperability is &lt;a href=&quot;https://www.swift.org/documentation/cxx-interop/status/#:~:text=C%2B%2B%20interoperability%20is%20supported%20in,wants%20to%20use%20Swift%20APIs.&quot; target=&quot;_blank&quot;&gt;supported only in Swift 5.9 and above&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;there-is-a-way&quot;&gt;There is a way&lt;/h3&gt;

&lt;p&gt;To be able to call Swift code, you need to have a thin Objective-C layer. Let’s create a new RN library and show you step-by-step.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cristiangutu@ % npx create-react-native-library@latest new-lib      
✔ What is the name of the npm package? … react-native-new-lib
[...]
✔ What type of library do you want to develop? › Turbo module with backward compat
✔ Which languages do you want to use? › Kotlin &amp;amp; Objective-C
✔ Project created successfully at new-lib!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Make sure you select &lt;code&gt;Turbo module with backward compat&lt;/code&gt;, we will start with a simple Turbo module for now.&lt;/p&gt;

&lt;p&gt;Install node_modules, the iOS Pod dependencies and start the Metro server.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cd new-lib
yarn
cd example/ios/
bundle install
RCT_NEW_ARCH_ENABLED=1 pod install
cd ..
yarn start
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Open Xcode, &lt;code&gt;NewLibExample.xcworkspace&lt;/code&gt;, and try to run the example project. It’s important to have a fully working iOS project in this state.&lt;/p&gt;

&lt;h3 id=&quot;swift-turbo-modules&quot;&gt;Swift Turbo Modules&lt;/h3&gt;

&lt;p&gt;To support Swift in a Turbo Module, we need to tell CocoaPods to pick up the &lt;code&gt;.swift&lt;/code&gt; extension. Open the &lt;code&gt;react-native-new-lib.podspec&lt;/code&gt; and include &lt;code&gt;swift&lt;/code&gt; in &lt;code&gt;source_files&lt;/code&gt; list.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[...]
    s.platforms    = { :ios =&amp;gt; min_ios_version_supported }
    s.source       = { :git =&amp;gt; &quot;https://github.com/cristiangu/react-native-new-lib.git&quot;, :tag =&amp;gt; &quot;#{s.version}&quot; }

    s.source_files = &quot;ios/**/*.{h,m,mm,swift}&quot; 👈

    # Use install_modules_dependencies helper to install the dependencies if React Native version &amp;gt;=0.71.0.
    # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
    if respond_to?(:install_modules_dependencies, true)
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now let’s have a simple Swift class. Inside &lt;code&gt;new-lib/ios&lt;/code&gt;, create a new file with the following implementation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// Calculator.swift

@objc public class Calculator: NSObject {
    @objc public static func multiply(a: Double, b: Double) -&amp;gt; Double {
        return a * b
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Go to &lt;code&gt;new-lib/example/ios&lt;/code&gt; and run &lt;code&gt;RCT_NEW_ARCH_ENABLED=1 pod install&lt;/code&gt;, you should see the Pod being installed again.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[...]
[Codegen] Found rncore
Downloading dependencies
Installing react-native-new-lib 0.1.0 👈
Generating Pods project
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s use it, we need to import a special header. This .h file behaves like an umbrella header for your Swift code. To learn more about this, &lt;a href=&quot;https://developer.apple.com/documentation/swift/importing-swift-into-objective-c&quot; target=&quot;_blank&quot;&gt;check out these docs.&lt;/a&gt; Open &lt;code&gt;new-lib/ios/NewLib.mm&lt;/code&gt; and make the following changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#import &quot;NewLib.h&quot;
#import &quot;react_native_new_lib-Swift.h&quot; // 👈 Yes, Xcode will not allow `-` characters, only for the last part.

@implementation NewLib
RCT_EXPORT_MODULE()

// Example method
// See // https://reactnative.dev/docs/native-modules-ios
RCT_EXPORT_METHOD(multiply:(double)a
                  b:(double)b
                  resolve:(RCTPromiseResolveBlock)resolve
                  reject:(RCTPromiseRejectBlock)reject)
{
    double result =  [Calculator multiplyWithA:a b:b]; // 👈
    resolve([NSNumber numberWithDouble:result]); // 👈
}
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Add a breakpoint in Xcode, run again the Example project and you will see the Swift code being executed. 🎉&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/turbo-module-swift-breakpoint.png&amp;amp;w=960&quot; alt=&quot;assets/images/turbo-module-swift-breakpoint.png&quot; width=&quot;1000&quot; height=&quot;360&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/turbo-module-swift-breakpoint.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/turbo-module-swift-breakpoint.png&amp;amp;w=960 960w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;supporting-both-fabric-components-and-turbo-modules&quot;&gt;Supporting both Fabric components and Turbo modules&lt;/h3&gt;

&lt;p&gt;All the templates offered by the &lt;code&gt;create-react-native-library&lt;/code&gt; don’t include a template to have Fabric components and Turbo modules in the same library.&lt;/p&gt;

&lt;p&gt;To achieve this, open &lt;code&gt;new-lib/package.json&lt;/code&gt; and scroll to the bottom and do the following change:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[...]
 &quot;codegenConfig&quot;: {
    &quot;name&quot;: &quot;RNNewLibSpec&quot;,
    &quot;type&quot;: &quot;all&quot;, 👈
    &quot;jsSrcsDir&quot;: &quot;src&quot;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;using-swift-in-fabric-components&quot;&gt;Using Swift in Fabric components&lt;/h3&gt;

&lt;p&gt;In our current project we will start to create some files for our new &lt;code&gt;MyComponentView&lt;/code&gt; Fabric component. Basically I will re-use most of the files that are generated when you create a new library, make sure you choose the &lt;code&gt;Fabric view with backward compat&lt;/code&gt; template.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;cristiangutu@ % npx create-react-native-library@latest my-component
✔ What is the name of the npm package? … react-native-my-component
[...]
✔ What type of library do you want to develop? › Fabric view with backward compat
✔ Which languages do you want to use? › Kotlin &amp;amp; Objective-C
✔ Project created successfully at my-component!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Copy the following files from &lt;code&gt;my-component/ios&lt;/code&gt; into &lt;code&gt;new-lib/ios&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;MyComponentView.h&lt;/li&gt;
  &lt;li&gt;MyComponentView.mm&lt;/li&gt;
  &lt;li&gt;MyComponentViewManager.mm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open the &lt;code&gt;MyComponentView.mm&lt;/code&gt; file and replace all the &lt;code&gt;RNMyComponentViewSpec&lt;/code&gt; strings with &lt;code&gt;RNNewLibSpec&lt;/code&gt;. This value is generated from &lt;code&gt;new-lib/package.json&lt;/code&gt;, &lt;code&gt;codeGenConfig&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;Replace the &lt;code&gt;#import &quot;Utils.h&quot;&lt;/code&gt; lines from &lt;code&gt;MyComponentView.mm&lt;/code&gt; and &lt;code&gt;MyComponentViewManager.mm&lt;/code&gt; with:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#import &quot;react_native_new_lib-Swift.h&quot;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now let’s create something that can be used in our Fabric component, let’s have the usual Hex to UIColor converter. Inside &lt;code&gt;new-lib/ios&lt;/code&gt; create this new file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// UIColor+Hex.swift

extension UIColor {
    @objc public convenience init(hex: String, alpha: CGFloat = 1.0) {
        var hexValue = hex.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased()
        
        if hexValue.hasPrefix(&quot;#&quot;) {
            hexValue.remove(at: hexValue.startIndex)
        }
        
        var rgbValue: UInt64 = 0
        Scanner(string: hexValue).scanHexInt64(&amp;amp;rgbValue)
        
        let red = CGFloat((rgbValue &amp;amp; 0xFF0000) &amp;gt;&amp;gt; 16) / 255.0
        let green = CGFloat((rgbValue &amp;amp; 0x00FF00) &amp;gt;&amp;gt; 8) / 255.0
        let blue = CGFloat(rgbValue &amp;amp; 0x0000FF) / 255.0
        
        self.init(red: red, green: green, blue: blue, alpha: alpha)
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Both &lt;code&gt;MyComponentView.mm&lt;/code&gt; and &lt;code&gt;MyComponentViewManager.mm&lt;/code&gt; are setting a background color using the value sent in the &lt;code&gt;color&lt;/code&gt; prop on the JS side. We need to update those implementations to use our new Swift implementation.&lt;/p&gt;

&lt;p&gt;Find and replace all the &lt;code&gt;[_view setBackgroundColor:&lt;/code&gt; occurrences with:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;[_view setBackgroundColor: [[UIColor alloc] initWithHex:colorToConvert alpha:1.0]];&lt;/code&gt; in MyComponentView.mm&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;[view setBackgroundColor: [[UIColor alloc] initWithHex:json alpha:1.0]];&lt;/code&gt; in MyComponentViewManager.mm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The iOS native implementation is complete now, let’s go back to JS realm 🌈 and link them together. Inside &lt;code&gt;new-lib/src&lt;/code&gt; create a new file, and add the following implementation:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// MyComponentViewNativeComponent.ts

import codegenNativeComponent from &apos;react-native/Libraries/Utilities/codegenNativeComponent&apos;;
import type { ViewProps } from &apos;react-native&apos;;

interface NativeProps extends ViewProps {
  color?: string;
}

export default codegenNativeComponent&amp;lt;NativeProps&amp;gt;(&apos;MyComponentView&apos;);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the &lt;code&gt;new-lib/src/index.tsx&lt;/code&gt; file, add the following exports:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[...]
export { default as MyComponentView } from &apos;./MyComponentViewNativeComponent&apos;;
export * from &apos;./MyComponentViewNativeComponent&apos;;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit the &lt;code&gt;new-lib/example/src/App.tsx&lt;/code&gt; to use your new Fabric component:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[...]
return (
    &amp;lt;View style={styles.container}&amp;gt;
      &amp;lt;Text&amp;gt;Result: {result}&amp;lt;/Text&amp;gt;
      &amp;lt;MyComponentView style={styles.box} color=&quot;#64C17F&quot; /&amp;gt; 👈
    &amp;lt;/View&amp;gt;
  );
[...]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Refresh everything by running &lt;code&gt;RCT_NEW_ARCH_ENABLED=1 pod install&lt;/code&gt; inside &lt;code&gt;new-lib/example/ios&lt;/code&gt; and run again the Example app.&lt;/p&gt;

&lt;p&gt;You should see our new Fabric component in the wild! 🎉&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/fabric-view-running-on-simulator.png&amp;amp;w=480&quot; alt=&quot;assets/images/fabric-view-running-on-simulator.png&quot; width=&quot;800&quot; height=&quot;1070&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/fabric-view-running-on-simulator.png&amp;amp;w=480 480w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;This is a very simple example of using Swift inside Turbo modules and Fabric components, but I will stop here because this article is already too long.&lt;/p&gt;

&lt;p&gt;Having this in place enables you to start using fully-fledged UIViews defined in Swift; in the &lt;code&gt;- (instancetype)initWithFrame:(CGRect)frame&lt;/code&gt; method from &lt;code&gt;MyComponentView.mm&lt;/code&gt; you are free to instantiate any UIView defined in Swift.&lt;/p&gt;

&lt;p&gt;It’s time to use the best of both worlds, React Native’s New Architecture and Swift on iOS!&lt;/p&gt;

&lt;p&gt;Check out this &lt;a href=&quot;https://github.com/cristiangu/fabric-component-swift&quot; target=&quot;_blank&quot;&gt;example project&lt;/a&gt; with everything that we did today.&lt;/p&gt;

</description>
        <pubDate>Mon, 25 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/using-swift-in-fabric-components-and-turbo-modules/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/using-swift-in-fabric-components-and-turbo-modules/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>Adding a Forked Pod as a Dependency in a Podspec on iOS</title>
        <description>&lt;p&gt;You’re developing a new CocoaPods library. You found a bug in one of your library dependencies, so you decide to fork that pod dependency and fix it.&lt;/p&gt;

&lt;p&gt;After pushing the fix to the forked repository, you want to update your &lt;code&gt;s.dependency&lt;/code&gt; with the new version of your forked pod dependency.&lt;/p&gt;

&lt;p&gt;Here, you get an error while running &lt;code&gt;pod install&lt;/code&gt; and you learn that CocoaPods doesn’t support &lt;code&gt;:git =&amp;gt; [...]&lt;/code&gt; in a &lt;code&gt;.podspec&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[!] Invalid &apos;my-new-lib.podspec&apos; file: [!] Podspecs cannot specify the source of dependencies. The &apos;:git&apos; option is not supported. &apos;:git&apos; can be used in the Podfile instead to override global dependencies.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Basically, you cannot declare this in a &lt;code&gt;.podspec&lt;/code&gt; file, you can have it only in a Podfile:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;s.dependency &apos;ForkedPodName&apos;, :git =&amp;gt; &apos;https://github.com/cristiangu/myforkedlib.git&apos;&lt;/code&gt;&lt;/p&gt;

&lt;h3 id=&quot;what-do-you-do&quot;&gt;What do you do?&lt;/h3&gt;

&lt;p&gt;Add the forked lib repo as a Git Submodule in your current repo:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;cd &amp;lt;my-new-lib-podspec-root-dir&amp;gt;&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;git submodule add git@github.com:cristiangu/myforkedlib.git&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In your &lt;code&gt;.podspec&lt;/code&gt; file add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Pod::Spec.new do |s|
    [...]
    s.dependency &quot;ForkedPodName&quot;
  
    s.subspec &apos;ForkedPodName&apos; do |ss|
        ss.source_files = &apos;ForkedPodName/**/*.{swift}&apos;
    end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Refresh everything with: &lt;code&gt;pod install&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now your forked library (the git submodule) will be used as &lt;code&gt;source_files&lt;/code&gt; for your &lt;code&gt;ForkedPodName&lt;/code&gt; dependency.&lt;/p&gt;

&lt;p&gt;Learn more about:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Submodules&quot; target=&quot;_blank&quot;&gt;Git Submodules&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://guides.cocoapods.org/syntax/podspec.html&quot; target=&quot;_blank&quot;&gt;Podspec File&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Sun, 24 Mar 2024 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/adding-a-forked-pod-as-a-dependency-in-a-podspec-file-on-ios/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/adding-a-forked-pod-as-a-dependency-in-a-podspec-file-on-ios/</guid>
        
        
        <category>iOS</category>
        
      </item>
    
      <item>
        <title>How to add DKIM and DMARC records to your email</title>
        <description>&lt;p&gt;DKIM and DMARC records are now required by Google and Yahoo if you want to bulk send emails but they are also useful for your private custom domain email because without them your emails can get blocked by various firewalls.&lt;/p&gt;

&lt;h3 id=&quot;add-a-dkim-record&quot;&gt;Add a DKIM record&lt;/h3&gt;

&lt;p&gt;1 - If you’re using Namecheap’s email solution (Private Email), go to email settings and look for the &lt;strong&gt;Show DKIM&lt;/strong&gt; button.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/dkim-1.png&amp;amp;w=1440&quot; alt=&quot;assets/images/dkim-1.png&quot; width=&quot;1500&quot; height=&quot;1000&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/dkim-1.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/dkim-1.png&amp;amp;w=960 960w, /.netlify/images?url=/assets/images/dkim-1.png&amp;amp;w=1440 1440w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;p&gt;2 - Click on it and copy only the value between the quotes.
&lt;br /&gt;
&lt;code&gt;default._domainkey IN TXT (&quot;&lt;/code&gt; THIS VALUE &lt;code&gt;&quot;);&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/dkim-2.png&amp;amp;w=1440&quot; alt=&quot;assets/images/dkim-2.png&quot; width=&quot;1500&quot; height=&quot;1046&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/dkim-2.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/dkim-2.png&amp;amp;w=960 960w, /.netlify/images?url=/assets/images/dkim-2.png&amp;amp;w=1440 1440w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;p&gt;3 - Go to your favorite DNS manager and add a new DNS record with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Record Type: TXT
Name: default_.domainkey
Value: THE VALUE BETWEEN QUOTES
TTL: use the default or leave it empty
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/dkim-3.png&amp;amp;w=960&quot; alt=&quot;assets/images/dkim-3.png&quot; width=&quot;1190&quot; height=&quot;1082&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/dkim-3.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/dkim-3.png&amp;amp;w=960 960w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;check-if-the-dkim-record-is-doing-the-job&quot;&gt;Check if the DKIM record is doing the job&lt;/h3&gt;

&lt;p&gt;Try to send an email to you using your custom domain email address, once you got it &lt;a href=&quot;https://it.umn.edu/services-technologies/how-tos/gmail-view-email-headers&quot;&gt;check the headers&lt;/a&gt; of that email, for example on Gmail you should see &lt;strong&gt;PASS&lt;/strong&gt; for the DKIM field.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/dkim-4.png&amp;amp;w=960&quot; alt=&quot;assets/images/dkim-4.png&quot; width=&quot;1300&quot; height=&quot;587&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/dkim-4.png&amp;amp;w=480 480w, /.netlify/images?url=/assets/images/dkim-4.png&amp;amp;w=960 960w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;p&gt;If you don’t see this, wait 24 hours for those DNS records to be up-to-date.&lt;/p&gt;

&lt;h3 id=&quot;add-a-dmarc-record&quot;&gt;Add a DMARC record&lt;/h3&gt;

&lt;p&gt;DMARC also helps authenticate email messages. It tells email servers what to do after checking a domain’s SPF and DKIM records, which are other ways to verify emails. You can read more about this &lt;a href=&quot;https://www.cloudflare.com/en-gb/learning/dns/dns-records/dns-dmarc-record/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;1 - There are many ways to configure this, you can use this &lt;a href=&quot;https://dmarcian.com/dmarc-record-wizard/&quot;&gt;guided generator&lt;/a&gt; to generate a value for this record.&lt;/p&gt;

&lt;p&gt;2 - Go to your favorite DNS manager and add a new DNS record with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Record Type: TXT
Name: _dmarc
Value: YOUR VALUE
TTL: use the default or leave it empty
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&quot;check-if-the-dmarc-record-is-doing-the-job&quot;&gt;Check if the DMARC record is doing the job&lt;/h3&gt;

&lt;p&gt;Try to send an email to you using your custom domain email address, once you got it &lt;a href=&quot;https://it.umn.edu/services-technologies/how-tos/gmail-view-email-headers&quot;&gt;check the headers&lt;/a&gt; for that email. Look for &lt;code&gt;dmarc=pass&lt;/code&gt; if you find this, everything should be ok.&lt;/p&gt;

&lt;p&gt;If you don’t see this, wait 24 hours for those DNS records to be up-to-date.&lt;/p&gt;

&lt;p&gt;If you encounter any other issues, feel free to leave a comment and I will get back to you!&lt;/p&gt;
</description>
        <pubDate>Fri, 02 Feb 2024 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/how-to-add-dkim-and-dmarc-records-to-your-email/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/how-to-add-dkim-and-dmarc-records-to-your-email/</guid>
        
        <category>Web</category>
        
        
        <category>Software</category>
        
      </item>
    
      <item>
        <title>Optimising React Native&apos;s View component render speed</title>
        <description>&lt;p&gt;We all know that you can achieve a significant performance boost if you’re rendering fewer views. The &lt;code&gt;&amp;lt;View/&amp;gt;&lt;/code&gt; component is one of the most used components in any React Native project.&lt;/p&gt;

&lt;p&gt;It seems that by directly using the &lt;code&gt;RCTView&lt;/code&gt; without its corresponding JS node, we can achieve this performance boost.&lt;/p&gt;

&lt;h3 id=&quot;before&quot;&gt;Before&lt;/h3&gt;

&lt;p&gt;Let’s try rendering a &lt;code&gt;&amp;lt;View/&amp;gt;&lt;/code&gt; multiple times. If we check Flipper, this will output a render time of 592.8ms&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/c5e0567e9f4734519c6249bce3112670.js?file=before.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;In Flipper, if we switch to the Components tab, we can see our &lt;code&gt;&amp;lt;View/&amp;gt;&lt;/code&gt; nodes.
&lt;img src=&quot;/.netlify/images?url=/assets/images/react-native-optimise-view-before-nodes.jpg&amp;amp;w=446&quot; alt=&quot;assets/images/react-native-optimise-view-before-nodes.jpg&quot; width=&quot;446&quot; height=&quot;625&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/react-native-optimise-view-before-nodes.jpg&amp;amp;w=446 446w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;h3 id=&quot;after&quot;&gt;After&lt;/h3&gt;

&lt;p&gt;Now let’s create a new file and export a &lt;code&gt;View&lt;/code&gt; const, but point it to &lt;code&gt;ViewNativeComponent&lt;/code&gt;.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/c5e0567e9f4734519c6249bce3112670.js?file=view.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;Try running your test again using this new View component like this:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/c5e0567e9f4734519c6249bce3112670.js?file=after.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;In my case, the render time significantly decreased to 280.1ms. Now, if you look in the Components tab in Flipper, you will not see those View nodes. Here, I’m assuming this import is causing RN to render directly into the native layer.&lt;/p&gt;

&lt;p&gt;That was it! This post was inspired by &lt;a href=&quot;https://twitter.com/natebirdman/status/1695511232298783079&quot; target=&quot;_blank&quot;&gt;Nate’s tweet&lt;/a&gt;, if you want to learn more about this, go check it out!&lt;/p&gt;

</description>
        <pubDate>Thu, 28 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/optimising-react-native-view-render-speed/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/optimising-react-native-view-render-speed/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>react-native-fast-image - No flickering when changing the image source</title>
        <description>&lt;h3 id=&quot;what-is-react-native-fast-image&quot;&gt;What is react-native-fast-image?&lt;/h3&gt;

&lt;p&gt;Before diving into the details of the patch, let’s briefly review what react-native-fast-image is and why it’s widely used.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;react-native-fast-image&lt;/code&gt; is a library that enhances image loading and rendering in React Native applications. It leverages the powerful &lt;a href=&quot;https://github.com/bumptech/glide&quot;&gt;Glide&lt;/a&gt; library for Android and &lt;a href=&quot;https://github.com/SDWebImage/SDWebImage&quot;&gt;SDWebImage&lt;/a&gt; for iOS to provide a highly optimized image loading experience. This means faster image loading, better caching, and smoother transitions when displaying images in your app.&lt;/p&gt;

&lt;h3 id=&quot;introducing-a-new-prop&quot;&gt;Introducing a new prop&lt;/h3&gt;

&lt;p&gt;The patch in question is adding a new prop, &lt;code&gt;useLastImageAsDefaultSource&lt;/code&gt;, by making changes to both the Android and iOS implementations of &lt;code&gt;react-native-fast-image&lt;/code&gt;. Let’s break down the changes step by step.&lt;/p&gt;

&lt;h3 id=&quot;android-changes&quot;&gt;Android Changes&lt;/h3&gt;

&lt;p&gt;In the Android part of the patch, we see a new method added to the &lt;code&gt;FastImageViewManager&lt;/code&gt; class:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=FastImageViewManager.java&quot;&gt; &lt;/script&gt;

&lt;p&gt;This method is used to set a property called &lt;code&gt;useLastImageAsDefaultSource&lt;/code&gt; on an instance of &lt;code&gt;FastImageViewWithUrl&lt;/code&gt;, which is the Android equivalent of the &lt;code&gt;react-native-fast-image component&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is how the new property is being used in &lt;code&gt;FastImageViewWithUrl&lt;/code&gt;, line 23 is the most important one:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=FastImageViewWithUrl.java&quot;&gt; &lt;/script&gt;

&lt;h3 id=&quot;ios-changes&quot;&gt;iOS Changes&lt;/h3&gt;

&lt;p&gt;In the iOS part of the patch, we see a similar addition in the &lt;code&gt;FFFastImageView.h&lt;/code&gt;:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=FFFastImageView.h&quot;&gt; &lt;/script&gt;

&lt;p&gt;Then this property is being used in &lt;code&gt;FFFastImageView.m&lt;/code&gt;, check out line 15:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=FFFastImageView.m&quot;&gt; &lt;/script&gt;

&lt;h3 id=&quot;what-does-it-do&quot;&gt;What Does It Do&lt;/h3&gt;

&lt;p&gt;The purpose of this patch is to give you more control over the default image source displayed while an image is loading. When &lt;code&gt;useLastImageAsDefaultSource&lt;/code&gt; is set, the component will use the last loaded image as the placeholder while the new image is being fetched. When set to false (or not set at all), the &lt;code&gt;defaultSource&lt;/code&gt; prop will be used as the placeholder. By doing this you can avoid the flicker that is occurring during the image change.&lt;/p&gt;

&lt;h3 id=&quot;how-to-use-it&quot;&gt;How to Use It&lt;/h3&gt;

&lt;p&gt;To take advantage of this patch, you need to set the &lt;code&gt;useLastImageAsDefaultSource&lt;/code&gt; prop on your &lt;code&gt;FastImage&lt;/code&gt; component to a truthy value.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=Example.tsx&quot;&gt; &lt;/script&gt;

&lt;h3 id=&quot;the-patch-diff&quot;&gt;The Patch Diff&lt;/h3&gt;

&lt;p&gt;If you’re already using &lt;a href=&quot;https://github.com/ds300/patch-package&quot;&gt;patch-package&lt;/a&gt; you can create a new file (&lt;code&gt;react-native-fast-image+8.6.3.patch&lt;/code&gt;) in your &lt;code&gt;patches&lt;/code&gt; directory and add this diff:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/3b5b016b06b43a401ee0b015a4101ae4.js?file=patch.diff&quot;&gt; &lt;/script&gt;

&lt;h3 id=&quot;demo&quot;&gt;Demo&lt;/h3&gt;

&lt;video width=&quot;100%&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left: auto; margin-right:auto; margin-bottom: 20px; margin-top: 40px;&quot;&gt;
  &lt;source src=&quot;../assets/videos/flickering-demo-video-1080p.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;h3 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;The introduction of the &lt;code&gt;useLastImageAsDefaultSource&lt;/code&gt; is a subtle enhancement that can significantly elevate the user experience within image-rich applications.&lt;/p&gt;
</description>
        <pubDate>Sat, 02 Sep 2023 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/react-native-fast-image-patch-to-fix-the-image-change-flickering/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/react-native-fast-image-patch-to-fix-the-image-change-flickering/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>React Native animated bottom modal in a Native Stack Navigator</title>
        <description>&lt;p&gt;If you’re using the React Navigation library and you want to show a bottom modal you cannot use the &lt;code&gt;useCardAnimation()&lt;/code&gt; hook to know the state of the transition, this hook is not available in native navigators.&lt;/p&gt;

&lt;p&gt;You can implement a gesture-aware bottom modal with a transparent background using the bare minimum:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;RN Animated API&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;yarn add react-native-gesture-handler&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Declare the &lt;code&gt;GModal&lt;/code&gt; in your Native Stack navigator. If you plan to have multiple modals feel free to include all of them in &lt;code&gt;&amp;lt;RootStack.Group&amp;gt;&lt;/code&gt;. All the &lt;code&gt;screenOptions&lt;/code&gt; values will automatically be passed down to all of the children.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-1.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;Create a new &lt;code&gt;GModal.tsx&lt;/code&gt; file and let’s start with some imports.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-2.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;Add a root view.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-3.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;Add a &lt;code&gt;&amp;lt;PanGestureHandler&amp;gt;&lt;/code&gt; with an animated content view, this &lt;code&gt;&amp;lt;Animated.View&amp;gt;&lt;/code&gt; will be translated on Y axis using the gesture data provided by the PanGestureHandler.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-4.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;&lt;img src=&quot;/.netlify/images?url=/assets/images/g-modal-2.png&amp;amp;w=480&quot; alt=&quot;assets/images/g-modal-2.png&quot; width=&quot;250&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; srcset=&quot;/.netlify/images?url=/assets/images/g-modal-2.png&amp;amp;w=480 480w&quot; sizes=&quot;(max-width: 767px) 100vw, 720px&quot;&gt;&lt;/p&gt;

&lt;p&gt;Declare a variable to hold the current Y value and some functions that will be called by the PanGestureHandler.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-5.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;Take a look and play a bit with this.&lt;/p&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-3.webm&quot; type=&quot;video/webm&quot; /&gt;
  &lt;source src=&quot;../assets/videos/g-modal-3.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Let’s change the blue background, in the root view replace the &lt;code&gt;blue&lt;/code&gt; value with &lt;code&gt;transparent&lt;/code&gt; and you will see the content beneath.&lt;/p&gt;

&lt;p&gt;If you open the modal and drag it up as much as you can, at the bottom of the modal, because it’s transparent you can see the parent’s page content.&lt;/p&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-3.5.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Let’s create a new component to fix this.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-6.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;This component will be placed as the last child in the root view:&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-7.tsx&quot;&gt; &lt;/script&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-4.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Add a drop shadow for our content view so we can see the edges more clearly.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-8.tsx&quot;&gt; &lt;/script&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-5.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;It’s cool to swipe it down to close it but we also want the modal to be dismissed if we click on the transparent background. Add a &lt;code&gt;&amp;lt;Pressable&amp;gt;&lt;/code&gt; to intercept some click events and link it to the already defined &lt;code&gt;closeModal()&lt;/code&gt; function.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-9.tsx&quot;&gt; &lt;/script&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-6.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;One problem here. If you click on the red view, the &lt;code&gt;onPress&lt;/code&gt; will be called and the modal will be closed, if you don’t want this, make sure to add another &lt;code&gt;&amp;lt;Pressable&amp;gt;&lt;/code&gt; over &lt;code&gt;&amp;lt;PanGestureHandler&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;noscript&gt;&lt;pre&gt;404: Not Found&lt;/pre&gt;&lt;/noscript&gt;
&lt;script src=&quot;https://gist.github.com/74ba83cd4ea243cda92f5b84a6a2c889.js?file=Step-10.tsx&quot;&gt; &lt;/script&gt;

&lt;p&gt;You’re pretty much done! 
Watch this short demo with a polished Logout Modal on Android.&lt;/p&gt;

&lt;video height=&quot;800&quot; autoplay=&quot;&quot; muted=&quot;&quot; controls=&quot;&quot; style=&quot;display:block; margin-left:auto; margin-right:auto&quot;&gt;
  &lt;source src=&quot;../assets/videos/g-modal-7.mp4&quot; type=&quot;video/mp4&quot; /&gt;
&lt;/video&gt;

&lt;p&gt;Check out the full &lt;a href=&quot;https://gist.github.com/cristiangu/74ba83cd4ea243cda92f5b84a6a2c889#file-step-11-tsx&quot; target=&quot;_blank&quot;&gt;implementation here.&lt;/a&gt;&lt;/p&gt;

</description>
        <pubDate>Sat, 05 Aug 2023 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/react-native-animated-bottom-modal-in-a-native-stack-navigator/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/react-native-animated-bottom-modal-in-a-native-stack-navigator/</guid>
        
        
        <category>React Native</category>
        
      </item>
    
      <item>
        <title>Top quality sources to find free and paid landing page templates in 2023</title>
        <description>&lt;p&gt;A few weeks ago I started to build a landing page for my company, &lt;a href=&quot;https://www.guulabs.com/&quot; target=&quot;_blank&quot;&gt;GUU Labs&lt;/a&gt;, and I realized how hard it is to find some good starting points.&lt;/p&gt;

&lt;p&gt;Here is a list with the best ones that I’ve found, written in various frameworks, take a look and find what suits you best:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://astro.build/themes&quot; target=&quot;_blank&quot;&gt;Astro.js&lt;/a&gt;, if you’re planning to use it, they have this list with a lot of free and paid templates.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.wickedtemplates.com/&quot; target=&quot;_blank&quot;&gt;Wicked Templates&lt;/a&gt; is offering some really good paid starters built in HTML 5 &amp;amp; Tailwind.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://cruip.com/&quot; target=&quot;_blank&quot;&gt;Cruip&lt;/a&gt; is by far one of the best paid options that you have out there, the templates look good and can be downloaded in React.js, Next.js, Vue.js or Laravel. Besides this, you also get Figma or Sketch designs, making it very easy to edit your assets.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://onepagelove.com/templates/landing-page-templates&quot; target=&quot;_blank&quot;&gt;One Page Love&lt;/a&gt; has this very long list with a ton of templates written in various frameworks and it also includes some for Framer or Webflow.&lt;/li&gt;
  &lt;li&gt;If coding is not your expertise &lt;a href=&quot;https://webflow.com/templates&quot; target=&quot;_blank&quot;&gt;Webflow&lt;/a&gt; has some crazy good templates and if you want something simpler &lt;a href=&quot;https://www.framer.com/templates/&quot; target=&quot;_blank&quot;&gt;Framer&lt;/a&gt; is your buddy.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.builtatlightspeed.com/&quot; target=&quot;_blank&quot;&gt;Built At Light Speed&lt;/a&gt; is a really big aggregator where you can find a lot of stuff.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nextjstemplates.com/templates&quot; target=&quot;_blank&quot;&gt;Next.js Templates&lt;/a&gt; offer some good free starter templates for Next.js.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.tailwindawesome.com/&quot; target=&quot;_blank&quot;&gt;Tailwind Awesome&lt;/a&gt; will be a nice place for all the Tailwind fans out there.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.comingsoonkit.com/&quot; target=&quot;_blank&quot;&gt;Coming Soon Kit&lt;/a&gt; offers an interesting package with 45+ one page templates available in Tailwind &amp;amp; Figma or in Webflow &amp;amp; Figma.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ui.shadcn.com/&quot; target=&quot;_blank&quot;&gt;shadcn/ui&lt;/a&gt; is a really good components library to help build that landing page almost from scratch.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.radix-ui.com/&quot; target=&quot;_blank&quot;&gt;Radix UI&lt;/a&gt; was the inspiration for shadcn/ui, check it out!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://mui.com/store/&quot; target=&quot;_blank&quot;&gt;MUI&lt;/a&gt; has some really good templates built with MUI in React.js and Next.js, these are more focused for a dashboard type of project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;May this help you do your best work!&lt;/p&gt;

</description>
        <pubDate>Thu, 06 Jul 2023 00:00:00 +0000</pubDate>
        <link>https://www.cristiangutu.pro/top-quality-sources-to-find-landing-page-templates/</link>
        <guid isPermaLink="true">https://www.cristiangutu.pro/top-quality-sources-to-find-landing-page-templates/</guid>
        
        <category>Templates</category>
        
        <category>Landing Page</category>
        
        
        <category>Software</category>
        
      </item>
    
  </channel>
</rss>
